mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Merge branch 'release/os/4.12' into merge-release/os/4.11-release/os/4.12-2024-11-27-467
This commit is contained in:
commit
61aa4de348
3958
.ci/api-current.txt
3958
.ci/api-current.txt
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
|||||||
FROM azul/zulu-openjdk:11.0.14
|
|
||||||
RUN apt-get update && apt-get install -y curl apt-transport-https \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
gnupg2 \
|
|
||||||
software-properties-common \
|
|
||||||
wget
|
|
||||||
ARG USER="stresstester"
|
|
||||||
RUN useradd -m ${USER}
|
|
@ -1,213 +0,0 @@
|
|||||||
#!groovy
|
|
||||||
/**
|
|
||||||
* Jenkins pipeline to build Corda OS release with JDK11
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kill already started job.
|
|
||||||
* Assume new commit takes precendence and results from previous
|
|
||||||
* unfinished builds are not required.
|
|
||||||
* This feature doesn't play well with disableConcurrentBuilds() option
|
|
||||||
*/
|
|
||||||
@Library('corda-shared-build-pipeline-steps')
|
|
||||||
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|
||||||
|
|
||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sense environment
|
|
||||||
*/
|
|
||||||
boolean isReleaseTag = (env.TAG_NAME =~ /^release.*JDK11$/)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common Gradle arguments for all Gradle executions
|
|
||||||
*/
|
|
||||||
String COMMON_GRADLE_PARAMS = [
|
|
||||||
'--no-daemon',
|
|
||||||
'--stacktrace',
|
|
||||||
'--info',
|
|
||||||
'-Pcompilation.warningsAsErrors=false',
|
|
||||||
'-Ptests.failFast=true',
|
|
||||||
].join(' ')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of subfolders to run tests previously on Another Agent and Same Agent
|
|
||||||
*/
|
|
||||||
String sameAgentFolder = 'sameAgent'
|
|
||||||
String anotherAgentFolder = 'anotherAgent'
|
|
||||||
|
|
||||||
pipeline {
|
|
||||||
agent {
|
|
||||||
dockerfile {
|
|
||||||
label 'standard'
|
|
||||||
additionalBuildArgs '--build-arg USER="${USER}"' // DON'T change quotation - USER variable is substituted by SHELL!!!!
|
|
||||||
filename "${sameAgentFolder}/.ci/dev/compatibility/DockerfileJDK11"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List options in alphabetical order
|
|
||||||
*/
|
|
||||||
options {
|
|
||||||
buildDiscarder(logRotator(daysToKeepStr: '14', artifactDaysToKeepStr: '14'))
|
|
||||||
checkoutToSubdirectory "${sameAgentFolder}"
|
|
||||||
parallelsAlwaysFailFast()
|
|
||||||
timeout(time: 6, unit: 'HOURS')
|
|
||||||
timestamps()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List environment variables in alphabetical order
|
|
||||||
*/
|
|
||||||
environment {
|
|
||||||
ARTIFACTORY_BUILD_NAME = "Corda :: Publish :: Publish JDK 11 Release to Artifactory :: ${env.BRANCH_NAME}"
|
|
||||||
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
|
||||||
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
|
||||||
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Compile') {
|
|
||||||
steps {
|
|
||||||
dir(sameAgentFolder) {
|
|
||||||
authenticateGradleWrapper()
|
|
||||||
sh script: [
|
|
||||||
'./gradlew',
|
|
||||||
COMMON_GRADLE_PARAMS,
|
|
||||||
'clean',
|
|
||||||
'jar'
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Copy') {
|
|
||||||
steps {
|
|
||||||
sh "rm -rf ${anotherAgentFolder} && mkdir -p ${anotherAgentFolder} && cd ${sameAgentFolder} && cp -aR . ../${anotherAgentFolder}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('All Tests') {
|
|
||||||
parallel {
|
|
||||||
stage('Another agent') {
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
dir(anotherAgentFolder) {
|
|
||||||
archiveArtifacts artifacts: '**/*.log', fingerprint: false
|
|
||||||
junit testResults: '**/build/test-results/**/*.xml', keepLongStdio: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Unit Test') {
|
|
||||||
steps {
|
|
||||||
dir(anotherAgentFolder) {
|
|
||||||
sh script: [
|
|
||||||
'./gradlew',
|
|
||||||
COMMON_GRADLE_PARAMS,
|
|
||||||
'test'
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Smoke Test') {
|
|
||||||
steps {
|
|
||||||
dir(anotherAgentFolder) {
|
|
||||||
sh script: [
|
|
||||||
'./gradlew',
|
|
||||||
COMMON_GRADLE_PARAMS,
|
|
||||||
'smokeTest'
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Slow Integration Test') {
|
|
||||||
steps {
|
|
||||||
dir(anotherAgentFolder) {
|
|
||||||
sh script: [
|
|
||||||
'./gradlew',
|
|
||||||
COMMON_GRADLE_PARAMS,
|
|
||||||
'slowIntegrationTest'
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Same agent') {
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
dir(sameAgentFolder) {
|
|
||||||
archiveArtifacts artifacts: '**/*.log', fingerprint: false
|
|
||||||
junit testResults: '**/build/test-results/**/*.xml', keepLongStdio: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Integration Test') {
|
|
||||||
steps {
|
|
||||||
dir(sameAgentFolder) {
|
|
||||||
sh script: [
|
|
||||||
'./gradlew',
|
|
||||||
COMMON_GRADLE_PARAMS,
|
|
||||||
'integrationTest'
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Deploy Node') {
|
|
||||||
steps {
|
|
||||||
dir(sameAgentFolder) {
|
|
||||||
sh script: [
|
|
||||||
'./gradlew',
|
|
||||||
COMMON_GRADLE_PARAMS,
|
|
||||||
'deployNode'
|
|
||||||
].join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Publish to Artifactory') {
|
|
||||||
when {
|
|
||||||
expression { isReleaseTag }
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
dir(sameAgentFolder) {
|
|
||||||
rtServer(
|
|
||||||
id: 'R3-Artifactory',
|
|
||||||
url: 'https://software.r3.com/artifactory',
|
|
||||||
credentialsId: 'artifactory-credentials'
|
|
||||||
)
|
|
||||||
rtGradleDeployer(
|
|
||||||
id: 'deployer',
|
|
||||||
serverId: 'R3-Artifactory',
|
|
||||||
repo: 'corda-releases'
|
|
||||||
)
|
|
||||||
rtGradleRun(
|
|
||||||
usesPlugin: true,
|
|
||||||
useWrapper: true,
|
|
||||||
switches: '-s --info',
|
|
||||||
tasks: 'artifactoryPublish',
|
|
||||||
deployerId: 'deployer',
|
|
||||||
buildName: env.ARTIFACTORY_BUILD_NAME
|
|
||||||
)
|
|
||||||
rtPublishBuildInfo(
|
|
||||||
serverId: 'R3-Artifactory',
|
|
||||||
buildName: env.ARTIFACTORY_BUILD_NAME
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
|
||||||
cleanup {
|
|
||||||
deleteDir() /* clean up our workspace */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
#!groovy
|
|
||||||
/**
|
|
||||||
* Jenkins pipeline to build Corda Opensource Pull Requests with JDK11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Library('corda-shared-build-pipeline-steps')
|
|
||||||
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|
||||||
|
|
||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
|
||||||
|
|
||||||
pipeline {
|
|
||||||
agent {
|
|
||||||
dockerfile {
|
|
||||||
label 'standard'
|
|
||||||
additionalBuildArgs '--build-arg USER="${USER}"' // DON'T change quotation - USER variable is substituted by SHELL!!!!
|
|
||||||
filename '.ci/dev/compatibility/DockerfileJDK11'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
options {
|
|
||||||
timestamps()
|
|
||||||
timeout(time: 3, unit: 'HOURS')
|
|
||||||
buildDiscarder(logRotator(daysToKeepStr: '14', artifactDaysToKeepStr: '14'))
|
|
||||||
}
|
|
||||||
|
|
||||||
environment {
|
|
||||||
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
|
||||||
BUILD_CACHE_CREDENTIALS = credentials('gradle-ent-cache-credentials')
|
|
||||||
BUILD_CACHE_PASSWORD = "${env.BUILD_CACHE_CREDENTIALS_PSW}"
|
|
||||||
BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}"
|
|
||||||
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
|
||||||
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
|
||||||
CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key')
|
|
||||||
CORDA_USE_CACHE = "corda-remotes"
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('JDK 11 Compile') {
|
|
||||||
steps {
|
|
||||||
authenticateGradleWrapper()
|
|
||||||
sh "./gradlew --no-daemon --parallel --build-cache -Pcompilation.allWarningsAsErrors=true -Ptests.failFast=false " +
|
|
||||||
"-Ptests.ignoreFailures=true clean compileAll --stacktrace"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Deploy nodes') {
|
|
||||||
steps {
|
|
||||||
sh "./gradlew --no-daemon --build-cache deployNodes"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
findBuildScans()
|
|
||||||
}
|
|
||||||
cleanup {
|
|
||||||
deleteDir() /* clean up our workspace */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
4
.ci/dev/forward-merge/Jenkinsfile
vendored
4
.ci/dev/forward-merge/Jenkinsfile
vendored
@ -13,13 +13,13 @@
|
|||||||
* the branch name of origin branch, it should match the current branch
|
* the branch name of origin branch, it should match the current branch
|
||||||
* and it acts as a fail-safe inside {@code forwardMerger} pipeline
|
* and it acts as a fail-safe inside {@code forwardMerger} pipeline
|
||||||
*/
|
*/
|
||||||
String originBranch = 'release/os/4.11'
|
String originBranch = 'release/os/4.12'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the branch name of target branch, it should be the branch with the next version
|
* the branch name of target branch, it should be the branch with the next version
|
||||||
* after the one in current branch.
|
* after the one in current branch.
|
||||||
*/
|
*/
|
||||||
String targetBranch = 'release/os/4.12'
|
String targetBranch = 'release/os/4.13'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward merge any changes between #originBranch and #targetBranch
|
* Forward merge any changes between #originBranch and #targetBranch
|
||||||
|
2
.ci/dev/nightly-regression/Jenkinsfile
vendored
2
.ci/dev/nightly-regression/Jenkinsfile
vendored
@ -45,6 +45,8 @@ pipeline {
|
|||||||
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
||||||
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
||||||
CORDA_USE_CACHE = "corda-remotes"
|
CORDA_USE_CACHE = "corda-remotes"
|
||||||
|
JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
|
JAVA_8_HOME = "/usr/lib/jvm/java-1.8.0-amazon-corretto"
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
|
36
.ci/dev/pr-code-checks/Jenkinsfile
vendored
36
.ci/dev/pr-code-checks/Jenkinsfile
vendored
@ -15,48 +15,32 @@ pipeline {
|
|||||||
* List environment variables in alphabetical order
|
* List environment variables in alphabetical order
|
||||||
*/
|
*/
|
||||||
environment {
|
environment {
|
||||||
|
SNYK_API_TOKEN = credentials('c4-os-snyk-api-token-secret')
|
||||||
|
C4_OS_SNYK_ORG_ID = credentials('c4-os-snyk-org-id')
|
||||||
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
||||||
BUILD_CACHE_CREDENTIALS = credentials('gradle-ent-cache-credentials')
|
|
||||||
BUILD_CACHE_PASSWORD = "${env.BUILD_CACHE_CREDENTIALS_PSW}"
|
|
||||||
BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}"
|
|
||||||
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
||||||
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
||||||
CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key')
|
|
||||||
CORDA_USE_CACHE = "corda-remotes"
|
CORDA_USE_CACHE = "corda-remotes"
|
||||||
C4_OS_SNYK_ORG_ID = credentials('c4-os-snyk-org-id')
|
JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
SNYK_API_TOKEN = credentials('c4-os-snyk-api-token-secret')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
stage('Detekt check') {
|
stage('Detekt check') {
|
||||||
steps {
|
steps {
|
||||||
authenticateGradleWrapper()
|
authenticateGradleWrapper()
|
||||||
sh "./gradlew --no-daemon --parallel --build-cache clean detekt"
|
sh "./gradlew --no-daemon clean detekt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Compilation warnings check') {
|
stage('Compilation warnings check') {
|
||||||
steps {
|
steps {
|
||||||
sh "./gradlew --no-daemon --parallel --build-cache -Pcompilation.warningsAsErrors=true compileAll"
|
sh "./gradlew --no-daemon -Pcompilation.warningsAsErrors=true compileAll"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Snyk Delta') {
|
stage('Snyk Delta') {
|
||||||
agent {
|
agent { label 'standard' }
|
||||||
docker {
|
|
||||||
image 'build-zulu-openjdk:8'
|
|
||||||
reuseNode true
|
|
||||||
registryUrl 'https://engineering-docker.software.r3.com/'
|
|
||||||
registryCredentialsId 'artifactory-credentials'
|
|
||||||
args '-v /tmp:/host_tmp'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
GRADLE_USER_HOME = "/host_tmp/gradle"
|
|
||||||
}
|
|
||||||
steps {
|
steps {
|
||||||
authenticateGradleWrapper()
|
|
||||||
sh 'mkdir -p ${GRADLE_USER_HOME}'
|
|
||||||
authenticateGradleWrapper()
|
authenticateGradleWrapper()
|
||||||
snykDeltaScan(env.SNYK_API_TOKEN, env.C4_OS_SNYK_ORG_ID)
|
snykDeltaScan(env.SNYK_API_TOKEN, env.C4_OS_SNYK_ORG_ID)
|
||||||
}
|
}
|
||||||
@ -64,21 +48,19 @@ pipeline {
|
|||||||
|
|
||||||
stage('No API change check') {
|
stage('No API change check') {
|
||||||
steps {
|
steps {
|
||||||
sh "./gradlew --no-daemon --parallel --build-cache generateApi"
|
sh "./gradlew --no-daemon generateApi"
|
||||||
sh ".ci/check-api-changes.sh"
|
sh ".ci/check-api-changes.sh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Deploy Nodes') {
|
stage('Deploy Nodes') {
|
||||||
steps {
|
steps {
|
||||||
sh "./gradlew --no-daemon --build-cache jar deployNodes"
|
sh "./gradlew --no-daemon jar deployNodes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post {
|
post {
|
||||||
always {
|
|
||||||
findBuildScans()
|
|
||||||
}
|
|
||||||
cleanup {
|
cleanup {
|
||||||
deleteDir() /* clean up our workspace */
|
deleteDir() /* clean up our workspace */
|
||||||
}
|
}
|
||||||
|
1
.ci/dev/publish-api-docs/Jenkinsfile
vendored
1
.ci/dev/publish-api-docs/Jenkinsfile
vendored
@ -27,6 +27,7 @@ pipeline {
|
|||||||
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
||||||
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
||||||
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
CORDA_ARTIFACTORY_PASSWORD = "${env.ARTIFACTORY_CREDENTIALS_PSW}"
|
||||||
|
JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
|
@ -39,6 +39,7 @@ pipeline {
|
|||||||
BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}"
|
BUILD_CACHE_USERNAME = "${env.BUILD_CACHE_CREDENTIALS_USR}"
|
||||||
USE_CACHE = 'corda-remotes'
|
USE_CACHE = 'corda-remotes'
|
||||||
DOCKER_URL = "https://index.docker.io/v1/"
|
DOCKER_URL = "https://index.docker.io/v1/"
|
||||||
|
JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
|
@ -24,6 +24,7 @@ pipeline {
|
|||||||
// in the name
|
// in the name
|
||||||
ARTIFACTORY_BUILD_NAME = "Corda / Publish / Publish Preview to Artifactory"
|
ARTIFACTORY_BUILD_NAME = "Corda / Publish / Publish Preview to Artifactory"
|
||||||
.replaceAll("/", " :: ")
|
.replaceAll("/", " :: ")
|
||||||
|
JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
|
4
.ci/dev/regression/Jenkinsfile
vendored
4
.ci/dev/regression/Jenkinsfile
vendored
@ -70,6 +70,8 @@ pipeline {
|
|||||||
SNYK_API_KEY = "c4-os-snyk" //Jenkins credential type: Snyk Api token
|
SNYK_API_KEY = "c4-os-snyk" //Jenkins credential type: Snyk Api token
|
||||||
SNYK_TOKEN = credentials('c4-os-snyk-api-token-secret') //Jenkins credential type: Secret text
|
SNYK_TOKEN = credentials('c4-os-snyk-api-token-secret') //Jenkins credential type: Secret text
|
||||||
C4_OS_SNYK_ORG_ID = credentials('corda4-os-snyk-org-id')
|
C4_OS_SNYK_ORG_ID = credentials('corda4-os-snyk-org-id')
|
||||||
|
JAVA_HOME = "/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
|
JAVA_8_HOME = "/usr/lib/jvm/java-1.8.0-amazon-corretto"
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
@ -327,7 +329,7 @@ pipeline {
|
|||||||
'./gradlew',
|
'./gradlew',
|
||||||
COMMON_GRADLE_PARAMS,
|
COMMON_GRADLE_PARAMS,
|
||||||
'docker:pushDockerImage',
|
'docker:pushDockerImage',
|
||||||
'-Pdocker.image.repository=corda/community',
|
'-Pdocker.image.repository=corda/open-source',
|
||||||
'--image OFFICIAL'
|
'--image OFFICIAL'
|
||||||
].join(' ')
|
].join(' ')
|
||||||
}
|
}
|
||||||
|
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
# PR Checklist:
|
# PR Checklist:
|
||||||
|
|
||||||
- [ ] Have you run the unit, integration and smoke tests as described [here](https://docs.r3.com/en/platform/corda/4.8/open-source/testing.html)?
|
- [ ] Have you run the unit, integration and smoke tests as described [here](https://docs.r3.com/testing.html)?
|
||||||
- [ ] If you added public APIs, did you write the JavaDocs/kdocs?
|
- [ ] If you added public APIs, did you write the JavaDocs/kdocs?
|
||||||
- [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially the [release notes](https://docs.corda.net/head/release-notes.html) (`https://docs.r3.com/en/platform/corda/4.8/open-source/release-notes.html`)?
|
- [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially the [release notes](https://docs.r3.com/release-notes.html) (`https://docs.r3.com/release-notes.html`)?
|
||||||
- [ ] If you are contributing for the first time, please read the [contributor agreement](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html#merging-the-changes-back-into-corda).
|
- [ ] If you are contributing for the first time, please read the [contributor agreement](https://docs.r3.com/contributing.html) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://docs.r3.com/contributing.html).
|
||||||
|
|
||||||
Thanks for your code, it's appreciated! :)
|
Thanks for your code, it's appreciated! :)
|
||||||
|
2
.github/workflows/check-pr-title.yml
vendored
2
.github/workflows/check-pr-title.yml
vendored
@ -9,6 +9,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: morrisoncole/pr-lint-action@v1.7.1
|
- uses: morrisoncole/pr-lint-action@v1.7.1
|
||||||
with:
|
with:
|
||||||
title-regex: '^((CORDA|AG|EG|ENT|INFRA|ES)-\d+)(.*)'
|
title-regex: '^((CORDA|AG|EG|ENT|INFRA|ES|DOC)-\d+)(.*)'
|
||||||
on-failed-regex-comment: "PR title failed to match regex -> `%regex%`"
|
on-failed-regex-comment: "PR title failed to match regex -> `%regex%`"
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Corda is an open-source project and contributions are welcome!
|
Corda is an open-source project and contributions are welcome!
|
||||||
|
|
||||||
To find out how to contribute, please see our [contributing docs](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html).
|
To find out how to contribute, please see our [contributing docs](https://docs.r3.com/contributing.html).
|
||||||
|
20
Jenkinsfile
vendored
20
Jenkinsfile
vendored
@ -53,6 +53,8 @@ pipeline {
|
|||||||
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
CORDA_ARTIFACTORY_USERNAME = "${env.ARTIFACTORY_CREDENTIALS_USR}"
|
||||||
CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key')
|
CORDA_GRADLE_SCAN_KEY = credentials('gradle-build-scans-key')
|
||||||
CORDA_USE_CACHE = "corda-remotes"
|
CORDA_USE_CACHE = "corda-remotes"
|
||||||
|
JAVA_HOME="/usr/lib/jvm/java-17-amazon-corretto"
|
||||||
|
JAVA_8_HOME = "/usr/lib/jvm/java-1.8.0-amazon-corretto"
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
@ -119,6 +121,24 @@ pipeline {
|
|||||||
].join(' ')
|
].join(' ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage('Smoke Test') {
|
||||||
|
steps {
|
||||||
|
sh script: [
|
||||||
|
'./gradlew',
|
||||||
|
COMMON_GRADLE_PARAMS,
|
||||||
|
'smokeTest'
|
||||||
|
].join(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Slow Integration Test') {
|
||||||
|
steps {
|
||||||
|
sh script: [
|
||||||
|
'./gradlew',
|
||||||
|
COMMON_GRADLE_PARAMS,
|
||||||
|
'slowIntegrationTest'
|
||||||
|
].join(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Same agent') {
|
stage('Same agent') {
|
||||||
|
19
README.md
19
README.md
@ -1,5 +1,5 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://www.corda.net/wp-content/themes/corda/assets/images/crda-logo-big.svg" alt="Corda" width="500">
|
<img src="https://corda.net/wp-content/uploads/2021/11/corda-logo.svg" alt="Corda" width="500">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a href="https://ci-master.corda.r3cev.com/viewType.html?buildTypeId=Corda_Build_ActiveReleaseBranches_BuildOsRelease45&tab=buildTypeStatusDiv&guest=1"><img src="https://ci.corda.r3cev.com/app/rest/builds/buildType:Corda_Build_ActiveReleaseBranches_BuildOsRelease45/statusIcon"/></a> [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
|
<a href="https://ci-master.corda.r3cev.com/viewType.html?buildTypeId=Corda_Build_ActiveReleaseBranches_BuildOsRelease45&tab=buildTypeStatusDiv&guest=1"><img src="https://ci.corda.r3cev.com/app/rest/builds/buildType:Corda_Build_ActiveReleaseBranches_BuildOsRelease45/statusIcon"/></a> [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
|
||||||
@ -25,27 +25,26 @@ However, like all things, Corda must evolve to serve the more stringent needs of
|
|||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
1. Read the [Getting Started](https://docs.corda.net/getting-set-up.html) documentation
|
1. Read the [Getting Started](https://docs.r3.com/getting-set-up.html) documentation
|
||||||
2. Run the [Example CorDapp](https://docs.corda.net/tutorial-cordapp.html)
|
2. Run the [Example CorDapp](https://docs.r3.com/tutorial-cordapp.html)
|
||||||
3. Read about Corda's [Key Concepts](https://docs.corda.net/key-concepts.html)
|
3. Read about Corda's [Key Concepts](https://docs.r3.com/key-concepts.html)
|
||||||
4. Follow the [Hello, World! tutorial](https://docs.corda.net/hello-world-introduction.html)
|
4. Follow the [Hello, World! tutorial](https://docs.r3.com/hello-world-introduction.html)
|
||||||
|
|
||||||
## Useful links
|
## Useful links
|
||||||
|
|
||||||
* [Project Website](https://corda.net)
|
* [Project Website](https://corda.net)
|
||||||
* [Mailing List](https://groups.io/g/corda-dev/)
|
* [Mailing List](https://groups.io/g/corda-dev/)
|
||||||
* [Documentation](https://docs.corda.net)
|
* [Documentation](https://docs.r3.com)
|
||||||
* [Stack Overflow Tag](https://stackoverflow.com/questions/tagged/corda)
|
* [Stack Overflow Tag](https://stackoverflow.com/questions/tagged/corda)
|
||||||
* [Slack Channel](https://slack.corda.net/)
|
* [Slack Channel](https://slack.corda.net/)
|
||||||
* [Twitter](https://twitter.com/Cordablockchain)
|
* [Twitter](https://twitter.com/inside_r3)
|
||||||
* [Meetups](https://www.meetup.com/pro/corda/)
|
* [Training Courses](https://r3certification.com/)
|
||||||
* [Training Courses](https://www.corda.net/corda-training/)
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Corda is an open-source project and contributions are welcome!
|
Corda is an open-source project and contributions are welcome!
|
||||||
|
|
||||||
To find out how to contribute, please see our [contributing docs](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html).
|
To find out how to contribute, please see our [contributing docs](https://docs.r3.com/contributing.html).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
338
build.gradle
338
build.gradle
@ -1,8 +1,11 @@
|
|||||||
import com.r3.testing.DistributeTestsBy
|
import com.r3.testing.DistributeTestsBy
|
||||||
import com.r3.testing.PodLogLevel
|
import com.r3.testing.PodLogLevel
|
||||||
|
import net.corda.plugins.apiscanner.GenerateApi
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
import static org.gradle.api.JavaVersion.VERSION_11
|
import static org.gradle.api.JavaVersion.VERSION_17
|
||||||
import static org.gradle.api.JavaVersion.VERSION_1_8
|
import static org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
|
||||||
|
import static org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
// For sharing constants between builds
|
// For sharing constants between builds
|
||||||
@ -15,26 +18,18 @@ buildscript {
|
|||||||
|
|
||||||
ext.corda_build_edition = System.getenv("CORDA_BUILD_EDITION")?.trim() ?: "Corda Open Source"
|
ext.corda_build_edition = System.getenv("CORDA_BUILD_EDITION")?.trim() ?: "Corda Open Source"
|
||||||
ext.corda_platform_version = constants.getProperty("platformVersion")
|
ext.corda_platform_version = constants.getProperty("platformVersion")
|
||||||
|
ext.corda_shell_version = constants.getProperty("cordaShellVersion")
|
||||||
ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
|
ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
|
||||||
|
|
||||||
// Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things.
|
// Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things.
|
||||||
//
|
//
|
||||||
// TODO: Sort this alphabetically.
|
// TODO: Sort this alphabetically.
|
||||||
ext.kotlin_version = constants.getProperty("kotlinVersion")
|
|
||||||
ext.warnings_as_errors = project.hasProperty("compilation.warningsAsErrors") ? project.property("compilation.warningsAsErrors").toBoolean() : false
|
ext.warnings_as_errors = project.hasProperty("compilation.warningsAsErrors") ? project.property("compilation.warningsAsErrors").toBoolean() : false
|
||||||
|
|
||||||
ext.quasar_group = 'co.paralleluniverse'
|
ext.quasar_group = 'co.paralleluniverse'
|
||||||
// Set version of Quasar according to version of Java used:
|
// Set version of Quasar according to version of Java used:
|
||||||
if (JavaVersion.current().isJava8()) {
|
|
||||||
ext.quasar_version = constants.getProperty("quasarVersion")
|
ext.quasar_version = constants.getProperty("quasarVersion")
|
||||||
ext.quasar_classifier = constants.getProperty("quasarClassifier")
|
ext.quasar_classifier = constants.getProperty("quasarClassifier")
|
||||||
ext.jdkClassifier = constants.getProperty("jdkClassifier")
|
|
||||||
} else {
|
|
||||||
ext.quasar_version = constants.getProperty("quasarVersion11")
|
|
||||||
ext.quasar_classifier = constants.getProperty("quasarClassifier11")
|
|
||||||
ext.jdkClassifier = constants.getProperty("jdkClassifier11")
|
|
||||||
}
|
|
||||||
ext.cordaScanApiClassifier = jdkClassifier
|
|
||||||
ext.quasar_exclusions = [
|
ext.quasar_exclusions = [
|
||||||
'co.paralleluniverse**',
|
'co.paralleluniverse**',
|
||||||
'groovy**',
|
'groovy**',
|
||||||
@ -49,7 +44,7 @@ buildscript {
|
|||||||
'org.junit**',
|
'org.junit**',
|
||||||
'org.slf4j**',
|
'org.slf4j**',
|
||||||
'worker.org.gradle.**',
|
'worker.org.gradle.**',
|
||||||
'com.nhaarman.mockito_kotlin**',
|
'org.mockito.kotlin**',
|
||||||
'org.assertj**',
|
'org.assertj**',
|
||||||
'org.hamcrest**',
|
'org.hamcrest**',
|
||||||
'org.mockito**',
|
'org.mockito**',
|
||||||
@ -95,7 +90,6 @@ buildscript {
|
|||||||
ext.h2_version = constants.getProperty("h2Version")
|
ext.h2_version = constants.getProperty("h2Version")
|
||||||
ext.rxjava_version = constants.getProperty("rxjavaVersion")
|
ext.rxjava_version = constants.getProperty("rxjavaVersion")
|
||||||
ext.dokka_version = constants.getProperty("dokkaVersion")
|
ext.dokka_version = constants.getProperty("dokkaVersion")
|
||||||
ext.eddsa_version = constants.getProperty("eddsaVersion")
|
|
||||||
ext.dependency_checker_version = constants.getProperty("dependencyCheckerVersion")
|
ext.dependency_checker_version = constants.getProperty("dependencyCheckerVersion")
|
||||||
ext.commons_collections_version = constants.getProperty("commonsCollectionsVersion")
|
ext.commons_collections_version = constants.getProperty("commonsCollectionsVersion")
|
||||||
ext.beanutils_version = constants.getProperty("beanutilsVersion")
|
ext.beanutils_version = constants.getProperty("beanutilsVersion")
|
||||||
@ -116,7 +110,6 @@ buildscript {
|
|||||||
ext.class_graph_version = constants.getProperty('classgraphVersion')
|
ext.class_graph_version = constants.getProperty('classgraphVersion')
|
||||||
ext.jcabi_manifests_version = constants.getProperty("jcabiManifestsVersion")
|
ext.jcabi_manifests_version = constants.getProperty("jcabiManifestsVersion")
|
||||||
ext.picocli_version = constants.getProperty("picocliVersion")
|
ext.picocli_version = constants.getProperty("picocliVersion")
|
||||||
ext.commons_lang_version = constants.getProperty("commonsLangVersion")
|
|
||||||
ext.commons_io_version = constants.getProperty("commonsIoVersion")
|
ext.commons_io_version = constants.getProperty("commonsIoVersion")
|
||||||
ext.controlsfx_version = constants.getProperty("controlsfxVersion")
|
ext.controlsfx_version = constants.getProperty("controlsfxVersion")
|
||||||
ext.detekt_version = constants.getProperty('detektVersion')
|
ext.detekt_version = constants.getProperty('detektVersion')
|
||||||
@ -124,20 +117,10 @@ buildscript {
|
|||||||
ext.commons_configuration2_version = constants.getProperty("commonsConfiguration2Version")
|
ext.commons_configuration2_version = constants.getProperty("commonsConfiguration2Version")
|
||||||
ext.commons_text_version = constants.getProperty("commonsTextVersion")
|
ext.commons_text_version = constants.getProperty("commonsTextVersion")
|
||||||
ext.snake_yaml_version = constants.getProperty("snakeYamlVersion")
|
ext.snake_yaml_version = constants.getProperty("snakeYamlVersion")
|
||||||
ext.javaassist_version = constants.getProperty("javaassistVersion")
|
|
||||||
|
|
||||||
if (JavaVersion.current().isJava8()) {
|
|
||||||
ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsJava8Version")
|
|
||||||
ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeJava8Version")
|
|
||||||
} else {
|
|
||||||
ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsVersion")
|
ext.fontawesomefx_commons_version = constants.getProperty("fontawesomefxCommonsVersion")
|
||||||
ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeVersion")
|
ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeVersion")
|
||||||
}
|
ext.javaassist_version = constants.getProperty("javaassistVersion")
|
||||||
|
|
||||||
// Update 121 is required for ObjectInputFilter.
|
|
||||||
// Updates [131, 161] also have zip compression bugs on MacOS (High Sierra).
|
|
||||||
// when the java version in NodeStartup.hasMinimumJavaVersion() changes, so must this check
|
|
||||||
ext.java8_minUpdateVersion = constants.getProperty('java8MinUpdateVersion')
|
|
||||||
ext.corda_revision = {
|
ext.corda_revision = {
|
||||||
try {
|
try {
|
||||||
"git rev-parse HEAD".execute().text.trim()
|
"git rev-parse HEAD".execute().text.trim()
|
||||||
@ -171,6 +154,7 @@ buildscript {
|
|||||||
content {
|
content {
|
||||||
includeGroupByRegex 'net\\.corda(\\..*)?'
|
includeGroupByRegex 'net\\.corda(\\..*)?'
|
||||||
includeGroupByRegex 'com\\.r3(\\..*)?'
|
includeGroupByRegex 'com\\.r3(\\..*)?'
|
||||||
|
includeGroup 'co.paralleluniverse'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
@ -180,7 +164,6 @@ buildscript {
|
|||||||
includeGroupByRegex 'com\\.r3(\\..*)?'
|
includeGroupByRegex 'com\\.r3(\\..*)?'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gradlePluginPortal()
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven {
|
maven {
|
||||||
url "${publicArtifactURL}/jcenter-backup"
|
url "${publicArtifactURL}/jcenter-backup"
|
||||||
@ -188,28 +171,21 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
|
|
||||||
classpath "net.corda.plugins:publish-utils:$gradle_plugins_version"
|
|
||||||
classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version"
|
classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version"
|
||||||
classpath "net.corda.plugins:cordformation:$gradle_plugins_version"
|
classpath "net.corda.plugins:cordformation:$gradle_plugins_version"
|
||||||
classpath "net.corda.plugins:cordapp:$gradle_plugins_version"
|
classpath "net.corda.plugins:cordapp:$gradle_plugins_version"
|
||||||
classpath "net.corda.plugins:api-scanner:$gradle_plugins_version"
|
classpath "net.corda.plugins:api-scanner:$gradle_plugins_version"
|
||||||
classpath "net.corda.plugins:jar-filter:$gradle_plugins_version"
|
classpath "net.corda.plugins:jar-filter:$gradle_plugins_version"
|
||||||
classpath "net.sf.proguard:proguard-gradle:$proguard_version"
|
classpath "com.guardsquare:proguard-gradle:$proguard_version"
|
||||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.15.0'
|
classpath 'com.github.ben-manes:gradle-versions-plugin:0.15.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
|
classpath "org.jetbrains.dokka:dokka-base:$dokka_version"
|
||||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${dokka_version}"
|
classpath "org.owasp:dependency-check-gradle:$dependency_checker_version"
|
||||||
classpath "net.i2p.crypto:eddsa:$eddsa_version" // Needed for ServiceIdentityGenerator in the build environment.
|
|
||||||
classpath "org.owasp:dependency-check-gradle:${dependency_checker_version}"
|
|
||||||
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:$artifactory_plugin_version"
|
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:$artifactory_plugin_version"
|
||||||
// Capsule gradle plugin forked and maintained locally to support Gradle 5.x
|
// Capsule gradle plugin forked and maintained locally to support Gradle 5.x
|
||||||
// See https://github.com/corda/gradle-capsule-plugin
|
// See https://github.com/corda/gradle-capsule-plugin
|
||||||
classpath "us.kirchmeier:gradle-capsule-plugin:1.0.4_r3"
|
classpath "us.kirchmeier:gradle-capsule-plugin:1.0.5_r3"
|
||||||
classpath group: "com.r3.testing", name: "gradle-distributed-testing-plugin", version: '1.3.0'
|
classpath group: "com.r3.testing", name: "gradle-distributed-testing-plugin", version: '1.3.0'
|
||||||
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8"
|
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8"
|
||||||
classpath "com.gradle:gradle-enterprise-gradle-plugin:$gradleEnterprisePlugin"
|
|
||||||
classpath "com.gradle:common-custom-user-data-gradle-plugin:$customUserDataGradlePlugin"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.classpath {
|
configurations.classpath {
|
||||||
@ -219,32 +195,18 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
// Add the shadow plugin to the plugins classpath for the entire project.
|
id 'org.jetbrains.kotlin.jvm' apply false
|
||||||
id 'com.github.johnrengelman.shadow' version '2.0.4' apply false
|
id 'org.jetbrains.kotlin.plugin.allopen' apply false
|
||||||
|
id 'org.jetbrains.kotlin.plugin.jpa' apply false
|
||||||
|
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
|
||||||
id "org.ajoberstar.grgit" version "4.0.0"
|
id "org.ajoberstar.grgit" version "4.0.0"
|
||||||
|
id 'corda.root-publish'
|
||||||
|
id "org.jetbrains.dokka" version "1.8.20"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'project-report'
|
apply plugin: 'project-report'
|
||||||
apply plugin: 'com.github.ben-manes.versions'
|
apply plugin: 'com.github.ben-manes.versions'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
|
||||||
apply plugin: 'com.r3.testing.distributed-testing'
|
apply plugin: 'com.r3.testing.distributed-testing'
|
||||||
apply plugin: "com.gradle.build-scan"
|
|
||||||
apply plugin: "com.gradle.common-custom-user-data-gradle-plugin"
|
|
||||||
|
|
||||||
buildScan {
|
|
||||||
server = gradleEnterpriseUrl
|
|
||||||
allowUntrustedServer = false
|
|
||||||
def apiKey = project.findProperty('CORDA_GRADLE_SCAN_KEY') ?: System.getenv('CORDA_GRADLE_SCAN_KEY')
|
|
||||||
if (apiKey?.trim()) {
|
|
||||||
publishAlways()
|
|
||||||
capture {
|
|
||||||
taskInputFiles = true
|
|
||||||
}
|
|
||||||
uploadInBackground = false
|
|
||||||
accessKey = apiKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the command line project option -PversionFromGit is added to the gradle invocation, we'll resolve
|
// If the command line project option -PversionFromGit is added to the gradle invocation, we'll resolve
|
||||||
// the latest git commit hash and timestamp and create a version postfix from that
|
// the latest git commit hash and timestamp and create a version postfix from that
|
||||||
@ -259,26 +221,17 @@ if (ext.versionSuffix != ""){
|
|||||||
ext.corda_release_version = "${ext.baseVersion}".toString()
|
ext.corda_release_version = "${ext.baseVersion}".toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need the following three lines even though they're inside an allprojects {} block below because otherwise
|
logger.lifecycle("JDK: {}", System.getProperty("java.home"))
|
||||||
// IntelliJ gets confused when importing the project and ends up erasing and recreating the .idea directory, along
|
|
||||||
// with the run configurations. It also doesn't realise that the project is a Java 8 project and misconfigures
|
|
||||||
// the resulting import. This fixes it.
|
|
||||||
apply plugin: 'java'
|
|
||||||
|
|
||||||
logger.lifecycle("Java version: {}", JavaVersion.current())
|
|
||||||
sourceCompatibility = VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.current().isJava8() ? VERSION_1_8 : VERSION_11
|
|
||||||
logger.lifecycle("Java source compatibility: {}", sourceCompatibility)
|
|
||||||
logger.lifecycle("Java target compatibility: {}", targetCompatibility)
|
|
||||||
logger.lifecycle("Quasar version: {}", quasar_version)
|
logger.lifecycle("Quasar version: {}", quasar_version)
|
||||||
logger.lifecycle("Quasar classifier: {}", quasar_classifier.toString())
|
logger.lifecycle("Quasar classifier: {}", quasar_classifier.toString())
|
||||||
logger.lifecycle("Building Corda version: {}", corda_release_version)
|
logger.lifecycle("Building Corda version: {}", corda_release_version)
|
||||||
|
logger.lifecycle("User home: {}", System.getProperty('user.home'))
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'kotlin-allopen'
|
||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
apply plugin: 'org.owasp.dependencycheck'
|
apply plugin: 'org.owasp.dependencycheck'
|
||||||
apply plugin: 'kotlin-allopen'
|
|
||||||
apply plugin: 'org.sonarqube'
|
apply plugin: 'org.sonarqube'
|
||||||
|
|
||||||
allOpen {
|
allOpen {
|
||||||
@ -289,19 +242,6 @@ allprojects {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we do this to allow for Gradle task caching.
|
|
||||||
// below block tells Gradle to ignore specifically the dymaically generated files in the manifest when checking if a file is up to date
|
|
||||||
// this has no impact on publishing or production of jar, This only reates to Grades mechamish for verifying the Cache key
|
|
||||||
normalization {
|
|
||||||
runtimeClasspath {
|
|
||||||
ignore("**/*.EC") //signing related
|
|
||||||
ignore("**/*.SF") //signing related
|
|
||||||
ignore("**/*.MF")
|
|
||||||
ignore("**/*.kotlin_module")
|
|
||||||
ignore("**/Cordapp-Dependencies")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyCheck {
|
dependencyCheck {
|
||||||
suppressionFile = '.ci/dependency-checker/suppressedLibraries.xml'
|
suppressionFile = '.ci/dependency-checker/suppressedLibraries.xml'
|
||||||
cveValidForHours = 1
|
cveValidForHours = 1
|
||||||
@ -316,12 +256,17 @@ allprojects {
|
|||||||
nugetconfEnabled = false
|
nugetconfEnabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceCompatibility = VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.current().isJava8() ? VERSION_1_8 : VERSION_11
|
sourceCompatibility = VERSION_17
|
||||||
|
targetCompatibility = VERSION_17
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
// JDK11 official support (https://github.com/jacoco/jacoco/releases/tag/v0.8.3)
|
toolVersion = "0.8.7"
|
||||||
toolVersion = "0.8.3"
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
@ -336,13 +281,13 @@ allprojects {
|
|||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
tasks.withType(KotlinCompile).configureEach {
|
||||||
kotlinOptions {
|
compilerOptions {
|
||||||
languageVersion = "1.2"
|
languageVersion = KOTLIN_1_9
|
||||||
apiVersion = "1.2"
|
apiVersion = KOTLIN_1_9
|
||||||
jvmTarget = VERSION_1_8
|
jvmTarget = JVM_17
|
||||||
javaParameters = true // Useful for reflection.
|
javaParameters = true // Useful for reflection.
|
||||||
freeCompilerArgs = ['-Xjvm-default=compatibility']
|
freeCompilerArgs = ['-Xjvm-default=all-compatibility']
|
||||||
allWarningsAsErrors = warnings_as_errors
|
allWarningsAsErrors = warnings_as_errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,13 +309,12 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
tasks.withType(Test).configureEach {
|
||||||
|
jvmArgs += project(":node:capsule").file("src/main/resources/node-jvm-args.txt").readLines()
|
||||||
|
jvmArgs += "--add-modules=jdk.incubator.foreign" // For the SharedMemoryIncremental
|
||||||
forkEvery = 20
|
forkEvery = 20
|
||||||
ignoreFailures = project.hasProperty('tests.ignoreFailures') ? project.property('tests.ignoreFailures').toBoolean() : false
|
ignoreFailures = project.hasProperty('tests.ignoreFailures') ? project.property('tests.ignoreFailures').toBoolean() : false
|
||||||
failFast = project.hasProperty('tests.failFast') ? project.property('tests.failFast').toBoolean() : false
|
failFast = project.hasProperty('tests.failFast') ? project.property('tests.failFast').toBoolean() : false
|
||||||
|
|
||||||
// Prevent the project from creating temporary files outside of the build directory.
|
|
||||||
systemProperty 'java.io.tmpdir', buildDir.absolutePath
|
|
||||||
|
|
||||||
maxHeapSize = "1g"
|
maxHeapSize = "1g"
|
||||||
|
|
||||||
if (project.path.startsWith(':experimental') && System.getProperty("experimental.test.enable") == null) {
|
if (project.path.startsWith(':experimental') && System.getProperty("experimental.test.enable") == null) {
|
||||||
@ -380,25 +324,18 @@ allprojects {
|
|||||||
// Required to use Gradle build cache (until Gradle 5.0 is released with default value of "append" set to false)
|
// Required to use Gradle build cache (until Gradle 5.0 is released with default value of "append" set to false)
|
||||||
// See https://github.com/gradle/gradle/issues/5269 and https://github.com/gradle/gradle/pull/6419
|
// See https://github.com/gradle/gradle/issues/5269 and https://github.com/gradle/gradle/pull/6419
|
||||||
extensions.configure(TypeOf.typeOf(JacocoTaskExtension)) { ex ->
|
extensions.configure(TypeOf.typeOf(JacocoTaskExtension)) { ex ->
|
||||||
ex.append = false
|
// ex.append = false
|
||||||
}
|
}
|
||||||
|
|
||||||
maxParallelForks = (System.env.CORDA_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_TESTING_FORKS".toInteger()
|
|
||||||
|
|
||||||
systemProperty 'java.security.egd', 'file:/dev/./urandom'
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
|
||||||
if (name.contains("integrationTest")) {
|
if (name.contains("integrationTest")) {
|
||||||
maxParallelForks = (System.env.CORDA_INT_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_INT_TESTING_FORKS".toInteger()
|
maxParallelForks = (System.env.CORDA_INT_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_INT_TESTING_FORKS".toInteger()
|
||||||
}
|
} else {
|
||||||
|
maxParallelForks = (System.env.CORDA_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_TESTING_FORKS".toInteger()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jdkClassifier) {
|
// Prevent the project from creating temporary files outside of the build directory.
|
||||||
jar {
|
systemProperty 'java.io.tmpdir', buildDir.absolutePath
|
||||||
// JDK11 built and published artifacts to include classifier
|
systemProperty 'java.security.egd', 'file:/dev/./urandom'
|
||||||
archiveClassifier = jdkClassifier
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'net.corda'
|
group 'net.corda'
|
||||||
@ -439,6 +376,16 @@ allprojects {
|
|||||||
includeGroup 'com.github.bft-smart'
|
includeGroup 'com.github.bft-smart'
|
||||||
includeGroup 'com.github.detro'
|
includeGroup 'com.github.detro'
|
||||||
}
|
}
|
||||||
|
metadataSources {
|
||||||
|
mavenPom()
|
||||||
|
artifact()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "${publicArtifactURL}/corda-dependencies-dev"
|
||||||
|
content {
|
||||||
|
includeGroup 'co.paralleluniverse'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
url "${publicArtifactURL}/corda-dev"
|
url "${publicArtifactURL}/corda-dev"
|
||||||
@ -468,12 +415,12 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
all {
|
configureEach {
|
||||||
resolutionStrategy {
|
resolutionStrategy {
|
||||||
|
if (pluginManager.hasPlugin("org.jetbrains.kotlin.jvm")) {
|
||||||
// Force dependencies to use the same version of Kotlin as Corda.
|
// Force dependencies to use the same version of Kotlin as Corda.
|
||||||
force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
|
||||||
force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
||||||
force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
|
}
|
||||||
|
|
||||||
// Force dependencies to use the same version of Guava as Corda.
|
// Force dependencies to use the same version of Guava as Corda.
|
||||||
force "com.google.guava:guava:$guava_version"
|
force "com.google.guava:guava:$guava_version"
|
||||||
@ -500,6 +447,9 @@ allprojects {
|
|||||||
if (details.requested.group == 'org.yaml' && details.requested.name == 'snakeyaml') {
|
if (details.requested.group == 'org.yaml' && details.requested.name == 'snakeyaml') {
|
||||||
details.useVersion snake_yaml_version
|
details.useVersion snake_yaml_version
|
||||||
}
|
}
|
||||||
|
if (details.requested.group == 'commons-io' && details.requested.name == "commons-io") {
|
||||||
|
details.useVersion commons_io_version
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencySubstitution {
|
dependencySubstitution {
|
||||||
@ -508,7 +458,7 @@ allprojects {
|
|||||||
substitute module('commons-logging:commons-logging') with module("org.slf4j:jcl-over-slf4j:$slf4j_version")
|
substitute module('commons-logging:commons-logging') with module("org.slf4j:jcl-over-slf4j:$slf4j_version")
|
||||||
|
|
||||||
// Remove any transitive dependency on Logback (e.g. Liquibase 3.6 introduces this dependency)
|
// Remove any transitive dependency on Logback (e.g. Liquibase 3.6 introduces this dependency)
|
||||||
substitute module('ch.qos.logback:logback-classic') with module("org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version")
|
substitute module('ch.qos.logback:logback-classic') with module("org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version")
|
||||||
|
|
||||||
// Netty-All is an uber-jar which contains every Netty module.
|
// Netty-All is an uber-jar which contains every Netty module.
|
||||||
// Exclude it to force us to use the individual Netty modules instead.
|
// Exclude it to force us to use the individual Netty modules instead.
|
||||||
@ -519,25 +469,30 @@ allprojects {
|
|||||||
|
|
||||||
// Effectively delete this unused and unwanted transitive dependency of Artemis.
|
// Effectively delete this unused and unwanted transitive dependency of Artemis.
|
||||||
substitute module('org.jgroups:jgroups') with module("org.apache.activemq:artemis-commons:$artemis_version")
|
substitute module('org.jgroups:jgroups') with module("org.apache.activemq:artemis-commons:$artemis_version")
|
||||||
|
|
||||||
|
// Force use of LTS version of BC everywhere
|
||||||
|
substitute module('org.bouncycastle:bcutil-jdk18on') with module("org.bouncycastle:bcutil-lts8on:$bouncycastle_version")
|
||||||
|
substitute module('org.bouncycastle:bcprov-jdk18on') with module("org.bouncycastle:bcprov-lts8on:$bouncycastle_version")
|
||||||
|
substitute module('org.bouncycastle:bcpkix-jdk18on') with module("org.bouncycastle:bcpkix-lts8on:$bouncycastle_version")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FORCE Gradle to use latest SNAPSHOT dependencies.
|
||||||
|
cacheChangingModulesFor 0, 'seconds'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pluginManager.hasPlugin("org.jetbrains.kotlin.jvm")) {
|
||||||
// Select all of the compileClasspath and runtimeClasspath etc configurations,
|
// Select all of the compileClasspath and runtimeClasspath etc configurations,
|
||||||
// but NOT the "classpath" configuration, as that is used by the Gradle plugins.
|
// but NOT the "classpath" configuration, as that is used by the Gradle plugins.
|
||||||
matching { it.name.endsWith("Classpath") }.configureEach { cfg ->
|
matching { it.name.endsWith("Classpath") }.configureEach { cfg ->
|
||||||
cfg.resolutionStrategy {
|
cfg.resolutionStrategy {
|
||||||
dependencySubstitution {
|
dependencySubstitution {
|
||||||
// Force dependencies to use the same version of Kotlin as Corda.
|
// Force dependencies to use the same version of Kotlin as Corda.
|
||||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib-jdk8') with module("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
|
|
||||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib-jdk7') with module("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version")
|
|
||||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib-common') with module("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version")
|
substitute module('org.jetbrains.kotlin:kotlin-stdlib-common') with module("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version")
|
||||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib') with module("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
|
substitute module('org.jetbrains.kotlin:kotlin-stdlib') with module("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
|
||||||
substitute module('org.jetbrains.kotlin:kotlin-reflect') with module("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
|
substitute module('org.jetbrains.kotlin:kotlin-reflect') with module("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// FORCE Gradle to use latest SNAPSHOT dependencies.
|
|
||||||
cacheChangingModulesFor 0, 'seconds'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,37 +509,29 @@ sonarqube {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we are running on a Java 8 JDK. The source/targetCompatibility values above aren't sufficient to
|
|
||||||
// guarantee this because those are properties checked by the Java plugin, but we're using Kotlin.
|
|
||||||
//
|
|
||||||
// We recommend a specific minor version (unfortunately, not checkable directly) because JavaFX adds APIs in
|
|
||||||
// minor releases, so we can't work with just any Java 8, it has to be a recent one.
|
|
||||||
if (!JavaVersion.current().java8Compatible)
|
|
||||||
throw new GradleException("Corda requires Java 8, please upgrade to at least 1.8.0_$java8_minUpdateVersion")
|
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
detekt
|
detekt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Required for building out the fat JAR.
|
// Required for building out the fat JAR.
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':node')
|
implementation project(':node')
|
||||||
compile "com.google.guava:guava:$guava_version"
|
implementation "com.google.guava:guava:$guava_version"
|
||||||
|
|
||||||
// Set to corda compile to ensure it exists now deploy nodes no longer relies on build
|
// Set to corda implementation to ensure it exists now deploy nodes no longer relies on build
|
||||||
compile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
implementation project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||||
compile project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
implementation project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
||||||
|
|
||||||
// For the buildCordappDependenciesJar task
|
// For the buildCordappDependenciesJar task
|
||||||
runtime project(':client:jfx')
|
runtimeOnly project(':client:jfx')
|
||||||
runtime project(':client:mock')
|
runtimeOnly project(':client:mock')
|
||||||
runtime project(':client:rpc')
|
runtimeOnly project(':client:rpc')
|
||||||
runtime project(':core')
|
runtimeOnly project(':core')
|
||||||
runtime project(':confidential-identities')
|
runtimeOnly project(':confidential-identities')
|
||||||
runtime project(':finance:workflows')
|
runtimeOnly project(':finance:workflows')
|
||||||
runtime project(':finance:contracts')
|
runtimeOnly project(':finance:contracts')
|
||||||
runtime project(':testing:testserver')
|
runtimeOnly project(':testing:testserver')
|
||||||
testCompile project(':test-utils')
|
testImplementation project(':test-utils')
|
||||||
detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.1'
|
detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,16 +540,16 @@ jar {
|
|||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) {
|
tasks.register('jacocoRootReport', JacocoReport) {
|
||||||
dependsOn = subprojects.test
|
dependsOn = subprojects.test
|
||||||
additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs)
|
// additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs)
|
||||||
sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs)
|
// sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs)
|
||||||
classDirectories = files(subprojects.sourceSets.main.output)
|
// classDirectories = files(subprojects.sourceSets.main.output)
|
||||||
executionData = files(subprojects.jacocoTestReport.executionData)
|
// executionData = files(subprojects.jacocoTestReport.executionData)
|
||||||
reports {
|
reports {
|
||||||
html.enabled = true
|
html.required = true
|
||||||
xml.enabled = true
|
xml.required = true
|
||||||
csv.enabled = false
|
csv.required = false
|
||||||
}
|
}
|
||||||
onlyIf = {
|
onlyIf = {
|
||||||
true
|
true
|
||||||
@ -622,13 +569,13 @@ tasks.register('detekt', JavaExec) {
|
|||||||
def plugins = detektPluginsJar.outputs.files.singleFile
|
def plugins = detektPluginsJar.outputs.files.singleFile
|
||||||
def params = ['-i', input, '-c', config, '-b', baseline, '--plugins', plugins]
|
def params = ['-i', input, '-c', config, '-b', baseline, '--plugins', plugins]
|
||||||
inputs.files(detektPluginsJar, config, baseline)
|
inputs.files(detektPluginsJar, config, baseline)
|
||||||
main = "io.gitlab.arturbosch.detekt.cli.Main"
|
mainClass = "io.gitlab.arturbosch.detekt.cli.Main"
|
||||||
classpath = configurations.detekt
|
classpath = configurations.detekt
|
||||||
args(params)
|
args(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('detektBaseline', JavaExec) {
|
tasks.register('detektBaseline', JavaExec) {
|
||||||
main = "io.gitlab.arturbosch.detekt.cli.Main"
|
mainClass = "io.gitlab.arturbosch.detekt.cli.Main"
|
||||||
classpath = configurations.detekt
|
classpath = configurations.detekt
|
||||||
def input = "$projectDir"
|
def input = "$projectDir"
|
||||||
def config = "$projectDir/detekt-config.yml, $projectDir/detekt-baseline-config.yml"
|
def config = "$projectDir/detekt-config.yml, $projectDir/detekt-baseline-config.yml"
|
||||||
@ -638,103 +585,28 @@ tasks.register('detektBaseline', JavaExec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
tasks.withType(Test).configureEach {
|
||||||
reports.html.destination = file("${reporting.baseDir}/${name}")
|
reports.html.outputLocation.set(file("${reporting.baseDir}/${name}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
task testReport(type: TestReport) {
|
tasks.register('testReport', TestReport) {
|
||||||
destinationDir = file("$buildDir/reports/allTests")
|
destinationDir = file("$buildDir/reports/allTests")
|
||||||
// Include the results from the `test` task in all subprojects
|
// Include the results from the `test` task in all subprojects
|
||||||
reportOn subprojects*.test
|
reportOn subprojects*.test
|
||||||
}
|
}
|
||||||
|
|
||||||
bintrayConfig {
|
|
||||||
user = System.getenv('CORDA_BINTRAY_USER')
|
|
||||||
key = System.getenv('CORDA_BINTRAY_KEY')
|
|
||||||
repo = 'corda'
|
|
||||||
org = 'r3'
|
|
||||||
licenses = ['Apache-2.0']
|
|
||||||
vcsUrl = 'https://github.com/corda/corda'
|
|
||||||
projectUrl = 'https://github.com/corda/corda'
|
|
||||||
gpgSign = true
|
|
||||||
gpgPassphrase = System.getenv('CORDA_BINTRAY_GPG_PASSPHRASE')
|
|
||||||
publications = [
|
|
||||||
'corda-opentelemetry',
|
|
||||||
'corda-opentelemetry-driver',
|
|
||||||
'corda-jfx',
|
|
||||||
'corda-mock',
|
|
||||||
'corda-rpc',
|
|
||||||
'corda-core',
|
|
||||||
'corda',
|
|
||||||
'corda-finance-workflows',
|
|
||||||
'corda-finance-contracts',
|
|
||||||
'corda-node',
|
|
||||||
'corda-node-api',
|
|
||||||
'corda-test-common',
|
|
||||||
'corda-core-test-utils',
|
|
||||||
'corda-test-utils',
|
|
||||||
'corda-test-db',
|
|
||||||
'corda-jackson',
|
|
||||||
'corda-testserver-impl',
|
|
||||||
'corda-testserver',
|
|
||||||
'corda-node-driver',
|
|
||||||
'corda-confidential-identities',
|
|
||||||
'corda-shell',
|
|
||||||
'corda-tools-shell-cli',
|
|
||||||
'corda-serialization',
|
|
||||||
'corda-tools-blob-inspector',
|
|
||||||
'corda-tools-explorer',
|
|
||||||
'corda-tools-network-bootstrapper',
|
|
||||||
'corda-tools-cliutils',
|
|
||||||
'corda-common-configuration-parsing',
|
|
||||||
'corda-common-validation',
|
|
||||||
'corda-common-logging',
|
|
||||||
'corda-tools-network-builder',
|
|
||||||
'corda-tools-checkpoint-agent'
|
|
||||||
]
|
|
||||||
license {
|
|
||||||
name = 'Apache-2.0'
|
|
||||||
url = 'https://www.apache.org/licenses/LICENSE-2.0'
|
|
||||||
distribution = 'repo'
|
|
||||||
}
|
|
||||||
developer {
|
|
||||||
id = 'R3'
|
|
||||||
name = 'R3'
|
|
||||||
email = 'dev@corda.net'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a ZIP of all JARs required to compile the Cordapp template
|
|
||||||
// Note: corda.jar is used at runtime so no runtime ZIP is necessary.
|
// Note: corda.jar is used at runtime so no runtime ZIP is necessary.
|
||||||
// Resulting ZIP can be found in "build/distributions"
|
// Resulting ZIP can be found in "build/distributions"
|
||||||
task buildCordappDependenciesZip(type: Zip) {
|
tasks.register('buildCordappDependenciesZip', Zip) {
|
||||||
baseName 'corda-deps'
|
baseName 'corda-deps'
|
||||||
from configurations.runtime
|
from configurations.runtimeOnly
|
||||||
from configurations.compile
|
from configurations.implementation
|
||||||
from configurations.testCompile
|
from configurations.testImplementation
|
||||||
from buildscript.configurations.classpath
|
from buildscript.configurations.classpath
|
||||||
from 'node/capsule/NOTICE' // CDDL notice
|
from 'node/capsule/NOTICE' // CDDL notice
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
artifactory {
|
tasks.register('generateApi', GenerateApi) {
|
||||||
publish {
|
|
||||||
contextUrl = artifactory_contextUrl
|
|
||||||
repository {
|
|
||||||
repoKey = 'corda-dev'
|
|
||||||
username = System.getenv('CORDA_ARTIFACTORY_USERNAME')
|
|
||||||
password = System.getenv('CORDA_ARTIFACTORY_PASSWORD')
|
|
||||||
}
|
|
||||||
|
|
||||||
defaults {
|
|
||||||
// Root project applies the plugin (for this block) but does not need to be published
|
|
||||||
if (project != rootProject) {
|
|
||||||
publications(project.extensions.publish.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('generateApi', net.corda.plugins.apiscanner.GenerateApi) {
|
|
||||||
baseName = "api-corda"
|
baseName = "api-corda"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,7 +642,7 @@ if (file('corda-docs-only-build').exists() || (System.getenv('CORDA_DOCS_ONLY_BU
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrapper {
|
wrapper {
|
||||||
gradleVersion = '5.6.4'
|
gradleVersion = '7.6.4'
|
||||||
distributionType = Wrapper.DistributionType.ALL
|
distributionType = Wrapper.DistributionType.ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
buildCacheSettings.gradle
Normal file
16
buildCacheSettings.gradle
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Gradle Build Cache configuration recommendation: https://docs.gradle.org/current/userguide/build_cache.html
|
||||||
|
ext {
|
||||||
|
isCiServer = System.getenv().containsKey("CORDA_CI")
|
||||||
|
gradleBuildCacheURL = System.getenv().containsKey("GRADLE_BUILD_CACHE_URL") ? System.getenv().get("GRADLE_BUILD_CACHE_URL") : 'http://localhost:5071/cache/'
|
||||||
|
}
|
||||||
|
|
||||||
|
buildCache {
|
||||||
|
local {
|
||||||
|
enabled = !isCiServer
|
||||||
|
}
|
||||||
|
remote(HttpBuildCache) {
|
||||||
|
enabled = isCiServer
|
||||||
|
url = gradleBuildCacheURL
|
||||||
|
push = isCiServer
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,56 @@
|
|||||||
|
plugins {
|
||||||
|
id 'groovy-gradle-plugin'
|
||||||
|
}
|
||||||
|
|
||||||
Properties constants = new Properties()
|
Properties constants = new Properties()
|
||||||
file("$rootDir/../constants.properties").withInputStream { constants.load(it) }
|
file("$rootDir/../constants.properties").withInputStream { constants.load(it) }
|
||||||
|
|
||||||
|
def internalPublishVersion = constants.getProperty('internalPublishVersion')
|
||||||
|
def artifactoryContextUrl = constants.getProperty('artifactoryContextUrl')
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
def cordaUseCache = System.getenv("CORDA_USE_CACHE")
|
||||||
|
if (cordaUseCache != null) {
|
||||||
|
maven {
|
||||||
|
url = "${artifactoryContextUrl}/${cordaUseCache}"
|
||||||
|
name = "R3 Maven remote repositories"
|
||||||
|
authentication {
|
||||||
|
basic(BasicAuthentication)
|
||||||
|
}
|
||||||
|
credentials {
|
||||||
|
username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
|
||||||
|
password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
|
||||||
|
}
|
||||||
|
metadataSources {
|
||||||
|
mavenPom()
|
||||||
|
artifact()
|
||||||
|
ignoreGradleMetadataRedirection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maven {
|
||||||
|
url "${artifactoryContextUrl}/engineering-tools-maven"
|
||||||
|
authentication {
|
||||||
|
basic(BasicAuthentication)
|
||||||
|
}
|
||||||
|
credentials {
|
||||||
|
username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
|
||||||
|
password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
|
||||||
|
}
|
||||||
|
content {
|
||||||
|
includeGroupByRegex 'com\\.r3\\.internal(\\..*)?'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile group: 'com.github.docker-java', name: 'docker-java', version: constants.dockerJavaVersion
|
implementation "com.github.docker-java:docker-java:$constants.dockerJavaVersion"
|
||||||
compile group: 'com.github.docker-java', name: 'docker-java-transport-httpclient5', version: constants.dockerJavaVersion
|
implementation "com.github.docker-java:docker-java-transport-httpclient5:$constants.dockerJavaVersion"
|
||||||
|
implementation "org.jooq:joor:$constants.joorVersion"
|
||||||
|
|
||||||
|
if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) {
|
||||||
|
implementation "com.r3.internal.gradle.plugins:publish:$internalPublishVersion"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
92
buildSrc/src/main/groovy/corda.common-publishing.gradle
Normal file
92
buildSrc/src/main/groovy/corda.common-publishing.gradle
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import groovy.transform.CompileStatic
|
||||||
|
|
||||||
|
// plugin to cater for R3 vs Non R3 users building code base. R3 employees will leverage internal plugins non
|
||||||
|
// R3 users will use standard Maven publishing conventions as provided by the Maven-publish gradle plugin
|
||||||
|
if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) {
|
||||||
|
logger.info("Internal R3 user - resolving publication build dependencies from internal plugins")
|
||||||
|
pluginManager.apply('com.r3.internal.gradle.plugins.r3Publish')
|
||||||
|
afterEvaluate {
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
configureEach {
|
||||||
|
def repo = "https://github.com/corda/corda"
|
||||||
|
pom {
|
||||||
|
description = project.description
|
||||||
|
name = project.name
|
||||||
|
url = repo
|
||||||
|
scm {
|
||||||
|
url = repo
|
||||||
|
}
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = 'Apache-2.0'
|
||||||
|
url = 'https://www.apache.org/licenses/LICENSE-2.0'
|
||||||
|
distribution = 'repo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = 'R3'
|
||||||
|
name = 'R3'
|
||||||
|
email = 'dev@corda.net'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("External user - using standard maven publishing")
|
||||||
|
pluginManager.apply('maven-publish')
|
||||||
|
pluginManager.withPlugin('java') {
|
||||||
|
afterEvaluate {
|
||||||
|
publishing {
|
||||||
|
if (publications.isEmpty()) {
|
||||||
|
// If we haven't already created a MavenPublication then create one now.
|
||||||
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId = tasks.named('jar', Jar).flatMap { it.archiveBaseName }.get()
|
||||||
|
groupId group.toString()
|
||||||
|
from findSoftwareComponent(components).get()
|
||||||
|
|
||||||
|
if (artifacts.matching { it.classifier == 'sources' }.isEmpty()) {
|
||||||
|
try {
|
||||||
|
artifact tasks.named('sourcesJar', Jar)
|
||||||
|
} catch (UnknownTaskException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
artifact tasks.named('javadocJar', Jar)
|
||||||
|
} catch (UnknownTaskException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(GenerateModuleMetadata).configureEach {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('install') {
|
||||||
|
dependsOn 'publishToMavenLocal'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
private static Provider<SoftwareComponent> findSoftwareComponent(SoftwareComponentContainer components) {
|
||||||
|
try {
|
||||||
|
return components.named('cordapp')
|
||||||
|
} catch (UnknownDomainObjectException ignored) {
|
||||||
|
try {
|
||||||
|
return components.named('kotlin')
|
||||||
|
} catch (UnknownDomainObjectException ignored2) {
|
||||||
|
return components.named('java')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
buildSrc/src/main/groovy/corda.kotlin-1.2.gradle
Normal file
91
buildSrc/src/main/groovy/corda.kotlin-1.2.gradle
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import org.gradle.api.internal.file.DefaultSourceDirectorySet
|
||||||
|
|
||||||
|
import static org.joor.Reflect.onClass
|
||||||
|
|
||||||
|
pluginManager.apply(Kotlin12Plugin.class)
|
||||||
|
|
||||||
|
// We cannot use the 1.2 Kotlin plugin as it only works with a very old version of Gradle, which itself will only work on Java 8. So we need
|
||||||
|
// our own plugin which calls the 1.2 compiler directly.
|
||||||
|
class Kotlin12Plugin implements Plugin<Project> {
|
||||||
|
private static final KOTLIN_VERSION = "1.2.71"
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void apply(Project project) {
|
||||||
|
project.pluginManager.apply(JavaPlugin.class)
|
||||||
|
|
||||||
|
project.extensions.add("kotlin_1_2_version", KOTLIN_VERSION)
|
||||||
|
project.dependencies.add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$KOTLIN_VERSION")
|
||||||
|
|
||||||
|
def kotlinCompilerConfiguration = project.configurations.create("kotlinCompiler")
|
||||||
|
project.dependencies.add("kotlinCompiler", "org.jetbrains.kotlin:kotlin-compiler:$KOTLIN_VERSION")
|
||||||
|
|
||||||
|
project.extensions.getByType(JavaPluginExtension.class).sourceSets.configureEach { sourceSet ->
|
||||||
|
// Create the "src/*/kotlin" SourceDirectorySet, alongside the "java" one
|
||||||
|
def kotlinSourceDirectorySet = new DefaultSourceDirectorySet(project.objects.sourceDirectorySet("kotlin", "${sourceSet.displayName} Kotlin source"))
|
||||||
|
sourceSet.extensions.add(SourceDirectorySet.class, "kotlin", kotlinSourceDirectorySet)
|
||||||
|
kotlinSourceDirectorySet.filter.include("**/*.java", "**/*.kt")
|
||||||
|
kotlinSourceDirectorySet.srcDir(project.file("src/${sourceSet.name}/kotlin"))
|
||||||
|
|
||||||
|
def allKotlin = project.objects.sourceDirectorySet("allkotlin", "${sourceSet.displayName} Kotlin source")
|
||||||
|
allKotlin.filter.include("**/*.kt")
|
||||||
|
allKotlin.source(kotlinSourceDirectorySet)
|
||||||
|
|
||||||
|
sourceSet.allJava.source(kotlinSourceDirectorySet)
|
||||||
|
sourceSet.allSource.source(kotlinSourceDirectorySet)
|
||||||
|
|
||||||
|
def kotlinBuildDir = project.layout.buildDirectory.dir("classes/kotlin/${sourceSet.name}")
|
||||||
|
sourceSet.output.dir(kotlinBuildDir)
|
||||||
|
|
||||||
|
def taskSourceSetName = isMain(sourceSet) ? "" : sourceSet.name.capitalize()
|
||||||
|
|
||||||
|
def compileKotlin = project.tasks.register("compile${taskSourceSetName}Kotlin", KotlinCompile.class) { task ->
|
||||||
|
// The 1.2 compiler needs to be laoded in a separate class loader, as the build classpath already contains its own version
|
||||||
|
// of Kotlin.
|
||||||
|
task.compilerClasspath.from(kotlinCompilerConfiguration)
|
||||||
|
task.source(allKotlin)
|
||||||
|
// Paradoxically, the Java sources are also required by the Kotlin compiler. This is actually so that it can correctly
|
||||||
|
// resolve any references the Kotlin code makes to Java code.
|
||||||
|
task.source(sourceSet.allJava)
|
||||||
|
task.classpath = sourceSet.compileClasspath
|
||||||
|
task.destinationDirectory = kotlinBuildDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiling the Java code needs the compiled Kotlin code first
|
||||||
|
project.tasks.named("compile${taskSourceSetName}Java", JavaCompile.class) { task ->
|
||||||
|
task.classpath += project.files(compileKotlin.map { it.destinationDirectory })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class KotlinCompile extends AbstractCompile {
|
||||||
|
@Classpath
|
||||||
|
abstract ConfigurableFileCollection getCompilerClasspath()
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
void compile() {
|
||||||
|
def args = [
|
||||||
|
"-jvm-target", "1.8",
|
||||||
|
"-language-version", "1.2",
|
||||||
|
"-api-version", "1.2",
|
||||||
|
"-java-parameters",
|
||||||
|
"-Xjvm-default=compatibility",
|
||||||
|
"-no-stdlib",
|
||||||
|
"-Xallow-kotlin-package", // We may have copies of stdlib APIs (see `core-1.2`)
|
||||||
|
"-cp", classpath.asPath,
|
||||||
|
"-d", destinationDirectory.get().asFile.absolutePath
|
||||||
|
]
|
||||||
|
args.addAll(source.collect { it.absolutePath })
|
||||||
|
|
||||||
|
logger.info("args: {}", args)
|
||||||
|
|
||||||
|
def compilerClassLoader = new URLClassLoader(compilerClasspath.collect { it.toURI().toURL() } as URL[])
|
||||||
|
def exitCode = onClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler", compilerClassLoader)
|
||||||
|
.create()
|
||||||
|
.call("exec", System.err, args as String[])
|
||||||
|
.get()
|
||||||
|
if (exitCode.toString() != "OK") {
|
||||||
|
throw new GradleException("Compilation error. See log for more details")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
buildSrc/src/main/groovy/corda.root-publish.gradle
Normal file
6
buildSrc/src/main/groovy/corda.root-publish.gradle
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Apply artifactory r3ArtifactoryPublish plugin
|
||||||
|
if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) {
|
||||||
|
project.pluginManager.apply('com.r3.internal.gradle.plugins.r3ArtifactoryPublish')
|
||||||
|
}
|
||||||
|
|
||||||
|
project.pluginManager.apply('maven-publish')
|
@ -1,25 +1,37 @@
|
|||||||
apply plugin: 'java'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'kotlin'
|
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
|
||||||
apply plugin: 'net.corda.plugins.api-scanner'
|
apply plugin: 'net.corda.plugins.api-scanner'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
apply plugin: 'corda.common-publishing'
|
||||||
|
|
||||||
|
description 'Corda Jackson module'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':serialization')
|
api project(':core')
|
||||||
|
|
||||||
|
implementation project(':serialization')
|
||||||
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
||||||
// Jackson and its plugins: parsing to/from JSON and other textual formats.
|
// Jackson and its plugins: parsing to/from JSON and other textual formats.
|
||||||
compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") {
|
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") {
|
||||||
exclude module: "jackson-databind"
|
exclude module: "jackson-databind"
|
||||||
}
|
}
|
||||||
// Yaml is useful for parsing strings to method calls.
|
// Yaml is useful for parsing strings to method calls.
|
||||||
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version"
|
implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version"
|
||||||
// This adds support for java.time types.
|
// This adds support for java.time types.
|
||||||
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version"
|
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version"
|
||||||
compile "com.google.guava:guava:$guava_version"
|
implementation "com.google.guava:guava:$guava_version"
|
||||||
|
|
||||||
testCompile project(':test-utils')
|
// Bouncy castle support needed for X509 certificate manipulation
|
||||||
testCompile project(path: ':core', configuration: 'testArtifacts')
|
implementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}"
|
||||||
|
implementation "org.bouncycastle:bcpkix-lts8on:${bouncycastle_version}"
|
||||||
|
implementation "org.bouncycastle:bcutil-lts8on:${bouncycastle_version}"
|
||||||
|
implementation "org.slf4j:slf4j-api:$slf4j_version"
|
||||||
|
|
||||||
|
testImplementation project(':finance:workflows')
|
||||||
|
testImplementation project(':node-api')
|
||||||
|
testImplementation project(':test-common')
|
||||||
|
testImplementation project(':core-test-utils')
|
||||||
|
testImplementation project(':test-utils')
|
||||||
|
testImplementation project(":node-driver")
|
||||||
|
testImplementation project(path: ':core', configuration: 'testArtifacts')
|
||||||
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
@ -28,7 +40,7 @@ dependencies {
|
|||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +51,11 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -24,7 +24,7 @@ import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier
|
|||||||
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers
|
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode
|
import com.fasterxml.jackson.databind.node.ObjectNode
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
import com.fasterxml.jackson.module.kotlin.kotlinModule
|
||||||
import net.corda.client.jackson.internal.CordaModule
|
import net.corda.client.jackson.internal.CordaModule
|
||||||
import net.corda.client.jackson.internal.ToStringSerialize
|
import net.corda.client.jackson.internal.ToStringSerialize
|
||||||
import net.corda.client.jackson.internal.jsonObject
|
import net.corda.client.jackson.internal.jsonObject
|
||||||
@ -197,7 +197,7 @@ object JacksonSupport {
|
|||||||
addSerializer(Date::class.java, DateSerializer)
|
addSerializer(Date::class.java, DateSerializer)
|
||||||
})
|
})
|
||||||
registerModule(CordaModule())
|
registerModule(CordaModule())
|
||||||
registerModule(KotlinModule().apply {
|
registerModule(kotlinModule().apply {
|
||||||
setDeserializerModifier(KotlinObjectDeserializerModifier)
|
setDeserializerModifier(KotlinObjectDeserializerModifier)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ open class StringToMethodCallParser<in T : Any> @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses either Kotlin or Java 8 reflection to learn the names of the parameters to a method.
|
* Uses either Kotlin or Java reflection to learn the names of the parameters to a method.
|
||||||
*/
|
*/
|
||||||
open fun paramNamesFromMethod(method: Method): List<String> {
|
open fun paramNamesFromMethod(method: Method): List<String> {
|
||||||
val kf: KFunction<*>? = method.kotlinFunction
|
val kf: KFunction<*>? = method.kotlinFunction
|
||||||
@ -135,7 +135,7 @@ open class StringToMethodCallParser<in T : Any> @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses either Kotlin or Java 8 reflection to learn the names of the parameters to a constructor.
|
* Uses either Kotlin or Java reflection to learn the names of the parameters to a constructor.
|
||||||
*/
|
*/
|
||||||
open fun paramNamesFromConstructor(ctor: Constructor<*>): List<String> {
|
open fun paramNamesFromConstructor(ctor: Constructor<*>): List<String> {
|
||||||
val kf: KFunction<*>? = ctor.kotlinFunction
|
val kf: KFunction<*>? = ctor.kotlinFunction
|
||||||
|
@ -95,7 +95,8 @@ import java.math.BigDecimal
|
|||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.Currency
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
class CordaModule : SimpleModule("corda-core") {
|
class CordaModule : SimpleModule("corda-core") {
|
||||||
override fun setupModule(context: SetupContext) {
|
override fun setupModule(context: SetupContext) {
|
||||||
@ -256,6 +257,7 @@ private data class StxJson(
|
|||||||
private interface WireTransactionMixin
|
private interface WireTransactionMixin
|
||||||
|
|
||||||
private class WireTransactionSerializer : JsonSerializer<WireTransaction>() {
|
private class WireTransactionSerializer : JsonSerializer<WireTransaction>() {
|
||||||
|
@Suppress("INVISIBLE_MEMBER")
|
||||||
override fun serialize(value: WireTransaction, gen: JsonGenerator, serializers: SerializerProvider) {
|
override fun serialize(value: WireTransaction, gen: JsonGenerator, serializers: SerializerProvider) {
|
||||||
gen.writeObject(WireTransactionJson(
|
gen.writeObject(WireTransactionJson(
|
||||||
value.digestService,
|
value.digestService,
|
||||||
@ -265,7 +267,7 @@ private class WireTransactionSerializer : JsonSerializer<WireTransaction>() {
|
|||||||
value.outputs,
|
value.outputs,
|
||||||
value.commands,
|
value.commands,
|
||||||
value.timeWindow,
|
value.timeWindow,
|
||||||
value.attachments,
|
value.legacyAttachments.map { "$it-legacy" } + value.nonLegacyAttachments.map { it.toString() },
|
||||||
value.references,
|
value.references,
|
||||||
value.privacySalt,
|
value.privacySalt,
|
||||||
value.networkParametersHash
|
value.networkParametersHash
|
||||||
@ -276,15 +278,18 @@ private class WireTransactionSerializer : JsonSerializer<WireTransaction>() {
|
|||||||
private class WireTransactionDeserializer : JsonDeserializer<WireTransaction>() {
|
private class WireTransactionDeserializer : JsonDeserializer<WireTransaction>() {
|
||||||
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): WireTransaction {
|
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): WireTransaction {
|
||||||
val wrapper = parser.readValueAs<WireTransactionJson>()
|
val wrapper = parser.readValueAs<WireTransactionJson>()
|
||||||
|
// We're not concerned with backwards compatibility for any JSON string that was created with 4.11 and being materialised in 4.12.
|
||||||
|
val (legacyAttachments, newerAttachments) = wrapper.attachments.partition { it.endsWith("-legacy") }
|
||||||
val componentGroups = createComponentGroups(
|
val componentGroups = createComponentGroups(
|
||||||
wrapper.inputs,
|
wrapper.inputs,
|
||||||
wrapper.outputs,
|
wrapper.outputs,
|
||||||
wrapper.commands,
|
wrapper.commands,
|
||||||
wrapper.attachments,
|
newerAttachments.map(SecureHash::parse),
|
||||||
wrapper.notary,
|
wrapper.notary,
|
||||||
wrapper.timeWindow,
|
wrapper.timeWindow,
|
||||||
wrapper.references,
|
wrapper.references,
|
||||||
wrapper.networkParametersHash
|
wrapper.networkParametersHash,
|
||||||
|
legacyAttachments.map { SecureHash.parse(it.removeSuffix("-legacy")) }
|
||||||
)
|
)
|
||||||
return WireTransaction(componentGroups, wrapper.privacySalt, wrapper.digestService ?: DigestService.sha2_256)
|
return WireTransaction(componentGroups, wrapper.privacySalt, wrapper.digestService ?: DigestService.sha2_256)
|
||||||
}
|
}
|
||||||
@ -297,10 +302,11 @@ private class WireTransactionJson(@get:JsonInclude(Include.NON_NULL) val digestS
|
|||||||
val outputs: List<TransactionState<*>>,
|
val outputs: List<TransactionState<*>>,
|
||||||
val commands: List<Command<*>>,
|
val commands: List<Command<*>>,
|
||||||
val timeWindow: TimeWindow?,
|
val timeWindow: TimeWindow?,
|
||||||
val attachments: List<SecureHash>,
|
val attachments: List<String>,
|
||||||
val references: List<StateRef>,
|
val references: List<StateRef>,
|
||||||
val privacySalt: PrivacySalt,
|
val privacySalt: PrivacySalt,
|
||||||
val networkParametersHash: SecureHash?)
|
val networkParametersHash: SecureHash?
|
||||||
|
)
|
||||||
|
|
||||||
private interface TransactionStateMixin {
|
private interface TransactionStateMixin {
|
||||||
@get:JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
@get:JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||||
|
@ -8,27 +8,36 @@ import com.fasterxml.jackson.databind.node.ObjectNode
|
|||||||
import com.fasterxml.jackson.databind.node.TextNode
|
import com.fasterxml.jackson.databind.node.TextNode
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||||
import com.fasterxml.jackson.module.kotlin.convertValue
|
import com.fasterxml.jackson.module.kotlin.convertValue
|
||||||
import com.nhaarman.mockito_kotlin.any
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import com.nhaarman.mockito_kotlin.spy
|
|
||||||
import net.corda.client.jackson.internal.childrenAs
|
import net.corda.client.jackson.internal.childrenAs
|
||||||
import net.corda.client.jackson.internal.valueAs
|
import net.corda.client.jackson.internal.valueAs
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.Amount
|
||||||
|
import net.corda.core.contracts.Command
|
||||||
|
import net.corda.core.contracts.LinearState
|
||||||
|
import net.corda.core.contracts.PrivacySalt
|
||||||
|
import net.corda.core.contracts.StateRef
|
||||||
|
import net.corda.core.contracts.TimeWindow
|
||||||
|
import net.corda.core.contracts.TransactionState
|
||||||
|
import net.corda.core.contracts.UniqueIdentifier
|
||||||
import net.corda.core.cordapp.CordappProvider
|
import net.corda.core.cordapp.CordappProvider
|
||||||
import net.corda.core.crypto.*
|
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
|
import net.corda.core.crypto.Crypto
|
||||||
|
import net.corda.core.crypto.DigestService
|
||||||
|
import net.corda.core.crypto.DigitalSignature
|
||||||
|
import net.corda.core.crypto.PartialMerkleTree
|
||||||
import net.corda.core.crypto.PartialMerkleTree.PartialTree
|
import net.corda.core.crypto.PartialMerkleTree.PartialTree
|
||||||
import net.corda.core.identity.*
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.crypto.SignatureMetadata
|
||||||
|
import net.corda.core.crypto.SignatureScheme
|
||||||
|
import net.corda.core.crypto.TransactionSignature
|
||||||
|
import net.corda.core.crypto.secureRandomBytes
|
||||||
|
import net.corda.core.identity.AbstractParty
|
||||||
|
import net.corda.core.identity.AnonymousParty
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.DigitalSignatureWithCert
|
import net.corda.core.internal.DigitalSignatureWithCert
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
|
||||||
import net.corda.core.node.services.IdentityService
|
|
||||||
import net.corda.core.node.services.NetworkParametersService
|
|
||||||
import net.corda.core.node.services.TransactionStorage
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
@ -37,14 +46,27 @@ import net.corda.core.transactions.CoreTransaction
|
|||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.ByteSequence
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.days
|
||||||
|
import net.corda.core.utilities.hours
|
||||||
|
import net.corda.core.utilities.toBase58String
|
||||||
|
import net.corda.core.utilities.toBase64
|
||||||
|
import net.corda.core.utilities.toHexString
|
||||||
|
import net.corda.coretesting.internal.createNodeInfoAndSigned
|
||||||
|
import net.corda.coretesting.internal.rigorousMock
|
||||||
import net.corda.finance.USD
|
import net.corda.finance.USD
|
||||||
import net.corda.nodeapi.internal.crypto.x509Certificates
|
import net.corda.nodeapi.internal.crypto.x509Certificates
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.core.*
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.coretesting.internal.createNodeInfoAndSigned
|
import net.corda.testing.core.BOB_NAME
|
||||||
import net.corda.coretesting.internal.rigorousMock
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
|
import net.corda.testing.core.DummyCommandData
|
||||||
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.core.TestIdentity
|
||||||
|
import net.corda.testing.node.MockServices
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -54,15 +76,22 @@ import org.junit.jupiter.api.TestFactory
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
import org.junit.runners.Parameterized.Parameters
|
import org.junit.runners.Parameterized.Parameters
|
||||||
|
import org.mockito.kotlin.spy
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.nio.charset.StandardCharsets.UTF_8
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.Currency
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.UUID
|
||||||
import javax.security.auth.x500.X500Principal
|
import javax.security.auth.x500.X500Principal
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.component1
|
||||||
|
import kotlin.collections.component2
|
||||||
|
import kotlin.collections.component3
|
||||||
|
import kotlin.collections.component4
|
||||||
|
|
||||||
@RunWith(Parameterized::class)
|
@RunWith(Parameterized::class)
|
||||||
class JacksonSupportTest(@Suppress("unused") private val name: String, factory: JsonFactory) {
|
class JacksonSupportTest(@Suppress("unused") private val name: String, factory: JsonFactory) {
|
||||||
@ -90,23 +119,12 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory:
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
val unsignedAttachment = object : AbstractAttachment({ byteArrayOf() }, "test") {
|
services = MockServices(
|
||||||
override val id: SecureHash get() = throw UnsupportedOperationException()
|
listOf("net.corda.testing.contracts"),
|
||||||
}
|
MINI_CORP,
|
||||||
|
testNetworkParameters(minimumPlatformVersion = 4)
|
||||||
val attachments = rigorousMock<AttachmentStorage>().also {
|
)
|
||||||
doReturn(unsignedAttachment).whenever(it).openAttachment(any())
|
|
||||||
}
|
|
||||||
services = rigorousMock()
|
|
||||||
cordappProvider = rigorousMock()
|
cordappProvider = rigorousMock()
|
||||||
val networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
|
||||||
val networkParametersService = rigorousMock<NetworkParametersService>().also {
|
|
||||||
doReturn(networkParameters.serialize().hash).whenever(it).currentHash
|
|
||||||
}
|
|
||||||
doReturn(networkParametersService).whenever(services).networkParametersService
|
|
||||||
doReturn(cordappProvider).whenever(services).cordappProvider
|
|
||||||
doReturn(networkParameters).whenever(services).networkParameters
|
|
||||||
doReturn(attachments).whenever(services).attachments
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -263,17 +281,6 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory:
|
|||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `SignedTransaction (WireTransaction)`() {
|
fun `SignedTransaction (WireTransaction)`() {
|
||||||
val attachmentId = SecureHash.randomSHA256()
|
val attachmentId = SecureHash.randomSHA256()
|
||||||
doReturn(attachmentId).whenever(cordappProvider).getContractAttachmentID(DummyContract.PROGRAM_ID)
|
|
||||||
val attachmentStorage = rigorousMock<AttachmentStorage>()
|
|
||||||
doReturn(attachmentStorage).whenever(services).attachments
|
|
||||||
doReturn(mock<TransactionStorage>()).whenever(services).validatedTransactions
|
|
||||||
doReturn(mock<IdentityService>()).whenever(services).identityService
|
|
||||||
val attachment = rigorousMock<ContractAttachment>()
|
|
||||||
doReturn(attachment).whenever(attachmentStorage).openAttachment(attachmentId)
|
|
||||||
doReturn(attachmentId).whenever(attachment).id
|
|
||||||
doReturn(emptyList<Party>()).whenever(attachment).signerKeys
|
|
||||||
doReturn(setOf(DummyContract.PROGRAM_ID)).whenever(attachment).allContracts
|
|
||||||
doReturn("app").whenever(attachment).uploader
|
|
||||||
|
|
||||||
val wtx = TransactionBuilder(
|
val wtx = TransactionBuilder(
|
||||||
notary = DUMMY_NOTARY,
|
notary = DUMMY_NOTARY,
|
||||||
|
@ -26,7 +26,7 @@ class StringToMethodCallParserTest {
|
|||||||
"simple" to "simple",
|
"simple" to "simple",
|
||||||
"string noteTextWord: A test of barewords" to "A test of barewords",
|
"string noteTextWord: A test of barewords" to "A test of barewords",
|
||||||
"twoStrings a: Some words, b: ' and some words, like, Kirk, would, speak'" to "Some words and some words, like, Kirk, would, speak",
|
"twoStrings a: Some words, b: ' and some words, like, Kirk, would, speak'" to "Some words and some words, like, Kirk, would, speak",
|
||||||
"simpleObject hash: $randomHash" to randomHash.toUpperCase(),
|
"simpleObject hash: $randomHash" to randomHash.uppercase(Locale.getDefault()),
|
||||||
"complexObject pair: { first: 12, second: Word up brother }" to Pair(12, "Word up brother"),
|
"complexObject pair: { first: 12, second: Word up brother }" to Pair(12, "Word up brother"),
|
||||||
"overload a: A" to "A",
|
"overload a: A" to "A",
|
||||||
"overload a: A, b: B" to "AB"
|
"overload a: A, b: B" to "AB"
|
||||||
@ -51,7 +51,6 @@ class StringToMethodCallParserTest {
|
|||||||
val result = parser.parse(Target(), "complexNestedObject pairs: { first: 101, second: [ A, B, C ] }").invoke()
|
val result = parser.parse(Target(), "complexNestedObject pairs: { first: 101, second: [ A, B, C ] }").invoke()
|
||||||
|
|
||||||
assertTrue(result is Pair<*,*>)
|
assertTrue(result is Pair<*,*>)
|
||||||
result as Pair<*,*>
|
|
||||||
|
|
||||||
assertEquals(101, result.first)
|
assertEquals(101, result.first)
|
||||||
|
|
||||||
|
@ -1,28 +1,27 @@
|
|||||||
// JDK 11 JavaFX
|
// JDK 11 JavaFX
|
||||||
plugins {
|
plugins {
|
||||||
id 'org.openjfx.javafxplugin' version '0.0.7' apply false
|
id 'org.openjfx.javafxplugin' version '0.0.7' apply false
|
||||||
|
id 'corda.common-publishing'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JavaVersion.current().isJava9Compatible()) {
|
|
||||||
apply plugin: 'org.openjfx.javafxplugin'
|
apply plugin: 'org.openjfx.javafxplugin'
|
||||||
javafx {
|
javafx {
|
||||||
version = "11.0.2"
|
version = "11.0.2"
|
||||||
modules = ['javafx.controls',
|
modules = [
|
||||||
|
'javafx.controls',
|
||||||
'javafx.fxml'
|
'javafx.fxml'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
|
||||||
|
|
||||||
description 'Corda client JavaFX modules'
|
description 'Corda client JavaFX modules'
|
||||||
|
|
||||||
//noinspection GroovyAssignabilityCheck
|
//noinspection GroovyAssignabilityCheck
|
||||||
configurations {
|
configurations {
|
||||||
integrationTestCompile.extendsFrom testCompile
|
integrationTestImplementation.extendsFrom testImplementation
|
||||||
integrationTestRuntime.extendsFrom testRuntime
|
integrationTestRuntime.extendsFrom testRuntimeOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@ -39,23 +38,26 @@ sourceSets {
|
|||||||
// build/reports/project/dependencies/index.html for green highlighted parts of the tree.
|
// build/reports/project/dependencies/index.html for green highlighted parts of the tree.
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':core')
|
implementation project(':core')
|
||||||
compile project(':finance:contracts')
|
implementation project(':finance:contracts')
|
||||||
compile project(':finance:workflows')
|
implementation project(':finance:workflows')
|
||||||
compile project(':client:rpc')
|
implementation project(':client:rpc')
|
||||||
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "com.google.guava:guava:$guava_version"
|
||||||
compile "com.google.guava:guava:$guava_version"
|
implementation "io.reactivex:rxjava:$rxjava_version"
|
||||||
|
|
||||||
|
// For caches rather than guava
|
||||||
|
implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||||
|
|
||||||
// ReactFX: Functional reactive UI programming.
|
// ReactFX: Functional reactive UI programming.
|
||||||
compile 'org.reactfx:reactfx:2.0-M5'
|
implementation 'org.reactfx:reactfx:2.0-M5'
|
||||||
compile 'org.fxmisc.easybind:easybind:1.0.3'
|
implementation 'org.fxmisc.easybind:easybind:1.0.3'
|
||||||
|
|
||||||
// Artemis Client: ability to connect to an Artemis broker and control it.
|
// Artemis Client: ability to connect to an Artemis broker and control it.
|
||||||
// TODO: remove the forced update of commons-collections and beanutils when artemis updates them
|
// TODO: remove the forced update of commons-collections and beanutils when artemis updates them
|
||||||
compile "org.apache.commons:commons-collections4:${commons_collections_version}"
|
implementation "org.apache.commons:commons-collections4:${commons_collections_version}"
|
||||||
compile "commons-beanutils:commons-beanutils:${beanutils_version}"
|
implementation "commons-beanutils:commons-beanutils:${beanutils_version}"
|
||||||
compile("org.apache.activemq:artemis-core-client:${artemis_version}") {
|
implementation("org.apache.activemq:artemis-core-client:${artemis_version}") {
|
||||||
exclude group: 'org.jgroups', module: 'jgroups'
|
exclude group: 'org.jgroups', module: 'jgroups'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,13 +69,14 @@ dependencies {
|
|||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
testImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||||
|
|
||||||
testCompile project(':test-utils')
|
testImplementation project(':test-utils')
|
||||||
|
|
||||||
// Integration test helpers
|
// Integration test helpers
|
||||||
integrationTestCompile "junit:junit:$junit_version"
|
integrationTestImplementation "junit:junit:$junit_version"
|
||||||
integrationTestCompile project(':node-driver')
|
integrationTestImplementation project(':node-driver')
|
||||||
}
|
}
|
||||||
|
|
||||||
task integrationTest(type: Test) {
|
task integrationTest(type: Test) {
|
||||||
@ -88,6 +91,11 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,14 @@ import java.util.stream.Collectors
|
|||||||
* Utility bindings for the [Amount] type, similar in spirit to [Bindings]
|
* Utility bindings for the [Amount] type, similar in spirit to [Bindings]
|
||||||
*/
|
*/
|
||||||
object AmountBindings {
|
object AmountBindings {
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun <T : Any> sum(amounts: ObservableList<Amount<T>>, token: T): MonadicBinding<Amount<T>> = EasyBind.map(
|
fun <T : Any> sum(amounts: ObservableList<Amount<T>>, token: T): MonadicBinding<Amount<T>> = EasyBind.map(
|
||||||
Bindings.createLongBinding({
|
Bindings.createLongBinding({
|
||||||
amounts.stream().collect(Collectors.summingLong {
|
amounts.stream().collect(Collectors.summingLong {
|
||||||
require(it.token == token)
|
require(it.token == token)
|
||||||
it.quantity
|
it.quantity
|
||||||
})
|
})
|
||||||
}, arrayOf(amounts))
|
}, *arrayOf(amounts))
|
||||||
) { sum -> Amount(sum.toLong(), token) }
|
) { sum -> Amount(sum.toLong(), token) }
|
||||||
|
|
||||||
fun exchange(
|
fun exchange(
|
||||||
@ -35,6 +36,7 @@ object AmountBindings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun sumAmountExchange(
|
fun sumAmountExchange(
|
||||||
amounts: ObservableList<Amount<Currency>>,
|
amounts: ObservableList<Amount<Currency>>,
|
||||||
currency: ObservableValue<Currency>,
|
currency: ObservableValue<Currency>,
|
||||||
@ -45,7 +47,7 @@ object AmountBindings {
|
|||||||
EasyBind.map(
|
EasyBind.map(
|
||||||
Bindings.createLongBinding({
|
Bindings.createLongBinding({
|
||||||
amounts.stream().collect(Collectors.summingLong { exchange(it) })
|
amounts.stream().collect(Collectors.summingLong { exchange(it) })
|
||||||
}, arrayOf(amounts))
|
}, *arrayOf(amounts))
|
||||||
) { Amount(it.toLong(), currencyValue) }
|
) { Amount(it.toLong(), currencyValue) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ fun <A> ObservableList<out A>.filter(predicate: ObservableValue<(A) -> Boolean>)
|
|||||||
*/
|
*/
|
||||||
fun <A> ObservableList<out A?>.filterNotNull(): ObservableList<A> {
|
fun <A> ObservableList<out A?>.filterNotNull(): ObservableList<A> {
|
||||||
//TODO This is a tactical work round for an issue with SAM conversion (https://youtrack.jetbrains.com/issue/ALL-1552) so that the M10 explorer works.
|
//TODO This is a tactical work round for an issue with SAM conversion (https://youtrack.jetbrains.com/issue/ALL-1552) so that the M10 explorer works.
|
||||||
return uncheckedCast(uncheckedCast<Any, ObservableList<A?>>(this).filtered { t -> t != null })
|
return uncheckedCast(uncheckedCast<Any, ObservableList<A>>(this).filtered { t -> t != null })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,6 +128,7 @@ fun <A> ObservableList<out A?>.filterNotNull(): ObservableList<A> {
|
|||||||
* val concatenatedNames = people.foldObservable("", { names, person -> names + person.name })
|
* val concatenatedNames = people.foldObservable("", { names, person -> names + person.name })
|
||||||
* val concatenatedNames2 = people.map(Person::name).fold("", String::plus)
|
* val concatenatedNames2 = people.map(Person::name).fold("", String::plus)
|
||||||
*/
|
*/
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun <A, B> ObservableList<out A>.foldObservable(initial: B, folderFunction: (B, A) -> B): ObservableValue<B> {
|
fun <A, B> ObservableList<out A>.foldObservable(initial: B, folderFunction: (B, A) -> B): ObservableValue<B> {
|
||||||
return Bindings.createObjectBinding({
|
return Bindings.createObjectBinding({
|
||||||
var current = initial
|
var current = initial
|
||||||
@ -135,7 +136,7 @@ fun <A, B> ObservableList<out A>.foldObservable(initial: B, folderFunction: (B,
|
|||||||
current = folderFunction(current, it)
|
current = folderFunction(current, it)
|
||||||
}
|
}
|
||||||
current
|
current
|
||||||
}, arrayOf(this))
|
}, *arrayOf(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -285,6 +286,7 @@ fun <A> ObservableList<A>.first(): ObservableValue<A?> {
|
|||||||
return getValueAt(0)
|
return getValueAt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun <A> ObservableList<A>.last(): ObservableValue<A?> {
|
fun <A> ObservableList<A>.last(): ObservableValue<A?> {
|
||||||
return Bindings.createObjectBinding({
|
return Bindings.createObjectBinding({
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
@ -292,7 +294,7 @@ fun <A> ObservableList<A>.last(): ObservableValue<A?> {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}, arrayOf(this))
|
}, *arrayOf(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> ObservableList<T>.unique(): ObservableList<T> {
|
fun <T : Any> ObservableList<T>.unique(): ObservableList<T> {
|
||||||
@ -303,24 +305,27 @@ fun <T : Any, K : Any> ObservableList<T>.distinctBy(toKey: (T) -> K): Observable
|
|||||||
return AggregatedList(this, toKey, { _, entryList -> entryList[0] })
|
return AggregatedList(this, toKey, { _, entryList -> entryList[0] })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun ObservableValue<*>.isNotNull(): BooleanBinding {
|
fun ObservableValue<*>.isNotNull(): BooleanBinding {
|
||||||
return Bindings.createBooleanBinding({ this.value != null }, arrayOf(this))
|
return Bindings.createBooleanBinding({ this.value != null }, *arrayOf(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return first element of the observable list as observable value.
|
* Return first element of the observable list as observable value.
|
||||||
* Return provided default value if the list is empty.
|
* Return provided default value if the list is empty.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun <A> ObservableList<A>.firstOrDefault(default: ObservableValue<A?>, predicate: (A) -> Boolean): ObservableValue<A?> {
|
fun <A> ObservableList<A>.firstOrDefault(default: ObservableValue<A?>, predicate: (A) -> Boolean): ObservableValue<A?> {
|
||||||
return Bindings.createObjectBinding({ this.firstOrNull(predicate) ?: default.value }, arrayOf(this, default))
|
return Bindings.createObjectBinding({ this.firstOrNull(predicate) ?: default.value }, *arrayOf(this, default))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return first element of the observable list as observable value.
|
* Return first element of the observable list as observable value.
|
||||||
* Return ObservableValue(null) if the list is empty.
|
* Return ObservableValue(null) if the list is empty.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun <A> ObservableList<A>.firstOrNullObservable(predicate: (A) -> Boolean): ObservableValue<A?> {
|
fun <A> ObservableList<A>.firstOrNullObservable(predicate: (A) -> Boolean): ObservableValue<A?> {
|
||||||
return Bindings.createObjectBinding({ this.firstOrNull(predicate) }, arrayOf(this))
|
return Bindings.createObjectBinding({ this.firstOrNull(predicate) }, *arrayOf(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
apply plugin: 'corda.common-publishing'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
|
||||||
|
|
||||||
description 'Corda client mock modules'
|
description 'Corda client mock modules'
|
||||||
|
|
||||||
@ -9,9 +8,9 @@ description 'Corda client mock modules'
|
|||||||
// build/reports/project/dependencies/index.html for green highlighted parts of the tree.
|
// build/reports/project/dependencies/index.html for green highlighted parts of the tree.
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(":core")
|
implementation project(":core")
|
||||||
compile project(':finance:workflows')
|
implementation project(':finance:workflows')
|
||||||
compile project(':finance:contracts')
|
implementation project(':finance:contracts')
|
||||||
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
@ -21,9 +20,9 @@ dependencies {
|
|||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
// Unit testing helpers.
|
// Unit testing helpers.
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
testImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||||
|
|
||||||
testCompile project(':test-utils')
|
testImplementation project(':test-utils')
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
@ -39,6 +38,11 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,20 @@
|
|||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
|
||||||
apply plugin: 'net.corda.plugins.api-scanner'
|
apply plugin: 'net.corda.plugins.api-scanner'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
apply plugin: 'corda.common-publishing'
|
||||||
|
apply plugin: 'us.kirchmeier.capsule'
|
||||||
|
|
||||||
description 'Corda client RPC modules'
|
description 'Corda client RPC modules'
|
||||||
|
|
||||||
//noinspection GroovyAssignabilityCheck
|
//noinspection GroovyAssignabilityCheck
|
||||||
configurations {
|
configurations {
|
||||||
integrationTestCompile.extendsFrom testCompile
|
integrationTestImplementation.extendsFrom testImplementation
|
||||||
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
|
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
|
||||||
|
|
||||||
smokeTestCompile.extendsFrom compile
|
smokeTestImplementation.extendsFrom compile
|
||||||
smokeTestRuntimeOnly.extendsFrom runtimeOnly
|
smokeTestRuntimeOnly.extendsFrom runtimeOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
|
|
||||||
compileTestKotlin {
|
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
integrationTest {
|
integrationTest {
|
||||||
kotlin {
|
kotlin {
|
||||||
@ -55,8 +47,58 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':core')
|
||||||
|
implementation project(':node-api')
|
||||||
|
implementation project(':serialization')
|
||||||
|
// For caches rather than guava
|
||||||
|
implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
|
implementation "io.reactivex:rxjava:$rxjava_version"
|
||||||
|
implementation("org.apache.activemq:artemis-core-client:${artemis_version}") {
|
||||||
|
exclude group: 'org.jgroups', module: 'jgroups'
|
||||||
|
}
|
||||||
|
implementation "com.google.guava:guava-testlib:$guava_version"
|
||||||
|
|
||||||
|
testImplementation project(':node')
|
||||||
|
testImplementation project(':node-driver')
|
||||||
|
testImplementation project(':client:mock')
|
||||||
|
testImplementation project(':core-test-utils')
|
||||||
|
testImplementation "junit:junit:$junit_version"
|
||||||
|
// Unit testing helpers.
|
||||||
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
testImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||||
|
testImplementation "io.dropwizard.metrics:metrics-core:$metrics_version"
|
||||||
|
|
||||||
|
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||||
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
|
integrationTestImplementation project(path: ':node-api', configuration: 'testArtifacts')
|
||||||
|
integrationTestImplementation project(':common-configuration-parsing')
|
||||||
|
integrationTestImplementation project(':finance:contracts')
|
||||||
|
integrationTestImplementation project(':finance:workflows')
|
||||||
|
integrationTestImplementation project(':test-utils')
|
||||||
|
integrationTestImplementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||||
|
integrationTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
|
||||||
|
|
||||||
|
smokeTestImplementation project(':core')
|
||||||
|
smokeTestImplementation project(':node-api')
|
||||||
|
smokeTestImplementation project(':finance:contracts')
|
||||||
|
smokeTestImplementation project(':finance:workflows')
|
||||||
|
smokeTestImplementation project(':smoke-test-utils')
|
||||||
|
smokeTestImplementation project(':testing:cordapps:sleeping')
|
||||||
|
smokeTestImplementation "junit:junit:$junit_version"
|
||||||
|
smokeTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
smokeTestImplementation "com.google.guava:guava:$guava_version"
|
||||||
|
smokeTestImplementation "org.hamcrest:hamcrest-library:2.1"
|
||||||
|
|
||||||
|
smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||||
|
smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
}
|
||||||
|
|
||||||
processSmokeTestResources {
|
processSmokeTestResources {
|
||||||
from(project(':node:capsule').tasks['buildCordaJAR']) {
|
// Bring in the fully built corda.jar for use by NodeFactory in the smoke tests
|
||||||
|
from(project(":node:capsule").tasks['buildCordaJAR']) {
|
||||||
rename 'corda-(.*)', 'corda.jar'
|
rename 'corda-(.*)', 'corda.jar'
|
||||||
}
|
}
|
||||||
from(project(':finance:workflows').tasks['jar']) {
|
from(project(':finance:workflows').tasks['jar']) {
|
||||||
@ -70,52 +112,12 @@ processSmokeTestResources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To find potential version conflicts, run "gradle htmlDependencyReport" and then look in
|
tasks.register('integrationTest', Test) {
|
||||||
// build/reports/project/dependencies/index.html for green highlighted parts of the tree.
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile project(':core')
|
|
||||||
compile project(':node-api')
|
|
||||||
|
|
||||||
// For caches rather than guava
|
|
||||||
compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
|
||||||
|
|
||||||
testImplementation "junit:junit:$junit_version"
|
|
||||||
|
|
||||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
|
||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
|
||||||
|
|
||||||
// Unit testing helpers.
|
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
|
||||||
|
|
||||||
testCompile project(':node-driver')
|
|
||||||
testCompile project(':client:mock')
|
|
||||||
integrationTestCompile project(path: ':node-api', configuration: 'testArtifacts')
|
|
||||||
|
|
||||||
// Smoke tests do NOT have any Node code on the classpath!
|
|
||||||
smokeTestCompile project(':smoke-test-utils')
|
|
||||||
smokeTestCompile project(':finance:contracts')
|
|
||||||
smokeTestCompile project(':finance:workflows')
|
|
||||||
smokeTestCompile project(':testing:cordapps:sleeping')
|
|
||||||
smokeTestCompile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
|
||||||
smokeTestCompile "org.apache.logging.log4j:log4j-core:$log4j_version"
|
|
||||||
smokeTestCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
|
||||||
smokeTestCompile "org.assertj:assertj-core:${assertj_version}"
|
|
||||||
smokeTestImplementation "junit:junit:$junit_version"
|
|
||||||
smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
|
||||||
smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
|
||||||
|
|
||||||
// JDK11: required by Quasar at run-time
|
|
||||||
smokeTestRuntimeOnly "com.esotericsoftware:kryo:$kryo_version"
|
|
||||||
}
|
|
||||||
|
|
||||||
task integrationTest(type: Test) {
|
|
||||||
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
||||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
task smokeTest(type: Test) {
|
tasks.register('smokeTest', Test) {
|
||||||
testClassesDirs = sourceSets.smokeTest.output.classesDirs
|
testClassesDirs = sourceSets.smokeTest.output.classesDirs
|
||||||
classpath = sourceSets.smokeTest.runtimeClasspath
|
classpath = sourceSets.smokeTest.runtimeClasspath
|
||||||
}
|
}
|
||||||
@ -127,6 +129,11 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ import org.junit.Test
|
|||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.util.*
|
import java.util.Currency
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.ScheduledExecutorService
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.any
|
import org.mockito.kotlin.any
|
||||||
import com.nhaarman.mockito_kotlin.atLeastOnce
|
import org.mockito.kotlin.atLeastOnce
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import com.nhaarman.mockito_kotlin.never
|
import org.mockito.kotlin.never
|
||||||
import com.nhaarman.mockito_kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import com.nhaarman.mockito_kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
import net.corda.client.rpc.internal.RPCClient
|
import net.corda.client.rpc.internal.RPCClient
|
||||||
import net.corda.client.rpc.ext.RPCConnectionListener
|
import net.corda.client.rpc.ext.RPCConnectionListener
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import net.corda.client.rpc.RPCMultipleInterfacesTests.StringRPCOpsImpl.testPhrase
|
import net.corda.client.rpc.RPCMultipleInterfacesTests.StringRPCOpsImpl.testPhrase
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
|
@ -552,7 +552,7 @@ class RPCStabilityTests {
|
|||||||
// Construct an RPC session manually so that we can hang in the message handler
|
// Construct an RPC session manually so that we can hang in the message handler
|
||||||
val myQueue = "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.test.${random63BitValue()}"
|
val myQueue = "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.test.${random63BitValue()}"
|
||||||
val session = startArtemisSession(server.broker.hostAndPort!!)
|
val session = startArtemisSession(server.broker.hostAndPort!!)
|
||||||
session.createQueue(QueueConfiguration(myQueue)
|
session.createQueue(QueueConfiguration.of(myQueue)
|
||||||
.setRoutingType(ActiveMQDefaultConfiguration.getDefaultRoutingType())
|
.setRoutingType(ActiveMQDefaultConfiguration.getDefaultRoutingType())
|
||||||
.setAddress(myQueue)
|
.setAddress(myQueue)
|
||||||
.setTemporary(true)
|
.setTemporary(true)
|
||||||
@ -569,7 +569,7 @@ class RPCStabilityTests {
|
|||||||
|
|
||||||
val message = session.createMessage(false)
|
val message = session.createMessage(false)
|
||||||
val request = RPCApi.ClientToServer.RpcRequest(
|
val request = RPCApi.ClientToServer.RpcRequest(
|
||||||
clientAddress = SimpleString(myQueue),
|
clientAddress = SimpleString.of(myQueue),
|
||||||
methodName = SlowConsumerRPCOps::streamAtInterval.name,
|
methodName = SlowConsumerRPCOps::streamAtInterval.name,
|
||||||
serialisedArguments = listOf(100.millis, 1234).serialize(context = SerializationDefaults.RPC_SERVER_CONTEXT),
|
serialisedArguments = listOf(100.millis, 1234).serialize(context = SerializationDefaults.RPC_SERVER_CONTEXT),
|
||||||
replyId = Trace.InvocationId.newInstance(),
|
replyId = Trace.InvocationId.newInstance(),
|
||||||
@ -593,7 +593,7 @@ class RPCStabilityTests {
|
|||||||
// Construct an RPC client session manually
|
// Construct an RPC client session manually
|
||||||
val myQueue = "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.test.${random63BitValue()}"
|
val myQueue = "${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.test.${random63BitValue()}"
|
||||||
val session = startArtemisSession(server.broker.hostAndPort!!)
|
val session = startArtemisSession(server.broker.hostAndPort!!)
|
||||||
session.createQueue(QueueConfiguration(myQueue)
|
session.createQueue(QueueConfiguration.of(myQueue)
|
||||||
.setRoutingType(ActiveMQDefaultConfiguration.getDefaultRoutingType())
|
.setRoutingType(ActiveMQDefaultConfiguration.getDefaultRoutingType())
|
||||||
.setAddress(myQueue)
|
.setAddress(myQueue)
|
||||||
.setTemporary(true)
|
.setTemporary(true)
|
||||||
@ -612,7 +612,7 @@ class RPCStabilityTests {
|
|||||||
|
|
||||||
val message = session.createMessage(false)
|
val message = session.createMessage(false)
|
||||||
val request = RPCApi.ClientToServer.RpcRequest(
|
val request = RPCApi.ClientToServer.RpcRequest(
|
||||||
clientAddress = SimpleString(myQueue),
|
clientAddress = SimpleString.of(myQueue),
|
||||||
methodName = DummyOps::protocolVersion.name,
|
methodName = DummyOps::protocolVersion.name,
|
||||||
serialisedArguments = emptyList<Any>().serialize(context = SerializationDefaults.RPC_SERVER_CONTEXT),
|
serialisedArguments = emptyList<Any>().serialize(context = SerializationDefaults.RPC_SERVER_CONTEXT),
|
||||||
replyId = Trace.InvocationId.newInstance(),
|
replyId = Trace.InvocationId.newInstance(),
|
||||||
|
@ -110,11 +110,11 @@ class CordaRPCClientReconnectionTest {
|
|||||||
|
|
||||||
assertThatThrownBy {
|
assertThatThrownBy {
|
||||||
val node = startNode ()
|
val node = startNode ()
|
||||||
val client = CordaRPCClient(node.rpcAddress, config.copy(minimumServerProtocolVersion = 100, maxReconnectAttempts = 1))
|
val client = CordaRPCClient(node.rpcAddress, config.copy(minimumServerProtocolVersion = 999, maxReconnectAttempts = 1))
|
||||||
client.start(rpcUser.username, rpcUser.password, gracefulReconnect = gracefulReconnect)
|
client.start(rpcUser.username, rpcUser.password, gracefulReconnect = gracefulReconnect)
|
||||||
}
|
}
|
||||||
.isInstanceOf(UnrecoverableRPCException::class.java)
|
.isInstanceOf(UnrecoverableRPCException::class.java)
|
||||||
.hasMessageStartingWith("Requested minimum protocol version (100) is higher than the server's supported protocol version ")
|
.hasMessageStartingWith("Requested minimum protocol version (999) is higher than the server's supported protocol version ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,12 @@ import com.github.benmanes.caffeine.cache.LoadingCache
|
|||||||
import net.corda.core.internal.NamedCacheFactory
|
import net.corda.core.internal.NamedCacheFactory
|
||||||
|
|
||||||
class ClientCacheFactory : NamedCacheFactory {
|
class ClientCacheFactory : NamedCacheFactory {
|
||||||
override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
|
override fun <K : Any, V : Any> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
|
||||||
checkCacheName(name)
|
checkCacheName(name)
|
||||||
return caffeine.build<K, V>()
|
return caffeine.build<K, V>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
|
override fun <K : Any, V : Any> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
|
||||||
checkCacheName(name)
|
checkCacheName(name)
|
||||||
return caffeine.build<K, V>(loader)
|
return caffeine.build<K, V>(loader)
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,6 @@ internal class RPCClientProxyHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
|
||||||
private fun closeObservable(observable: UnicastSubject<Notification<*>>) {
|
private fun closeObservable(observable: UnicastSubject<Notification<*>>) {
|
||||||
// Notify listeners of the observables that the connection is being terminated.
|
// Notify listeners of the observables that the connection is being terminated.
|
||||||
try {
|
try {
|
||||||
@ -300,7 +299,7 @@ internal class RPCClientProxyHandler(
|
|||||||
class FailoverHandler(private val detected: () -> Unit = {},
|
class FailoverHandler(private val detected: () -> Unit = {},
|
||||||
private val completed: () -> Unit = {},
|
private val completed: () -> Unit = {},
|
||||||
private val failed: () -> Unit = {}): FailoverEventListener {
|
private val failed: () -> Unit = {}): FailoverEventListener {
|
||||||
override fun failoverEvent(eventType: FailoverEventType?) {
|
override fun failoverEvent(eventType: FailoverEventType) {
|
||||||
when (eventType) {
|
when (eventType) {
|
||||||
FailoverEventType.FAILURE_DETECTED -> { detected() }
|
FailoverEventType.FAILURE_DETECTED -> { detected() }
|
||||||
FailoverEventType.FAILOVER_COMPLETED -> { completed() }
|
FailoverEventType.FAILOVER_COMPLETED -> { completed() }
|
||||||
@ -346,7 +345,7 @@ internal class RPCClientProxyHandler(
|
|||||||
impersonatedActor,
|
impersonatedActor,
|
||||||
rpcClientTelemetry.telemetryService.getCurrentTelemetryData()
|
rpcClientTelemetry.telemetryService.getCurrentTelemetryData()
|
||||||
)
|
)
|
||||||
val replyFuture = SettableFuture.create<Any>()
|
val replyFuture = SettableFuture.create<Any?>()
|
||||||
require(rpcReplyMap.put(replyId, replyFuture) == null) {
|
require(rpcReplyMap.put(replyId, replyFuture) == null) {
|
||||||
"Generated several RPC requests with same ID $replyId"
|
"Generated several RPC requests with same ID $replyId"
|
||||||
}
|
}
|
||||||
@ -589,7 +588,6 @@ internal class RPCClientProxyHandler(
|
|||||||
}
|
}
|
||||||
if (observableIds != null) {
|
if (observableIds != null) {
|
||||||
log.debug { "Reaping ${observableIds.size} observables" }
|
log.debug { "Reaping ${observableIds.size} observables" }
|
||||||
@Suppress("TooGenericExceptionCaught")
|
|
||||||
try {
|
try {
|
||||||
sendMessage(RPCApi.ClientToServer.ObservablesClosed(observableIds))
|
sendMessage(RPCApi.ClientToServer.ObservablesClosed(observableIds))
|
||||||
} catch(ex: Exception) {
|
} catch(ex: Exception) {
|
||||||
@ -654,9 +652,9 @@ internal class RPCClientProxyHandler(
|
|||||||
producerSession = sessionFactory!!.createSession(rpcUsername, rpcPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)
|
producerSession = sessionFactory!!.createSession(rpcUsername, rpcPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)
|
||||||
rpcProducer = producerSession!!.createProducer(RPCApi.RPC_SERVER_QUEUE_NAME)
|
rpcProducer = producerSession!!.createProducer(RPCApi.RPC_SERVER_QUEUE_NAME)
|
||||||
consumerSession = sessionFactory!!.createSession(rpcUsername, rpcPassword, false, true, true, false, 16384)
|
consumerSession = sessionFactory!!.createSession(rpcUsername, rpcPassword, false, true, true, false, 16384)
|
||||||
clientAddress = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.$rpcUsername.${random63BitValue()}")
|
clientAddress = SimpleString.of("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.$rpcUsername.${random63BitValue()}")
|
||||||
log.debug { "Client address: $clientAddress" }
|
log.debug { "Client address: $clientAddress" }
|
||||||
consumerSession!!.createQueue(QueueConfiguration(clientAddress).setAddress(clientAddress).setRoutingType(RoutingType.ANYCAST)
|
consumerSession!!.createQueue(QueueConfiguration.of(clientAddress).setAddress(clientAddress).setRoutingType(RoutingType.ANYCAST)
|
||||||
.setTemporary(true).setDurable(false))
|
.setTemporary(true).setDurable(false))
|
||||||
rpcConsumer = consumerSession!!.createConsumer(clientAddress)
|
rpcConsumer = consumerSession!!.createConsumer(clientAddress)
|
||||||
rpcConsumer!!.setMessageHandler(this::artemisMessageHandler)
|
rpcConsumer!!.setMessageHandler(this::artemisMessageHandler)
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package net.corda.client.rpc.internal
|
package net.corda.client.rpc.internal
|
||||||
|
|
||||||
import net.corda.core.internal.telemetry.OpenTelemetryComponent
|
|
||||||
import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent
|
import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent
|
||||||
import net.corda.core.internal.telemetry.TelemetryServiceImpl
|
import net.corda.core.internal.telemetry.TelemetryServiceImpl
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import net.corda.nodeapi.internal.telemetry.OpenTelemetryComponent
|
||||||
|
|
||||||
class RPCClientTelemetry(val serviceName: String, val openTelemetryEnabled: Boolean,
|
class RPCClientTelemetry(serviceName: String,
|
||||||
val simpleLogTelemetryEnabled: Boolean, val spanStartEndEventsEnabled: Boolean,
|
val openTelemetryEnabled: Boolean,
|
||||||
|
val simpleLogTelemetryEnabled: Boolean,
|
||||||
|
val spanStartEndEventsEnabled: Boolean,
|
||||||
val copyBaggageToTags: Boolean) {
|
val copyBaggageToTags: Boolean) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = contextLogger()
|
private val log = contextLogger()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.corda.java.rpc;
|
package net.corda.java.rpc;
|
||||||
|
|
||||||
import net.corda.client.rpc.CordaRPCConnection;
|
|
||||||
import net.corda.core.contracts.Amount;
|
import net.corda.core.contracts.Amount;
|
||||||
import net.corda.core.identity.CordaX500Name;
|
import net.corda.core.identity.CordaX500Name;
|
||||||
import net.corda.core.identity.Party;
|
import net.corda.core.identity.Party;
|
||||||
@ -10,88 +9,48 @@ import net.corda.core.utilities.OpaqueBytes;
|
|||||||
import net.corda.finance.flows.AbstractCashFlow;
|
import net.corda.finance.flows.AbstractCashFlow;
|
||||||
import net.corda.finance.flows.CashIssueFlow;
|
import net.corda.finance.flows.CashIssueFlow;
|
||||||
import net.corda.nodeapi.internal.config.User;
|
import net.corda.nodeapi.internal.config.User;
|
||||||
import net.corda.smoketesting.NodeConfig;
|
import net.corda.smoketesting.NodeParams;
|
||||||
import net.corda.smoketesting.NodeProcess;
|
import net.corda.smoketesting.NodeProcess;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.Currency;
|
||||||
import java.nio.file.Files;
|
import java.util.HashSet;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static kotlin.test.AssertionsKt.assertEquals;
|
import static kotlin.test.AssertionsKt.assertEquals;
|
||||||
import static kotlin.test.AssertionsKt.fail;
|
|
||||||
import static net.corda.finance.workflows.GetBalances.getCashBalance;
|
import static net.corda.finance.workflows.GetBalances.getCashBalance;
|
||||||
|
import static net.corda.kotlin.rpc.StandaloneCordaRPClientTest.gatherCordapps;
|
||||||
|
|
||||||
public class StandaloneCordaRPCJavaClientTest {
|
public class StandaloneCordaRPCJavaClientTest {
|
||||||
|
private final User superUser = new User("superUser", "test", new HashSet<>(singletonList("ALL")));
|
||||||
|
|
||||||
public static void copyCordapps(NodeProcess.Factory factory, NodeConfig notaryConfig) {
|
private final AtomicInteger port = new AtomicInteger(15000);
|
||||||
Path cordappsDir = (factory.baseDirectory(notaryConfig).resolve(NodeProcess.CORDAPPS_DIR_NAME));
|
private final NodeProcess.Factory factory = new NodeProcess.Factory();
|
||||||
try {
|
|
||||||
Files.createDirectories(cordappsDir);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
fail("Failed to create directories");
|
|
||||||
}
|
|
||||||
try (Stream<Path> paths = Files.walk(Paths.get("build", "resources", "smokeTest"))) {
|
|
||||||
paths.filter(path -> path.toFile().getName().startsWith("cordapp")).forEach(file -> {
|
|
||||||
try {
|
|
||||||
Files.copy(file, cordappsDir.resolve(file.getFileName()));
|
|
||||||
} catch (IOException ex) {
|
|
||||||
fail("Failed to copy cordapp jar");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail("Failed to walk files");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> perms = singletonList("ALL");
|
|
||||||
private Set<String> permSet = new HashSet<>(perms);
|
|
||||||
private User superUser = new User("superUser", "test", permSet);
|
|
||||||
|
|
||||||
private AtomicInteger port = new AtomicInteger(15000);
|
|
||||||
|
|
||||||
private NodeProcess notary;
|
|
||||||
private CordaRPCOps rpcProxy;
|
private CordaRPCOps rpcProxy;
|
||||||
private CordaRPCConnection connection;
|
|
||||||
private Party notaryNodeIdentity;
|
private Party notaryNodeIdentity;
|
||||||
|
|
||||||
private NodeConfig notaryConfig = new NodeConfig(
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
NodeProcess notary = factory.createNotaries(new NodeParams(
|
||||||
new CordaX500Name("Notary Service", "Zurich", "CH"),
|
new CordaX500Name("Notary Service", "Zurich", "CH"),
|
||||||
port.getAndIncrement(),
|
port.getAndIncrement(),
|
||||||
port.getAndIncrement(),
|
port.getAndIncrement(),
|
||||||
port.getAndIncrement(),
|
port.getAndIncrement(),
|
||||||
true,
|
|
||||||
singletonList(superUser),
|
singletonList(superUser),
|
||||||
true
|
gatherCordapps()
|
||||||
);
|
)).get(0);
|
||||||
|
rpcProxy = notary.connect(superUser).getProxy();
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
NodeProcess.Factory factory = new NodeProcess.Factory();
|
|
||||||
copyCordapps(factory, notaryConfig);
|
|
||||||
notary = factory.create(notaryConfig);
|
|
||||||
connection = notary.connect(superUser);
|
|
||||||
rpcProxy = connection.getProxy();
|
|
||||||
notaryNodeIdentity = rpcProxy.nodeInfo().getLegalIdentities().get(0);
|
notaryNodeIdentity = rpcProxy.nodeInfo().getLegalIdentities().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void done() {
|
public void done() {
|
||||||
try {
|
factory.close();
|
||||||
connection.close();
|
|
||||||
} finally {
|
|
||||||
if (notary != null) {
|
|
||||||
notary.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -27,6 +27,7 @@ import net.corda.core.utilities.getOrThrow
|
|||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
|
import net.corda.finance.GBP
|
||||||
import net.corda.finance.POUNDS
|
import net.corda.finance.POUNDS
|
||||||
import net.corda.finance.SWISS_FRANCS
|
import net.corda.finance.SWISS_FRANCS
|
||||||
import net.corda.finance.USD
|
import net.corda.finance.USD
|
||||||
@ -35,89 +36,103 @@ import net.corda.finance.flows.CashIssueFlow
|
|||||||
import net.corda.finance.flows.CashPaymentFlow
|
import net.corda.finance.flows.CashPaymentFlow
|
||||||
import net.corda.finance.workflows.getCashBalance
|
import net.corda.finance.workflows.getCashBalance
|
||||||
import net.corda.finance.workflows.getCashBalances
|
import net.corda.finance.workflows.getCashBalances
|
||||||
import net.corda.java.rpc.StandaloneCordaRPCJavaClientTest
|
|
||||||
import net.corda.nodeapi.internal.config.User
|
import net.corda.nodeapi.internal.config.User
|
||||||
import net.corda.sleeping.SleepingFlow
|
import net.corda.sleeping.SleepingFlow
|
||||||
import net.corda.smoketesting.NodeConfig
|
import net.corda.smoketesting.NodeParams
|
||||||
import net.corda.smoketesting.NodeProcess
|
import net.corda.smoketesting.NodeProcess
|
||||||
import org.apache.commons.io.output.NullOutputStream.NULL_OUTPUT_STREAM
|
|
||||||
import org.hamcrest.text.MatchesPattern
|
import org.hamcrest.text.MatchesPattern
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
import org.junit.AfterClass
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.BeforeClass
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.ExpectedException
|
import org.junit.rules.ExpectedException
|
||||||
import java.io.FilterInputStream
|
import java.io.FilterInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.Currency
|
import java.io.OutputStream.nullOutputStream
|
||||||
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.listDirectoryEntries
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class StandaloneCordaRPClientTest {
|
class StandaloneCordaRPClientTest {
|
||||||
private companion object {
|
companion object {
|
||||||
private val log = contextLogger()
|
private val log = contextLogger()
|
||||||
val superUser = User("superUser", "test", permissions = setOf("ALL"))
|
val superUser = User("superUser", "test", permissions = setOf("ALL"))
|
||||||
val nonUser = User("nonUser", "test", permissions = emptySet())
|
val nonUser = User("nonUser", "test", permissions = emptySet())
|
||||||
val rpcUser = User("rpcUser", "test", permissions = setOf("InvokeRpc.startFlow", "InvokeRpc.killFlow"))
|
val rpcUser = User("rpcUser", "test", permissions = setOf("InvokeRpc.startFlow", "InvokeRpc.killFlow"))
|
||||||
val flowUser = User("flowUser", "test", permissions = setOf("StartFlow.net.corda.finance.flows.CashIssueFlow"))
|
val flowUser = User("flowUser", "test", permissions = setOf("StartFlow.net.corda.finance.flows.CashIssueFlow"))
|
||||||
val port = AtomicInteger(15200)
|
val port = AtomicInteger(15200)
|
||||||
const val attachmentSize = 2116
|
const val ATTACHMENT_SIZE = 2116
|
||||||
val timeout = 60.seconds
|
val timeout = 60.seconds
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var factory: NodeProcess.Factory
|
private val factory = NodeProcess.Factory()
|
||||||
|
|
||||||
private lateinit var notary: NodeProcess
|
private lateinit var notary: NodeProcess
|
||||||
private lateinit var rpcProxy: CordaRPCOps
|
|
||||||
private lateinit var connection: CordaRPCConnection
|
|
||||||
private lateinit var notaryNode: NodeInfo
|
|
||||||
private lateinit var notaryNodeIdentity: Party
|
|
||||||
|
|
||||||
private val notaryConfig = NodeConfig(
|
private val notaryConfig = NodeParams(
|
||||||
legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"),
|
legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"),
|
||||||
p2pPort = port.andIncrement,
|
p2pPort = port.andIncrement,
|
||||||
rpcPort = port.andIncrement,
|
rpcPort = port.andIncrement,
|
||||||
rpcAdminPort = port.andIncrement,
|
rpcAdminPort = port.andIncrement,
|
||||||
isNotary = true,
|
users = listOf(superUser, nonUser, rpcUser, flowUser),
|
||||||
users = listOf(superUser, nonUser, rpcUser, flowUser)
|
cordappJars = gatherCordapps()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun startNotary() {
|
||||||
|
notary = factory.createNotaries(notaryConfig)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
@JvmStatic
|
||||||
|
fun close() {
|
||||||
|
factory.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun gatherCordapps(): List<Path> {
|
||||||
|
return Path("build", "resources", "smokeTest").listDirectoryEntries("cordapp*.jar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var connection: CordaRPCConnection
|
||||||
|
private lateinit var rpcProxy: CordaRPCOps
|
||||||
|
private lateinit var notaryNodeIdentity: Party
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val exception: ExpectedException = ExpectedException.none()
|
val exception: ExpectedException = ExpectedException.none()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
factory = NodeProcess.Factory()
|
|
||||||
StandaloneCordaRPCJavaClientTest.copyCordapps(factory, notaryConfig)
|
|
||||||
notary = factory.create(notaryConfig)
|
|
||||||
connection = notary.connect(superUser)
|
connection = notary.connect(superUser)
|
||||||
rpcProxy = connection.proxy
|
rpcProxy = connection.proxy
|
||||||
notaryNode = fetchNotaryIdentity()
|
|
||||||
notaryNodeIdentity = rpcProxy.nodeInfo().legalIdentitiesAndCerts.first().party
|
notaryNodeIdentity = rpcProxy.nodeInfo().legalIdentitiesAndCerts.first().party
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun done() {
|
fun closeConnection() {
|
||||||
connection.use {
|
connection.close()
|
||||||
notary.close()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `test attachments`() {
|
fun `test attachments`() {
|
||||||
val attachment = InputStreamAndHash.createInMemoryTestZip(attachmentSize, 1)
|
val attachment = InputStreamAndHash.createInMemoryTestZip(ATTACHMENT_SIZE, 1)
|
||||||
assertFalse(rpcProxy.attachmentExists(attachment.sha256))
|
assertFalse(rpcProxy.attachmentExists(attachment.sha256))
|
||||||
val id = attachment.inputStream.use { rpcProxy.uploadAttachment(it) }
|
val id = attachment.inputStream.use { rpcProxy.uploadAttachment(it) }
|
||||||
assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash")
|
assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash")
|
||||||
|
|
||||||
val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it ->
|
val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use {
|
||||||
it.copyTo(NULL_OUTPUT_STREAM)
|
it.copyTo(nullOutputStream())
|
||||||
SecureHash.createSHA256(it.hash().asBytes())
|
SecureHash.createSHA256(it.hash().asBytes())
|
||||||
}
|
}
|
||||||
assertEquals(attachment.sha256, hash)
|
assertEquals(attachment.sha256, hash)
|
||||||
@ -126,13 +141,13 @@ class StandaloneCordaRPClientTest {
|
|||||||
@Ignore("CORDA-1520 - After switching from Kryo to AMQP this test won't work")
|
@Ignore("CORDA-1520 - After switching from Kryo to AMQP this test won't work")
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `test wrapped attachments`() {
|
fun `test wrapped attachments`() {
|
||||||
val attachment = InputStreamAndHash.createInMemoryTestZip(attachmentSize, 1)
|
val attachment = InputStreamAndHash.createInMemoryTestZip(ATTACHMENT_SIZE, 1)
|
||||||
assertFalse(rpcProxy.attachmentExists(attachment.sha256))
|
assertFalse(rpcProxy.attachmentExists(attachment.sha256))
|
||||||
val id = WrapperStream(attachment.inputStream).use { rpcProxy.uploadAttachment(it) }
|
val id = WrapperStream(attachment.inputStream).use { rpcProxy.uploadAttachment(it) }
|
||||||
assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash")
|
assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash")
|
||||||
|
|
||||||
val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it ->
|
val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use {
|
||||||
it.copyTo(NULL_OUTPUT_STREAM)
|
it.copyTo(nullOutputStream())
|
||||||
SecureHash.createSHA256(it.hash().asBytes())
|
SecureHash.createSHA256(it.hash().asBytes())
|
||||||
}
|
}
|
||||||
assertEquals(attachment.sha256, hash)
|
assertEquals(attachment.sha256, hash)
|
||||||
@ -168,8 +183,7 @@ class StandaloneCordaRPClientTest {
|
|||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `test state machines`() {
|
fun `test state machines`() {
|
||||||
val (stateMachines, updates) = rpcProxy.stateMachinesFeed()
|
val (_, updates) = rpcProxy.stateMachinesFeed()
|
||||||
assertEquals(0, stateMachines.size)
|
|
||||||
|
|
||||||
val updateLatch = CountDownLatch(1)
|
val updateLatch = CountDownLatch(1)
|
||||||
val updateCount = AtomicInteger(0)
|
val updateCount = AtomicInteger(0)
|
||||||
@ -190,8 +204,9 @@ class StandaloneCordaRPClientTest {
|
|||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `test vault track by`() {
|
fun `test vault track by`() {
|
||||||
val (vault, vaultUpdates) = rpcProxy.vaultTrackBy<Cash.State>(paging = PageSpecification(DEFAULT_PAGE_NUM))
|
val initialGbpBalance = rpcProxy.getCashBalance(GBP)
|
||||||
assertEquals(0, vault.totalStatesAvailable)
|
|
||||||
|
val (_, vaultUpdates) = rpcProxy.vaultTrackBy<Cash.State>(paging = PageSpecification(DEFAULT_PAGE_NUM))
|
||||||
|
|
||||||
val updateLatch = CountDownLatch(1)
|
val updateLatch = CountDownLatch(1)
|
||||||
vaultUpdates.subscribe { update ->
|
vaultUpdates.subscribe { update ->
|
||||||
@ -207,34 +222,35 @@ class StandaloneCordaRPClientTest {
|
|||||||
// Check that this cash exists in the vault
|
// Check that this cash exists in the vault
|
||||||
val cashBalance = rpcProxy.getCashBalances()
|
val cashBalance = rpcProxy.getCashBalances()
|
||||||
log.info("Cash Balances: $cashBalance")
|
log.info("Cash Balances: $cashBalance")
|
||||||
assertEquals(1, cashBalance.size)
|
assertEquals(629.POUNDS, cashBalance[GBP]!! - initialGbpBalance)
|
||||||
assertEquals(629.POUNDS, cashBalance[Currency.getInstance("GBP")])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `test vault query by`() {
|
fun `test vault query by`() {
|
||||||
// Now issue some cash
|
|
||||||
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNodeIdentity)
|
|
||||||
.returnValue.getOrThrow(timeout)
|
|
||||||
|
|
||||||
val criteria = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL)
|
val criteria = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL)
|
||||||
val paging = PageSpecification(DEFAULT_PAGE_NUM, 10)
|
val paging = PageSpecification(DEFAULT_PAGE_NUM, 10)
|
||||||
val sorting = Sort(setOf(Sort.SortColumn(SortAttribute.Standard(Sort.VaultStateAttribute.RECORDED_TIME), Sort.Direction.DESC)))
|
val sorting = Sort(setOf(Sort.SortColumn(SortAttribute.Standard(Sort.VaultStateAttribute.RECORDED_TIME), Sort.Direction.DESC)))
|
||||||
|
|
||||||
|
val initialStateCount = rpcProxy.vaultQueryBy<Cash.State>(criteria, paging, sorting).totalStatesAvailable
|
||||||
|
val initialGbpBalance = rpcProxy.getCashBalance(GBP)
|
||||||
|
|
||||||
|
// Now issue some cash
|
||||||
|
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNodeIdentity)
|
||||||
|
.returnValue.getOrThrow(timeout)
|
||||||
|
|
||||||
val queryResults = rpcProxy.vaultQueryBy<Cash.State>(criteria, paging, sorting)
|
val queryResults = rpcProxy.vaultQueryBy<Cash.State>(criteria, paging, sorting)
|
||||||
assertEquals(1, queryResults.totalStatesAvailable)
|
assertEquals(1, queryResults.totalStatesAvailable - initialStateCount)
|
||||||
assertEquals(queryResults.states.first().state.data.amount.quantity, 629.POUNDS.quantity)
|
assertEquals(queryResults.states.first().state.data.amount.quantity, 629.POUNDS.quantity)
|
||||||
|
|
||||||
rpcProxy.startFlow(::CashPaymentFlow, 100.POUNDS, notaryNodeIdentity, true, notaryNodeIdentity).returnValue.getOrThrow()
|
rpcProxy.startFlow(::CashPaymentFlow, 100.POUNDS, notaryNodeIdentity, true, notaryNodeIdentity).returnValue.getOrThrow()
|
||||||
|
|
||||||
val moreResults = rpcProxy.vaultQueryBy<Cash.State>(criteria, paging, sorting)
|
val moreResults = rpcProxy.vaultQueryBy<Cash.State>(criteria, paging, sorting)
|
||||||
assertEquals(3, moreResults.totalStatesAvailable) // 629 - 100 + 100
|
assertEquals(3, moreResults.totalStatesAvailable - initialStateCount) // 629 - 100 + 100
|
||||||
|
|
||||||
// Check that this cash exists in the vault
|
// Check that this cash exists in the vault
|
||||||
val cashBalances = rpcProxy.getCashBalances()
|
val cashBalances = rpcProxy.getCashBalances()
|
||||||
log.info("Cash Balances: $cashBalances")
|
log.info("Cash Balances: $cashBalances")
|
||||||
assertEquals(1, cashBalances.size)
|
assertEquals(629.POUNDS, cashBalances[GBP]!! - initialGbpBalance)
|
||||||
assertEquals(629.POUNDS, cashBalances[Currency.getInstance("GBP")])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.client.rpc
|
|||||||
|
|
||||||
import net.corda.core.internal.uncheckedCast
|
import net.corda.core.internal.uncheckedCast
|
||||||
import kotlin.reflect.KCallable
|
import kotlin.reflect.KCallable
|
||||||
|
import kotlin.reflect.jvm.ExperimentalReflectionOnLambdas
|
||||||
import kotlin.reflect.jvm.reflect
|
import kotlin.reflect.jvm.reflect
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,15 +11,19 @@ import kotlin.reflect.jvm.reflect
|
|||||||
* different combinations of parameters.
|
* different combinations of parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@OptIn(ExperimentalReflectionOnLambdas::class)
|
||||||
fun <A : Any, R> measure(a: Iterable<A>, f: (A) -> R) =
|
fun <A : Any, R> measure(a: Iterable<A>, f: (A) -> R) =
|
||||||
measure(listOf(a), f.reflect()!!) { f(uncheckedCast(it[0])) }
|
measure(listOf(a), f.reflect()!!) { f(uncheckedCast(it[0])) }
|
||||||
|
|
||||||
|
@OptIn(ExperimentalReflectionOnLambdas::class)
|
||||||
fun <A : Any, B : Any, R> measure(a: Iterable<A>, b: Iterable<B>, f: (A, B) -> R) =
|
fun <A : Any, B : Any, R> measure(a: Iterable<A>, b: Iterable<B>, f: (A, B) -> R) =
|
||||||
measure(listOf(a, b), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1])) }
|
measure(listOf(a, b), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1])) }
|
||||||
|
|
||||||
|
@OptIn(ExperimentalReflectionOnLambdas::class)
|
||||||
fun <A : Any, B : Any, C : Any, R> measure(a: Iterable<A>, b: Iterable<B>, c: Iterable<C>, f: (A, B, C) -> R) =
|
fun <A : Any, B : Any, C : Any, R> measure(a: Iterable<A>, b: Iterable<B>, c: Iterable<C>, f: (A, B, C) -> R) =
|
||||||
measure(listOf(a, b, c), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2])) }
|
measure(listOf(a, b, c), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2])) }
|
||||||
|
|
||||||
|
@OptIn(ExperimentalReflectionOnLambdas::class)
|
||||||
fun <A : Any, B : Any, C : Any, D : Any, R> measure(a: Iterable<A>, b: Iterable<B>, c: Iterable<C>, d: Iterable<D>, f: (A, B, C, D) -> R) =
|
fun <A : Any, B : Any, C : Any, D : Any, R> measure(a: Iterable<A>, b: Iterable<B>, c: Iterable<C>, d: Iterable<D>, f: (A, B, C, D) -> R) =
|
||||||
measure(listOf(a, b, c, d), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2]), uncheckedCast(it[3])) }
|
measure(listOf(a, b, c, d), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2]), uncheckedCast(it[3])) }
|
||||||
|
|
||||||
|
@ -49,14 +49,14 @@ class RPCFailureTests {
|
|||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `kotlin NPE`() = rpc {
|
fun `kotlin NPE`() = rpc {
|
||||||
assertThatThrownBy { it.kotlinNPE() }.isInstanceOf(CordaRuntimeException::class.java)
|
assertThatThrownBy { it.kotlinNPE() }.isInstanceOf(CordaRuntimeException::class.java)
|
||||||
.hasMessageContaining("kotlin.KotlinNullPointerException")
|
.hasMessageContaining("java.lang.NullPointerException")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `kotlin NPE async`() = rpc {
|
fun `kotlin NPE async`() = rpc {
|
||||||
val future = it.kotlinNPEAsync()
|
val future = it.kotlinNPEAsync()
|
||||||
assertThatThrownBy { future.getOrThrow() }.isInstanceOf(CordaRuntimeException::class.java)
|
assertThatThrownBy { future.getOrThrow() }.isInstanceOf(CordaRuntimeException::class.java)
|
||||||
.hasMessageContaining("kotlin.KotlinNullPointerException")
|
.hasMessageContaining("java.lang.NullPointerException")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
|
apply plugin: 'corda.common-publishing'
|
||||||
|
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
description 'Corda common-configuration-parsing module'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: kotlin_version
|
implementation group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version
|
||||||
compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version
|
|
||||||
|
|
||||||
compile group: "com.typesafe", name: "config", version: typesafe_config_version
|
implementation group: "com.typesafe", name: "config", version: typesafe_config_version
|
||||||
|
|
||||||
compile project(":common-validation")
|
implementation project(":common-validation")
|
||||||
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
@ -18,14 +17,20 @@ dependencies {
|
|||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
testCompile group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version
|
testImplementation group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version
|
||||||
testCompile group: "org.assertj", name: "assertj-core", version: assertj_version
|
testImplementation group: "org.assertj", name: "assertj-core", version: assertj_version
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
baseName 'corda-common-configuration-parsing'
|
baseName 'corda-common-configuration-parsing'
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.common.configuration.parsing.internal.versioned.VersionExtracto
|
|||||||
import net.corda.common.validation.internal.Validated
|
import net.corda.common.validation.internal.Validated
|
||||||
import net.corda.common.validation.internal.Validated.Companion.invalid
|
import net.corda.common.validation.internal.Validated.Companion.invalid
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.util.Locale
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -468,7 +469,7 @@ object Configuration {
|
|||||||
|
|
||||||
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): WrongType = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> WrongType(key, typeName, message, path) }
|
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): WrongType = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> WrongType(key, typeName, message, path) }
|
||||||
|
|
||||||
fun forKey(keyName: String, expectedTypeName: String, actualTypeName: String): WrongType = of("$keyName has type ${actualTypeName.toUpperCase()} rather than ${expectedTypeName.toUpperCase()}")
|
fun forKey(keyName: String, expectedTypeName: String, actualTypeName: String): WrongType = of("$keyName has type ${actualTypeName.uppercase(Locale.getDefault())} rather than ${expectedTypeName.uppercase(Locale.getDefault())}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun withContainingPath(vararg containingPath: String) = WrongType(keyName, typeName, message, containingPath.toList())
|
override fun withContainingPath(vararg containingPath: String) = WrongType(keyName, typeName, message, containingPath.toList())
|
||||||
|
@ -61,7 +61,7 @@ class SpecificationTest {
|
|||||||
|
|
||||||
override fun parseValid(configuration: Config, options: Configuration.Options): Valid<AtomicLong> {
|
override fun parseValid(configuration: Config, options: Configuration.Options): Valid<AtomicLong> {
|
||||||
val config = configuration.withOptions(options)
|
val config = configuration.withOptions(options)
|
||||||
return valid(AtomicLong(config[maxElement]!!))
|
return valid(AtomicLong(config[maxElement]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class SpecificationTest {
|
|||||||
if (elements.any { element -> element <= 1 }) {
|
if (elements.any { element -> element <= 1 }) {
|
||||||
return invalid(Configuration.Validation.Error.BadValue.of("elements cannot be less than or equal to 1"))
|
return invalid(Configuration.Validation.Error.BadValue.of("elements cannot be less than or equal to 1"))
|
||||||
}
|
}
|
||||||
return valid(elements.max()!!)
|
return valid(elements.max())
|
||||||
}
|
}
|
||||||
|
|
||||||
val spec = object : Configuration.Specification<AtomicLong>("AtomicLong") {
|
val spec = object : Configuration.Specification<AtomicLong>("AtomicLong") {
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
import org.apache.tools.ant.filters.ReplaceTokens
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
apply plugin: 'corda.common-publishing'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
|
||||||
|
description 'Corda common-logging module'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: kotlin_version
|
implementation group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version
|
||||||
compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version
|
|
||||||
|
|
||||||
compile group: "com.typesafe", name: "config", version: typesafe_config_version
|
implementation group: "com.typesafe", name: "config", version: typesafe_config_version
|
||||||
|
|
||||||
// Log4J: logging framework
|
// Log4J: logging framework
|
||||||
compile "org.apache.logging.log4j:log4j-core:$log4j_version"
|
implementation "org.apache.logging.log4j:log4j-core:$log4j_version"
|
||||||
|
|
||||||
compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version"
|
implementation "com.jcabi:jcabi-manifests:$jcabi_manifests_version"
|
||||||
|
|
||||||
// Need to depend on one other Corda project in order to get hold of a valid manifest for the tests
|
// Need to depend on one other Corda project in order to get hold of a valid manifest for the tests
|
||||||
testCompile project(":common-validation")
|
testImplementation project(":common-validation")
|
||||||
|
|
||||||
// test dependencies
|
// test dependencies
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testCompile group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version
|
testImplementation group: "org.jetbrains.kotlin", name: "kotlin-test", version: kotlin_version
|
||||||
testCompile "org.mockito:mockito-core:$mockito_version"
|
testImplementation "org.mockito:mockito-core:$mockito_version"
|
||||||
testCompile "com.natpryce:hamkrest:$hamkrest_version"
|
testImplementation "com.natpryce:hamkrest:$hamkrest_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -33,11 +33,19 @@ task generateSource(type: Copy) {
|
|||||||
into 'src/main'
|
into 'src/main'
|
||||||
}
|
}
|
||||||
compileKotlin.dependsOn generateSource
|
compileKotlin.dependsOn generateSource
|
||||||
|
processResources.dependsOn generateSource
|
||||||
|
sourcesJar.dependsOn generateSource
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
baseName 'corda-common-logging'
|
baseName 'corda-common-logging'
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -9,4 +9,4 @@ package net.corda.common.logging
|
|||||||
* (originally added to source control for ease of use)
|
* (originally added to source control for ease of use)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
internal const val CURRENT_MAJOR_RELEASE = "4.11-SNAPSHOT"
|
internal const val CURRENT_MAJOR_RELEASE = "4.12-SNAPSHOT"
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.common.logging.errorReporting
|
package net.corda.common.logging.errorReporting
|
||||||
|
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report errors that have occurred.
|
* Report errors that have occurred.
|
||||||
@ -12,7 +13,7 @@ import org.slf4j.Logger
|
|||||||
fun Logger.report(error: ErrorCode<*>) = ErrorReporting().getReporter().report(error, this)
|
fun Logger.report(error: ErrorCode<*>) = ErrorReporting().getReporter().report(error, this)
|
||||||
|
|
||||||
internal fun ErrorCode<*>.formatCode() : String {
|
internal fun ErrorCode<*>.formatCode() : String {
|
||||||
val namespaceString = this.code.namespace.toLowerCase().replace("_", "-")
|
val namespaceString = this.code.namespace.lowercase(Locale.getDefault()).replace("_", "-")
|
||||||
val codeString = this.code.toString().toLowerCase().replace("_", "-")
|
val codeString = this.code.toString().lowercase(Locale.getDefault()).replace("_", "-")
|
||||||
return "$namespaceString-$codeString"
|
return "$namespaceString-$codeString"
|
||||||
}
|
}
|
@ -1,17 +1,21 @@
|
|||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
|
apply plugin: 'corda.common-publishing'
|
||||||
|
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
description 'Corda common-validation module'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
baseName 'corda-common-validation'
|
baseName 'corda-common-validation'
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publishing {
|
||||||
name jar.baseName
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId jar.baseName
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,18 +1,24 @@
|
|||||||
// This contains the SwapIdentitiesFlow which can be used for exchanging confidential identities as part of a flow.
|
// This contains the SwapIdentitiesFlow which can be used for exchanging confidential identities as part of a flow.
|
||||||
// TODO: Merge this into core: the original plan was to develop it independently but in practice it's too widely used to break compatibility now, as finance uses it.
|
// TODO: Merge this into core: the original plan was to develop it independently but in practice it's too widely used to break compatibility now, as finance uses it.
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
apply plugin: 'net.corda.plugins.cordapp'
|
apply plugin: 'net.corda.plugins.cordapp'
|
||||||
apply plugin: 'com.jfrog.artifactory'
|
apply plugin: 'corda.common-publishing'
|
||||||
|
|
||||||
description 'Corda Experimental Confidential Identities'
|
description 'Corda Experimental Confidential Identities'
|
||||||
|
|
||||||
dependencies {
|
cordapp {
|
||||||
cordaCompile project(':core')
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
|
}
|
||||||
|
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
dependencies {
|
||||||
|
cordaProvided project(':core')
|
||||||
|
|
||||||
|
api "org.slf4j:slf4j-api:$slf4j_version"
|
||||||
|
|
||||||
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
|
testImplementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
|
|
||||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||||
@ -20,19 +26,28 @@ dependencies {
|
|||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
// Guava: Google test library (collections test suite)
|
// Guava: Google test library (collections test suite)
|
||||||
testCompile "com.google.guava:guava-testlib:$guava_version"
|
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
||||||
|
|
||||||
// Bring in the MockNode infrastructure for writing protocol unit tests.
|
// Bring in the MockNode infrastructure for writing protocol unit tests.
|
||||||
testCompile project(":node-driver")
|
testImplementation project(":node")
|
||||||
|
testImplementation project(":node-api")
|
||||||
|
testImplementation project(":node-driver")
|
||||||
|
testImplementation project(":core-test-utils")
|
||||||
|
testImplementation project(':finance:contracts')
|
||||||
|
testImplementation project(':finance:workflows')
|
||||||
|
|
||||||
// AssertJ: for fluent assertions for testing
|
// AssertJ: for fluent assertions for testing
|
||||||
testCompile "org.assertj:assertj-core:$assertj_version"
|
testImplementation "org.assertj:assertj-core:$assertj_version"
|
||||||
|
testImplementation "com.natpryce:hamkrest:$hamkrest_version"
|
||||||
|
testImplementation "io.reactivex:rxjava:$rxjava_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
publishing {
|
||||||
baseName 'corda-confidential-identities'
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId 'corda-confidential-identities'
|
||||||
|
from components.cordapp
|
||||||
|
artifact javadocJar
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
|
||||||
name jar.baseName
|
|
||||||
}
|
}
|
||||||
|
@ -2,64 +2,26 @@
|
|||||||
<Configuration status="info" shutdownHook="disable">
|
<Configuration status="info" shutdownHook="disable">
|
||||||
|
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="log-path">${sys:log-path:-logs}</Property>
|
<Property name="log_path">${sys:log-path:-logs}</Property>
|
||||||
<Property name="log-name">node-${hostName}</Property>
|
<Property name="log_name">node-${hostName}</Property>
|
||||||
<Property name="diagnostic-log-name">diagnostic-${hostName}</Property>
|
<Property name="diagnostic_log_name">diagnostic-${hostName}</Property>
|
||||||
<Property name="archive">${log-path}/archive</Property>
|
<Property name="archive">${log_path}/archive</Property>
|
||||||
<Property name="defaultLogLevel">${sys:defaultLogLevel:-info}</Property>
|
<Property name="default_log_level">${sys:defaultLogLevel:-info}</Property>
|
||||||
<Property name="consoleLogLevel">${sys:consoleLogLevel:-error}</Property>
|
<Property name="console_log_level">${sys:consoleLogLevel:-error}</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
<Appenders>
|
<Appenders>
|
||||||
<ScriptAppenderSelector name="Console-Selector">
|
|
||||||
<Script language="nashorn"><![CDATA[
|
|
||||||
var System = Java.type('java.lang.System');
|
|
||||||
var level = System.getProperty("consoleLogLevel");
|
|
||||||
var enabled = System.getProperty("consoleLoggingEnabled");
|
|
||||||
enabled == "true" && (level == "debug" || level == "trace") ? "Console-Debug-Appender" : "Console-Appender";
|
|
||||||
]]></Script>
|
|
||||||
<AppenderSet>
|
|
||||||
|
|
||||||
<!-- The default console appender - prints no exception information -->
|
<!-- The default console appender - prints no exception information -->
|
||||||
<Console name="Console-Appender" target="SYSTEM_OUT">
|
<Console name="Console-Appender" target="SYSTEM_OUT">
|
||||||
<PatternLayout>
|
<PatternLayout
|
||||||
<ScriptPatternSelector
|
pattern="%highlight{[%level{length=5}] %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg%n%throwable{0}}{INFO=white,WARN=red,FATAL=bright red}"/>
|
||||||
defaultPattern="%highlight{[%level{length=5}] %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg%n%throwable{0}}{INFO=white,WARN=red,FATAL=bright red}">
|
|
||||||
<Script name="MDCSelector" language="javascript"><![CDATA[
|
|
||||||
result = null;
|
|
||||||
if (!logEvent.getContextData().size() == 0) {
|
|
||||||
result = "WithMDC";
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
result;
|
|
||||||
]]>
|
|
||||||
</Script>
|
|
||||||
<PatternMatch key="WithMDC" pattern="%highlight{[%level{length=5}] %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg %X%n%throwable{0}}{INFO=white,WARN=red,FATAL=bright red}"/>
|
|
||||||
</ScriptPatternSelector>
|
|
||||||
</PatternLayout>
|
|
||||||
</Console>
|
</Console>
|
||||||
|
|
||||||
<!-- The console appender when debug or trace level logging is specified. Prints full stack trace -->
|
<!-- The console appender when debug or trace level logging is specified. Prints full stack trace -->
|
||||||
<Console name="Console-Debug-Appender" target="SYSTEM_OUT">
|
<Console name="Console-Debug-Appender" target="SYSTEM_OUT">
|
||||||
<PatternLayout>
|
<PatternLayout
|
||||||
<ScriptPatternSelector defaultPattern="%highlight{[%level{length=5}] %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg%n%throwable{}}{INFO=white,WARN=red,FATAL=bright red}">
|
pattern="%highlight{[%level{length=5}] %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg%n%throwable{}}{INFO=white,WARN=red,FATAL=bright red}"/>
|
||||||
<Script name="MDCSelector" language="javascript"><![CDATA[
|
|
||||||
result = null;
|
|
||||||
if (!logEvent.getContextData().size() == 0) {
|
|
||||||
result = "WithMDC";
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
result;
|
|
||||||
]]>
|
|
||||||
</Script>
|
|
||||||
<PatternMatch key="WithMDC" pattern="%highlight{[%level{length=5}] %date{HH:mm:ssZ} [%t] %c{2}.%method - %msg %X%n%throwable{}}{INFO=white,WARN=red,FATAL=bright red}"/>
|
|
||||||
</ScriptPatternSelector>
|
|
||||||
</PatternLayout>
|
|
||||||
</Console>
|
</Console>
|
||||||
</AppenderSet>
|
|
||||||
</ScriptAppenderSelector>
|
|
||||||
|
|
||||||
<!-- Required for printBasicInfo -->
|
<!-- Required for printBasicInfo -->
|
||||||
<Console name="Console-Appender-Println" target="SYSTEM_OUT">
|
<Console name="Console-Appender-Println" target="SYSTEM_OUT">
|
||||||
@ -69,24 +31,10 @@
|
|||||||
<!-- Will generate up to 500 log files for a given day. Adjust this number according to the available storage.
|
<!-- Will generate up to 500 log files for a given day. Adjust this number according to the available storage.
|
||||||
During every rollover it will delete those that are older than 60 days, but keep the most recent 10 GB -->
|
During every rollover it will delete those that are older than 60 days, but keep the most recent 10 GB -->
|
||||||
<RollingRandomAccessFile name="RollingFile-Appender"
|
<RollingRandomAccessFile name="RollingFile-Appender"
|
||||||
fileName="${log-path}/${log-name}.log"
|
fileName="${log_path}/${log_name}.log"
|
||||||
filePattern="${archive}/${log-name}.%date{yyyy-MM-dd}-%i.log.gz">
|
filePattern="${archive}/${log_name}.%date{yyyy-MM-dd}-%i.log.gz">
|
||||||
|
|
||||||
<PatternLayout>
|
<PatternLayout pattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg%n"/>
|
||||||
<ScriptPatternSelector defaultPattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg%n">
|
|
||||||
<Script name="MDCSelector" language="javascript"><![CDATA[
|
|
||||||
result = null;
|
|
||||||
if (!logEvent.getContextData().size() == 0) {
|
|
||||||
result = "WithMDC";
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
result;
|
|
||||||
]]>
|
|
||||||
</Script>
|
|
||||||
<PatternMatch key="WithMDC" pattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg %X%n"/>
|
|
||||||
</ScriptPatternSelector>
|
|
||||||
</PatternLayout>
|
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<TimeBasedTriggeringPolicy/>
|
<TimeBasedTriggeringPolicy/>
|
||||||
@ -95,7 +43,7 @@
|
|||||||
|
|
||||||
<DefaultRolloverStrategy min="1" max="500">
|
<DefaultRolloverStrategy min="1" max="500">
|
||||||
<Delete basePath="${archive}" maxDepth="1">
|
<Delete basePath="${archive}" maxDepth="1">
|
||||||
<IfFileName glob="${log-name}*.log.gz"/>
|
<IfFileName glob="${log_name}*.log.gz"/>
|
||||||
<IfLastModified age="60d">
|
<IfLastModified age="60d">
|
||||||
<IfAny>
|
<IfAny>
|
||||||
<IfAccumulatedFileSize exceeds="10 GB"/>
|
<IfAccumulatedFileSize exceeds="10 GB"/>
|
||||||
@ -109,24 +57,10 @@
|
|||||||
<!-- Will generate up to 100 log files for a given day. During every rollover it will delete
|
<!-- Will generate up to 100 log files for a given day. During every rollover it will delete
|
||||||
those that are older than 60 days, but keep the most recent 10 GB -->
|
those that are older than 60 days, but keep the most recent 10 GB -->
|
||||||
<RollingRandomAccessFile name="Diagnostic-RollingFile-Appender"
|
<RollingRandomAccessFile name="Diagnostic-RollingFile-Appender"
|
||||||
fileName="${log-path}/${diagnostic-log-name}.log"
|
fileName="${log_path}/${diagnostic_log_name}.log"
|
||||||
filePattern="${archive}/${diagnostic-log-name}.%date{yyyy-MM-dd}-%i.log.gz">
|
filePattern="${archive}/${diagnostic_log_name}.%date{yyyy-MM-dd}-%i.log.gz">
|
||||||
|
|
||||||
<PatternLayout>
|
<PatternLayout pattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg%n"/>
|
||||||
<ScriptPatternSelector defaultPattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg%n">
|
|
||||||
<Script name="MDCSelector" language="javascript"><![CDATA[
|
|
||||||
result = null;
|
|
||||||
if (!logEvent.getContextData().size() == 0) {
|
|
||||||
result = "WithMDC";
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
result;
|
|
||||||
]]>
|
|
||||||
</Script>
|
|
||||||
<PatternMatch key="WithMDC" pattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg %X%n"/>
|
|
||||||
</ScriptPatternSelector>
|
|
||||||
</PatternLayout>
|
|
||||||
|
|
||||||
<Policies>
|
<Policies>
|
||||||
<TimeBasedTriggeringPolicy/>
|
<TimeBasedTriggeringPolicy/>
|
||||||
@ -135,7 +69,7 @@
|
|||||||
|
|
||||||
<DefaultRolloverStrategy min="1" max="100">
|
<DefaultRolloverStrategy min="1" max="100">
|
||||||
<Delete basePath="${archive}" maxDepth="1">
|
<Delete basePath="${archive}" maxDepth="1">
|
||||||
<IfFileName glob="${diagnostic-log-name}*.log.gz"/>
|
<IfFileName glob="${diagnostic_log_name}*.log.gz"/>
|
||||||
<IfLastModified age="60d">
|
<IfLastModified age="60d">
|
||||||
<IfAny>
|
<IfAny>
|
||||||
<IfAccumulatedFileSize exceeds="10 GB"/>
|
<IfAccumulatedFileSize exceeds="10 GB"/>
|
||||||
@ -147,7 +81,7 @@
|
|||||||
</RollingRandomAccessFile>
|
</RollingRandomAccessFile>
|
||||||
|
|
||||||
<RollingFile name="Checkpoint-Agent-RollingFile-Appender"
|
<RollingFile name="Checkpoint-Agent-RollingFile-Appender"
|
||||||
fileName="${log-path}/checkpoints_agent-${date:yyyyMMdd-HHmmss}.log"
|
fileName="${log_path}/checkpoints_agent-${date:yyyyMMdd-HHmmss}.log"
|
||||||
filePattern="${archive}/checkpoints_agent.%date{yyyy-MM-dd}-%i.log.gz">
|
filePattern="${archive}/checkpoints_agent.%date{yyyy-MM-dd}-%i.log.gz">
|
||||||
|
|
||||||
<PatternLayout pattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg%n"/>
|
<PatternLayout pattern="[%-5level] %date{ISO8601}{UTC}Z [%t] %c{2}.%method - %msg%n"/>
|
||||||
@ -171,7 +105,7 @@
|
|||||||
</RollingFile>
|
</RollingFile>
|
||||||
|
|
||||||
<Rewrite name="Console-ErrorCode-Selector">
|
<Rewrite name="Console-ErrorCode-Selector">
|
||||||
<AppenderRef ref="Console-Selector"/>
|
<AppenderRef ref="Console-Appender"/>
|
||||||
</Rewrite>
|
</Rewrite>
|
||||||
|
|
||||||
<Rewrite name="Console-ErrorCode-Appender-Println">
|
<Rewrite name="Console-ErrorCode-Appender-Println">
|
||||||
@ -187,8 +121,8 @@
|
|||||||
</Appenders>
|
</Appenders>
|
||||||
|
|
||||||
<Loggers>
|
<Loggers>
|
||||||
<Root level="${defaultLogLevel}">
|
<Root level="${default_log_level}">
|
||||||
<AppenderRef ref="Console-ErrorCode-Selector" level="${consoleLogLevel}"/>
|
<AppenderRef ref="Console-ErrorCode-Selector" level="${console_log_level}"/>
|
||||||
<AppenderRef ref="RollingFile-ErrorCode-Appender"/>
|
<AppenderRef ref="RollingFile-ErrorCode-Appender"/>
|
||||||
</Root>
|
</Root>
|
||||||
<Logger name="BasicInfo" additivity="false">
|
<Logger name="BasicInfo" additivity="false">
|
||||||
|
@ -3,35 +3,32 @@
|
|||||||
# their own projects. So don't get fancy with syntax!
|
# their own projects. So don't get fancy with syntax!
|
||||||
# Fancy syntax - multi pass ${whatever} replacement
|
# Fancy syntax - multi pass ${whatever} replacement
|
||||||
|
|
||||||
cordaVersion=4.11
|
cordaVersion=4.12
|
||||||
versionSuffix=SNAPSHOT
|
versionSuffix=SNAPSHOT
|
||||||
gradlePluginsVersion=5.0.12
|
cordaShellVersion=4.12-SNAPSHOT
|
||||||
kotlinVersion=1.2.71
|
gradlePluginsVersion=5.1.1
|
||||||
java8MinUpdateVersion=171
|
artifactoryContextUrl=https://software.r3.com/artifactory
|
||||||
|
internalPublishVersion=1.+
|
||||||
# ***************************************************************#
|
# ***************************************************************#
|
||||||
# When incrementing platformVersion make sure to update #
|
# When incrementing platformVersion make sure to update #
|
||||||
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
|
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
|
||||||
# ***************************************************************#
|
# ***************************************************************#
|
||||||
platformVersion=13
|
platformVersion=140
|
||||||
openTelemetryVersion=1.20.1
|
openTelemetryVersion=1.20.1
|
||||||
openTelemetrySemConvVersion=1.20.1-alpha
|
openTelemetrySemConvVersion=1.20.1-alpha
|
||||||
guavaVersion=28.0-jre
|
guavaVersion=33.1.0-jre
|
||||||
# Quasar version to use with Java 8:
|
quasarVersion=0.9.0_r3
|
||||||
quasarVersion=0.7.16_r3
|
|
||||||
# Quasar version to use with Java 11:
|
|
||||||
quasarVersion11=0.8.1_r3
|
|
||||||
jdkClassifier11=jdk11
|
|
||||||
dockerJavaVersion=3.2.5
|
dockerJavaVersion=3.2.5
|
||||||
proguardVersion=6.1.1
|
proguardVersion=7.3.1
|
||||||
// bouncy castle version must not be changed on a patch release. Needs a full release test cycle to flush out any issues.
|
# Switch to release version when out
|
||||||
bouncycastleVersion=1.78.1
|
bouncycastleVersion=2.73.6
|
||||||
classgraphVersion=4.8.135
|
classgraphVersion=4.8.135
|
||||||
disruptorVersion=3.4.2
|
disruptorVersion=3.4.2
|
||||||
typesafeConfigVersion=1.3.4
|
typesafeConfigVersion=1.3.4
|
||||||
jsr305Version=3.0.2
|
jsr305Version=3.0.2
|
||||||
artifactoryPluginVersion=4.16.1
|
artifactoryPluginVersion=4.16.1
|
||||||
snakeYamlVersion=1.33
|
snakeYamlVersion=2.2
|
||||||
caffeineVersion=2.9.3
|
caffeineVersion=3.1.8
|
||||||
metricsVersion=4.1.0
|
metricsVersion=4.1.0
|
||||||
metricsNewRelicVersion=1.1.1
|
metricsNewRelicVersion=1.1.1
|
||||||
openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4
|
openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4
|
||||||
@ -46,22 +43,22 @@ commonsTextVersion=1.10.0
|
|||||||
|
|
||||||
# gradle-capsule-plugin:1.0.2 contains capsule:1.0.1 by default.
|
# gradle-capsule-plugin:1.0.2 contains capsule:1.0.1 by default.
|
||||||
# We must configure it manually to use the latest capsule version.
|
# We must configure it manually to use the latest capsule version.
|
||||||
capsuleVersion=1.0.3
|
capsuleVersion=1.0.4_r3
|
||||||
asmVersion=7.1
|
asmVersion=9.5
|
||||||
artemisVersion=2.19.1
|
artemisVersion=2.36.0
|
||||||
# TODO Upgrade Jackson only when corda is using kotlin 1.3.10
|
# TODO Upgrade Jackson only when corda is using kotlin 1.3.10
|
||||||
jacksonVersion=2.17.2
|
jacksonVersion=2.17.2
|
||||||
jacksonKotlinVersion=2.9.7
|
jacksonKotlinVersion=2.17.0
|
||||||
jettyVersion=9.4.56.v20240826
|
jettyVersion=12.0.14
|
||||||
jerseyVersion=2.25
|
jerseyVersion=3.1.6
|
||||||
servletVersion=4.0.1
|
servletVersion=4.0.1
|
||||||
assertjVersion=3.12.2
|
assertjVersion=3.12.2
|
||||||
slf4JVersion=1.7.30
|
slf4JVersion=2.0.12
|
||||||
log4JVersion=2.17.1
|
log4JVersion=2.23.1
|
||||||
okhttpVersion=3.14.9
|
okhttpVersion=4.12.0
|
||||||
nettyVersion=4.1.77.Final
|
nettyVersion=4.1.109.Final
|
||||||
fileuploadVersion=1.4
|
fileuploadVersion=2.0.0-M1
|
||||||
kryoVersion=4.0.2
|
kryoVersion=5.5.0
|
||||||
kryoSerializerVersion=0.43
|
kryoSerializerVersion=0.43
|
||||||
# Legacy JUnit 4 version
|
# Legacy JUnit 4 version
|
||||||
junitVersion=4.12
|
junitVersion=4.12
|
||||||
@ -71,8 +68,8 @@ junitVersion=4.12
|
|||||||
junitVintageVersion=5.5.0-RC1
|
junitVintageVersion=5.5.0-RC1
|
||||||
junitJupiterVersion=5.5.0-RC1
|
junitJupiterVersion=5.5.0-RC1
|
||||||
junitPlatformVersion=1.5.0-RC1
|
junitPlatformVersion=1.5.0-RC1
|
||||||
mockitoVersion=2.28.2
|
mockitoVersion=5.5.0
|
||||||
mockitoKotlinVersion=1.6.0
|
mockitoKotlinVersion=5.2.1
|
||||||
hamkrestVersion=1.7.0.0
|
hamkrestVersion=1.7.0.0
|
||||||
joptSimpleVersion=5.0.2
|
joptSimpleVersion=5.0.2
|
||||||
jansiVersion=1.18
|
jansiVersion=1.18
|
||||||
@ -80,13 +77,12 @@ hibernateVersion=5.6.14.Final
|
|||||||
# h2Version - Update docs if renamed or removed.
|
# h2Version - Update docs if renamed or removed.
|
||||||
h2Version=2.2.224
|
h2Version=2.2.224
|
||||||
rxjavaVersion=1.3.8
|
rxjavaVersion=1.3.8
|
||||||
dokkaVersion=0.10.1
|
dokkaVersion=1.8.20
|
||||||
eddsaVersion=0.3.0
|
|
||||||
dependencyCheckerVersion=5.2.0
|
dependencyCheckerVersion=5.2.0
|
||||||
commonsCollectionsVersion=4.3
|
commonsCollectionsVersion=4.3
|
||||||
beanutilsVersion=1.9.4
|
beanutilsVersion=1.9.4
|
||||||
shiroVersion=1.10.0
|
shiroVersion=1.10.0
|
||||||
hikariVersion=4.0.3
|
hikariVersion=5.1.0
|
||||||
liquibaseVersion=4.20.0
|
liquibaseVersion=4.20.0
|
||||||
dockerComposeRuleVersion=1.5.0
|
dockerComposeRuleVersion=1.5.0
|
||||||
seleniumVersion=3.141.59
|
seleniumVersion=3.141.59
|
||||||
@ -97,13 +93,9 @@ protonjVersion=0.33.0
|
|||||||
snappyVersion=0.5
|
snappyVersion=0.5
|
||||||
jcabiManifestsVersion=1.1
|
jcabiManifestsVersion=1.1
|
||||||
picocliVersion=3.9.6
|
picocliVersion=3.9.6
|
||||||
commonsLangVersion=3.9
|
|
||||||
commonsIoVersion=2.17.0
|
commonsIoVersion=2.17.0
|
||||||
controlsfxVersion=8.40.15
|
controlsfxVersion=8.40.15
|
||||||
# FontAwesomeFX for Java8
|
|
||||||
fontawesomefxCommonsJava8Version=8.15
|
|
||||||
fontawesomefxFontawesomeJava8Version=4.7.0-5
|
|
||||||
# FontAwesomeFX for a more recent version of the Java Runtime (class file version 55.0)
|
|
||||||
fontawesomefxCommonsVersion=11.0
|
fontawesomefxCommonsVersion=11.0
|
||||||
fontawesomefxFontawesomeVersion=4.7.0-11
|
fontawesomefxFontawesomeVersion=4.7.0-11
|
||||||
javaassistVersion=3.27.0-GA
|
javaassistVersion=3.29.2-GA
|
||||||
|
joorVersion=0.9.15
|
||||||
|
4
core-1.2/README.md
Normal file
4
core-1.2/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
This is a Kotlin 1.2 version of the `core` module, which is consumed by the `verifier` module, for verifying contracts written in Kotlin
|
||||||
|
1.2. This is just a "shell" module which uses the existing the code in `core` and compiles it with the 1.2 compiler.
|
||||||
|
|
||||||
|
To allow `core` to benefit from new APIs introduced since 1.2, those APIs much be copied into this module with the same `kotlin` package.
|
34
core-1.2/build.gradle
Normal file
34
core-1.2/build.gradle
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
apply plugin: "corda.kotlin-1.2"
|
||||||
|
apply plugin: "corda.common-publishing"
|
||||||
|
|
||||||
|
description 'Corda core built with Kotlin 1.2'
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java.srcDir("../core/src/main/java")
|
||||||
|
kotlin.srcDir("../core/src/main/kotlin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Use the same dependencies as core (minus Kotlin)
|
||||||
|
implementation(project(path: ":core", configuration: "resolvableImplementation")) {
|
||||||
|
exclude(group: "org.jetbrains.kotlin")
|
||||||
|
}
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_1_2_version"
|
||||||
|
implementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
archiveBaseName = 'corda-core-1.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Don't publish publicly as it's only needed by the `verifier` module which consumes this into a fat jar.
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
artifactId 'corda-core-1.2'
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
core-1.2/src/main/kotlin/kotlin/CharCode1.2.kt
Normal file
5
core-1.2/src/main/kotlin/kotlin/CharCode1.2.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("unused")
|
||||||
|
package kotlin
|
||||||
|
|
||||||
|
inline val Char.code: Int get() = this.toInt()
|
@ -0,0 +1,37 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("unused", "MagicNumber", "INVISIBLE_MEMBER")
|
||||||
|
|
||||||
|
package kotlin.collections
|
||||||
|
|
||||||
|
inline fun <K, V> Iterable<K>.associateWith(valueSelector: (K) -> V): Map<K, V> {
|
||||||
|
val result = LinkedHashMap<K, V>(mapCapacity(if (this is Collection<*>) size else 10).coerceAtLeast(16))
|
||||||
|
return associateWithTo(result, valueSelector)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <K, V, M : MutableMap<in K, in V>> Iterable<K>.associateWithTo(destination: M, valueSelector: (K) -> V): M {
|
||||||
|
for (element in this) {
|
||||||
|
destination.put(element, valueSelector(element))
|
||||||
|
}
|
||||||
|
return destination
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> Iterable<T>.sumOf(selector: (T) -> Int): Int {
|
||||||
|
var sum = 0
|
||||||
|
for (element in this) {
|
||||||
|
sum += selector(element)
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, R : Comparable<R>> Iterable<T>.maxOf(selector: (T) -> R): R {
|
||||||
|
val iterator = iterator()
|
||||||
|
if (!iterator.hasNext()) throw NoSuchElementException()
|
||||||
|
var maxValue = selector(iterator.next())
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val v = selector(iterator.next())
|
||||||
|
if (maxValue < v) {
|
||||||
|
maxValue = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxValue
|
||||||
|
}
|
37
core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt
Normal file
37
core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("unused", "SpreadOperator", "NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package kotlin.io.path
|
||||||
|
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.LinkOption
|
||||||
|
import java.nio.file.OpenOption
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.attribute.FileAttribute
|
||||||
|
|
||||||
|
inline operator fun Path.div(other: String): Path = this.resolve(other)
|
||||||
|
|
||||||
|
fun Path.listDirectoryEntries(glob: String = "*"): List<Path> = Files.newDirectoryStream(this, glob).use { it.toList() }
|
||||||
|
|
||||||
|
inline fun Path.createDirectories(vararg attributes: FileAttribute<*>): Path = Files.createDirectories(this, *attributes)
|
||||||
|
|
||||||
|
inline fun Path.deleteIfExists(): Boolean = Files.deleteIfExists(this)
|
||||||
|
|
||||||
|
inline fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options)
|
||||||
|
|
||||||
|
inline fun Path.inputStream(vararg options: OpenOption): InputStream = Files.newInputStream(this, *options)
|
||||||
|
|
||||||
|
inline fun Path.outputStream(vararg options: OpenOption): OutputStream = Files.newOutputStream(this, *options)
|
||||||
|
|
||||||
|
inline fun Path.isDirectory(vararg options: LinkOption): Boolean = Files.isDirectory(this, *options)
|
||||||
|
|
||||||
|
inline fun Path.isSymbolicLink(): Boolean = Files.isSymbolicLink(this)
|
||||||
|
|
||||||
|
inline fun Path.readSymbolicLink(): Path = Files.readSymbolicLink(this)
|
||||||
|
|
||||||
|
val Path.name: String
|
||||||
|
get() = fileName?.toString().orEmpty()
|
||||||
|
|
||||||
|
inline fun Path.readBytes(): ByteArray = Files.readAllBytes(this)
|
24
core-1.2/src/main/kotlin/kotlin/text/CharJVM1.2.kt
Normal file
24
core-1.2/src/main/kotlin/kotlin/text/CharJVM1.2.kt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package kotlin.text
|
||||||
|
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
inline fun Char.isLowerCase(): Boolean = Character.isLowerCase(this)
|
||||||
|
public fun Char.lowercase(locale: Locale): String = toString().lowercase(locale)
|
||||||
|
inline fun Char.lowercaseChar(): Char = Character.toLowerCase(this)
|
||||||
|
inline fun Char.uppercase(): String = toString().uppercase()
|
||||||
|
fun Char.uppercase(locale: Locale): String = toString().uppercase(locale)
|
||||||
|
inline fun Char.titlecaseChar(): Char = Character.toTitleCase(this)
|
||||||
|
fun Char.titlecase(locale: Locale): String {
|
||||||
|
val localizedUppercase = uppercase(locale)
|
||||||
|
if (localizedUppercase.length > 1) {
|
||||||
|
return if (this == '\u0149') localizedUppercase else localizedUppercase[0] + localizedUppercase.substring(1).lowercase()
|
||||||
|
}
|
||||||
|
if (localizedUppercase != uppercase()) {
|
||||||
|
return localizedUppercase
|
||||||
|
}
|
||||||
|
return titlecaseChar().toString()
|
||||||
|
}
|
||||||
|
|
12
core-1.2/src/main/kotlin/kotlin/text/StringBuilder1.2.kt
Normal file
12
core-1.2/src/main/kotlin/kotlin/text/StringBuilder1.2.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("NOTHING_TO_INLINE", "unused")
|
||||||
|
package kotlin.text
|
||||||
|
|
||||||
|
// StringBuilder
|
||||||
|
fun StringBuilder.append(vararg value: String?): StringBuilder {
|
||||||
|
for (item in value)
|
||||||
|
append(item)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
inline fun StringBuilder.appendLine(): StringBuilder = append('\n')
|
||||||
|
inline fun StringBuilder.appendLine(value: String?): StringBuilder = append(value).appendLine()
|
8
core-1.2/src/main/kotlin/kotlin/text/Strings1.2.kt
Normal file
8
core-1.2/src/main/kotlin/kotlin/text/Strings1.2.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package kotlin.text
|
||||||
|
|
||||||
|
inline fun String.replaceFirstChar(transform: (Char) -> CharSequence): String {
|
||||||
|
return if (isNotEmpty()) transform(this[0]).toString() + substring(1) else this
|
||||||
|
}
|
12
core-1.2/src/main/kotlin/kotlin/text/StringsJVM1.2.kt
Normal file
12
core-1.2/src/main/kotlin/kotlin/text/StringsJVM1.2.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||||
|
@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE", "unused")
|
||||||
|
|
||||||
|
package kotlin.text
|
||||||
|
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
// String extensions
|
||||||
|
inline fun String.lowercase(): String = (this as java.lang.String).toLowerCase(Locale.ROOT)
|
||||||
|
inline fun String.lowercase(locale: Locale): String = (this as java.lang.String).toLowerCase(locale)
|
||||||
|
inline fun String.uppercase(): String = (this as java.lang.String).toUpperCase(Locale.ROOT)
|
||||||
|
inline fun String.uppercase(locale: Locale): String = (this as java.lang.String).toUpperCase(locale)
|
@ -1,118 +0,0 @@
|
|||||||
package net.corda.core.contracts
|
|
||||||
|
|
||||||
import net.corda.core.crypto.CompositeKey
|
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.crypto.sha256
|
|
||||||
import net.corda.core.internal.hash
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
|
||||||
import java.security.PublicKey
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
import java.util.concurrent.ConcurrentMap
|
|
||||||
|
|
||||||
object CordaRotatedKeys {
|
|
||||||
val keys = RotatedKeys()
|
|
||||||
}
|
|
||||||
|
|
||||||
// The current development CorDapp code signing public key hash
|
|
||||||
const val DEV_CORDAPP_CODE_SIGNING_STR = "AA59D829F2CA8FDDF5ABEA40D815F937E3E54E572B65B93B5C216AE6594E7D6B"
|
|
||||||
// The non production CorDapp code signing public key hash
|
|
||||||
const val NEW_NON_PROD_CORDAPP_CODE_SIGNING_STR = "B710A80780A12C52DF8A0B4C2247E08907CCA5D0F19AB1E266FE7BAEA9036790"
|
|
||||||
// The production CorDapp code signing public key hash
|
|
||||||
const val PROD_CORDAPP_CODE_SIGNING_STR = "EB4989E7F861FEBEC242E6C24CF0B51C41E108D2C4479D296C5570CB8DAD3EE0"
|
|
||||||
// The new production CorDapp code signing public key hash
|
|
||||||
const val NEW_PROD_CORDAPP_CODE_SIGNING_STR = "01EFA14B42700794292382C1EEAC9788A26DAFBCCC98992C01D5BC30EEAACD28"
|
|
||||||
|
|
||||||
// Rotations used by Corda
|
|
||||||
private val CORDA_SIGNING_KEY_ROTATIONS = listOf(
|
|
||||||
listOf(SecureHash.create(DEV_CORDAPP_CODE_SIGNING_STR).sha256(), SecureHash.create(NEW_NON_PROD_CORDAPP_CODE_SIGNING_STR).sha256()),
|
|
||||||
listOf(SecureHash.create(PROD_CORDAPP_CODE_SIGNING_STR).sha256(), SecureHash.create(NEW_PROD_CORDAPP_CODE_SIGNING_STR).sha256())
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents the rotated CorDapp signing keys known by this node.
|
|
||||||
*
|
|
||||||
* A public key in this class is identified by its SHA-256 hash of the public key encoded bytes (@see PublicKey.getEncoded()).
|
|
||||||
* A sequence of rotated keys is represented by a list of hashes of those public keys. The list of those lists represents
|
|
||||||
* each unrelated set of rotated keys. A key should not appear more than once, either in the same list of in multiple lists.
|
|
||||||
*
|
|
||||||
* For the purposes of SignatureConstraints this means we treat all entries in a list of key hashes as equivalent.
|
|
||||||
* For two keys to be equivalent, they must be equal, or they must appear in the same list of hashes.
|
|
||||||
*
|
|
||||||
* @param rotatedSigningKeys A List of rotated keys. With a rotated key being represented by a list of hashes. This list comes from
|
|
||||||
* node.conf.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@CordaSerializable
|
|
||||||
data class RotatedKeys(val rotatedSigningKeys: List<List<SecureHash>> = emptyList()) {
|
|
||||||
private val canBeTransitionedMap: ConcurrentMap<Pair<PublicKey, PublicKey>, Boolean> = ConcurrentHashMap()
|
|
||||||
private val rotateMap: Map<SecureHash, SecureHash> = HashMap<SecureHash, SecureHash>().apply {
|
|
||||||
(rotatedSigningKeys + CORDA_SIGNING_KEY_ROTATIONS).forEach { rotatedKeyList ->
|
|
||||||
rotatedKeyList.forEach { key ->
|
|
||||||
if (this.containsKey(key)) throw IllegalStateException("The key with sha256(hash) $key appears in the rotated keys configuration more than once.")
|
|
||||||
this[key] = rotatedKeyList.last()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun canBeTransitioned(inputKey: PublicKey, outputKeys: List<PublicKey>): Boolean {
|
|
||||||
return canBeTransitioned(inputKey, CompositeKey.Builder().addKeys(outputKeys).build())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun canBeTransitioned(inputKeys: List<PublicKey>, outputKeys: List<PublicKey>): Boolean {
|
|
||||||
return canBeTransitioned(CompositeKey.Builder().addKeys(inputKeys).build(), CompositeKey.Builder().addKeys(outputKeys).build())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun canBeTransitioned(inputKey: PublicKey, outputKey: PublicKey): Boolean {
|
|
||||||
// Need to handle if inputKey and outputKey are composite keys. They could be if part of SignatureConstraints
|
|
||||||
return canBeTransitionedMap.getOrPut(Pair(inputKey, outputKey)) {
|
|
||||||
when {
|
|
||||||
(inputKey is CompositeKey && outputKey is CompositeKey) -> compareKeys(inputKey, outputKey)
|
|
||||||
(inputKey is CompositeKey && outputKey !is CompositeKey) -> compareKeys(inputKey, outputKey)
|
|
||||||
(inputKey !is CompositeKey && outputKey is CompositeKey) -> compareKeys(inputKey, outputKey)
|
|
||||||
else -> isRotatedEquals(inputKey, outputKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun rotateToHash(key: PublicKey) = rotate(key.hash.sha256())
|
|
||||||
|
|
||||||
private fun rotate(key: SecureHash): SecureHash {
|
|
||||||
return rotateMap[key] ?: key
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isRotatedEquals(inputKey: PublicKey, outputKey: PublicKey): Boolean {
|
|
||||||
return when {
|
|
||||||
inputKey == outputKey -> true
|
|
||||||
rotate(inputKey.hash.sha256()) == rotate(outputKey.hash.sha256()) -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compareKeys(inputKey: CompositeKey, outputKey: PublicKey): Boolean {
|
|
||||||
if (inputKey.leafKeys.size == 1) {
|
|
||||||
return canBeTransitioned(inputKey.leafKeys.first(), outputKey)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compareKeys(inputKey: PublicKey, outputKey: CompositeKey): Boolean {
|
|
||||||
if (outputKey.leafKeys.size == 1) {
|
|
||||||
return canBeTransitioned(inputKey, outputKey.leafKeys.first())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compareKeys(inputKey: CompositeKey, outputKey: CompositeKey): Boolean {
|
|
||||||
if (inputKey.leafKeys.size != outputKey.leafKeys.size) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
inputKey.leafKeys.forEach { inputLeafKey ->
|
|
||||||
if (!outputKey.leafKeys.any { outputLeafKey -> canBeTransitioned(inputLeafKey, outputLeafKey) }) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,21 @@
|
|||||||
apply plugin: 'kotlin'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'kotlin-jpa'
|
apply plugin: 'org.jetbrains.kotlin.plugin.jpa'
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
|
apply plugin: 'idea'
|
||||||
|
|
||||||
description 'Corda core tests'
|
description 'Corda core tests'
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
integrationTestCompile.extendsFrom testCompile
|
integrationTestImplementation.extendsFrom testImplementation
|
||||||
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
|
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
|
||||||
|
|
||||||
smokeTestCompile.extendsFrom compile
|
smokeTestImplementation.extendsFrom implementation
|
||||||
smokeTestRuntimeOnly.extendsFrom runtimeOnly
|
smokeTestRuntimeOnly.extendsFrom runtimeOnly
|
||||||
}
|
|
||||||
|
|
||||||
evaluationDependsOn(':node:capsule')
|
testArtifacts.extendsFrom testRuntimeOnlyClasspath
|
||||||
|
|
||||||
|
corda4_11
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
integrationTest {
|
integrationTest {
|
||||||
@ -41,64 +44,110 @@ sourceSets {
|
|||||||
|
|
||||||
processSmokeTestResources {
|
processSmokeTestResources {
|
||||||
// Bring in the fully built corda.jar for use by NodeFactory in the smoke tests
|
// Bring in the fully built corda.jar for use by NodeFactory in the smoke tests
|
||||||
from(project(':node:capsule').tasks['buildCordaJAR']) {
|
from(tasks.getByPath(":node:capsule:buildCordaJAR")) {
|
||||||
rename 'corda-(.*)', 'corda.jar'
|
rename 'corda-(.*)', 'corda.jar'
|
||||||
}
|
}
|
||||||
|
from(tasks.getByPath(":finance:workflows:jar")) {
|
||||||
|
rename 'corda-finance-workflows-.*.jar', 'corda-finance-workflows.jar'
|
||||||
|
}
|
||||||
|
from(tasks.getByPath(":finance:contracts:jar")) {
|
||||||
|
rename 'corda-finance-contracts-.*.jar', 'corda-finance-contracts.jar'
|
||||||
|
}
|
||||||
|
from(tasks.getByPath(":testing:cordapps:4.11-workflows:jar"))
|
||||||
|
from(configurations.corda4_11) {
|
||||||
|
rename 'jackson-core-.*.jar', 'jackson-core.jar'
|
||||||
|
}
|
||||||
|
from(tasks.getByPath(":legacy411:jar")) {
|
||||||
|
rename 'legacy411-.*.jar', 'legacy411.jar'
|
||||||
|
}
|
||||||
|
from(tasks.getByPath(":legacy412:jar")) {
|
||||||
|
rename 'legacy412-.*.jar', 'legacy412.jar'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processIntegrationTestResources {
|
||||||
|
from(tasks.getByPath(":finance:contracts:jar")) {
|
||||||
|
rename 'corda-finance-contracts-.*.jar', 'corda-finance-contracts.jar'
|
||||||
|
}
|
||||||
|
from(configurations.corda4_11)
|
||||||
|
}
|
||||||
|
|
||||||
|
processTestResources {
|
||||||
|
from(configurations.corda4_11)
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
testImplementation project(":core")
|
||||||
|
testImplementation project(":serialization")
|
||||||
|
testImplementation project(":finance:contracts")
|
||||||
|
testImplementation project(":finance:workflows")
|
||||||
|
testImplementation project(":node")
|
||||||
|
testImplementation project(":node-api")
|
||||||
|
testImplementation project(":client:rpc")
|
||||||
|
testImplementation project(":common-configuration-parsing")
|
||||||
|
testImplementation project(":core-test-utils")
|
||||||
|
testImplementation project(":test-utils")
|
||||||
|
testImplementation project(":node-driver")
|
||||||
|
// used by FinalityFlowTests
|
||||||
|
testImplementation project(':testing:cordapps:cashobservers')
|
||||||
|
testImplementation(project(path: ':core', configuration: 'testArtifacts')) {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
|
testImplementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version"
|
||||||
|
// Guava: Google test library (collections test suite)
|
||||||
|
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
||||||
|
testImplementation "com.google.jimfs:jimfs:1.1"
|
||||||
|
testImplementation "com.typesafe:config:$typesafe_config_version"
|
||||||
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
// Hamkrest, for fluent, composable matchers
|
||||||
|
testImplementation "com.natpryce:hamkrest:$hamkrest_version"
|
||||||
|
testImplementation 'org.hamcrest:hamcrest-library:2.1'
|
||||||
|
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
|
||||||
|
testImplementation "org.mockito:mockito-core:$mockito_version"
|
||||||
|
// AssertJ: for fluent assertions for testing
|
||||||
|
testImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||||
|
// Guava: Google utilities library.
|
||||||
|
testImplementation "com.google.guava:guava:$guava_version"
|
||||||
|
testImplementation "com.esotericsoftware:kryo:$kryo_version"
|
||||||
|
testImplementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||||
|
testImplementation "org.hibernate:hibernate-core:$hibernate_version"
|
||||||
|
testImplementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}"
|
||||||
|
testImplementation "io.netty:netty-common:$netty_version"
|
||||||
|
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
testImplementation "io.dropwizard.metrics:metrics-jmx:$metrics_version"
|
testImplementation "io.dropwizard.metrics:metrics-jmx:$metrics_version"
|
||||||
|
|
||||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
|
||||||
testCompile "commons-fileupload:commons-fileupload:$fileupload_version"
|
|
||||||
testCompile project(":core")
|
|
||||||
testCompile project(path: ':core', configuration: 'testArtifacts')
|
|
||||||
|
|
||||||
// Guava: Google test library (collections test suite)
|
|
||||||
testCompile "com.google.guava:guava-testlib:$guava_version"
|
|
||||||
|
|
||||||
// Bring in the MockNode infrastructure for writing protocol unit tests.
|
|
||||||
testCompile project(":node-driver")
|
|
||||||
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
|
||||||
|
|
||||||
// Hamkrest, for fluent, composable matchers
|
|
||||||
testCompile "com.natpryce:hamkrest:$hamkrest_version"
|
|
||||||
|
|
||||||
// SLF4J: commons-logging bindings for a SLF4J back end
|
|
||||||
compile "org.slf4j:jcl-over-slf4j:$slf4j_version"
|
|
||||||
compile "org.slf4j:slf4j-api:$slf4j_version"
|
|
||||||
|
|
||||||
// AssertJ: for fluent assertions for testing
|
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
|
||||||
|
|
||||||
// Guava: Google utilities library.
|
|
||||||
testCompile "com.google.guava:guava:$guava_version"
|
|
||||||
|
|
||||||
// Smoke tests do NOT have any Node code on the classpath!
|
// Smoke tests do NOT have any Node code on the classpath!
|
||||||
|
smokeTestImplementation project(":core")
|
||||||
|
smokeTestImplementation project(":node-api")
|
||||||
|
smokeTestImplementation project(":client:rpc")
|
||||||
|
smokeTestImplementation project(':smoke-test-utils')
|
||||||
|
smokeTestImplementation project(':core-test-utils')
|
||||||
|
smokeTestImplementation project(":finance:workflows")
|
||||||
|
smokeTestImplementation project(":testing:cordapps:4.11-workflows")
|
||||||
|
smokeTestImplementation project(":finance:contracts")
|
||||||
|
smokeTestImplementation project(":legacy411")
|
||||||
|
smokeTestImplementation project(":legacy412")
|
||||||
|
smokeTestImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||||
|
smokeTestImplementation "org.bouncycastle:bcprov-lts8on:${bouncycastle_version}"
|
||||||
|
smokeTestImplementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||||
smokeTestImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
smokeTestImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
smokeTestImplementation "junit:junit:$junit_version"
|
smokeTestImplementation "junit:junit:$junit_version"
|
||||||
|
|
||||||
smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
smokeTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||||
smokeTestRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
smokeTestRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||||
smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
smokeTestRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||||
|
smokeTestRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version"
|
||||||
|
|
||||||
smokeTestCompile project(':smoke-test-utils')
|
corda4_11 "net.corda:corda-finance-contracts:4.11"
|
||||||
smokeTestCompile "org.assertj:assertj-core:${assertj_version}"
|
corda4_11 "net.corda:corda-finance-workflows:4.11"
|
||||||
|
corda4_11 "net.corda:corda:4.11"
|
||||||
// used by FinalityFlowTests
|
corda4_11 "com.fasterxml.jackson.core:jackson-core:2.17.2"
|
||||||
testCompile project(':testing:cordapps:cashobservers')
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
testArtifacts.extendsFrom testRuntimeClasspath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
tasks.withType(Test).configureEach {
|
||||||
@ -106,27 +155,36 @@ tasks.withType(Test).configureEach {
|
|||||||
forkEvery = 10
|
forkEvery = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
task testJar(type: Jar) {
|
tasks.register('testJar', Jar) {
|
||||||
classifier "tests"
|
classifier "tests"
|
||||||
from sourceSets.test.output
|
from sourceSets.test.output
|
||||||
}
|
}
|
||||||
|
|
||||||
task integrationTest(type: Test) {
|
tasks.register('integrationTest', Test) {
|
||||||
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
||||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
task smokeTestJar(type: Jar) {
|
tasks.register('smokeTestJar', Jar) {
|
||||||
classifier 'smokeTests'
|
classifier 'smokeTests'
|
||||||
from sourceSets.smokeTest.output
|
from(sourceSets.smokeTest.output) {
|
||||||
|
exclude("*.jar")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task smokeTest(type: Test) {
|
tasks.register('smokeTest', Test) {
|
||||||
dependsOn smokeTestJar
|
dependsOn smokeTestJar
|
||||||
testClassesDirs = sourceSets.smokeTest.output.classesDirs
|
testClassesDirs = sourceSets.smokeTest.output.classesDirs
|
||||||
classpath = sourceSets.smokeTest.runtimeClasspath
|
classpath = sourceSets.smokeTest.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idea {
|
||||||
|
module {
|
||||||
|
downloadJavadoc = true
|
||||||
|
downloadSources = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// quasar exclusions upon agent code instrumentation at run-time
|
// quasar exclusions upon agent code instrumentation at run-time
|
||||||
quasar {
|
quasar {
|
||||||
excludePackages.addAll(
|
excludePackages.addAll(
|
||||||
@ -141,7 +199,6 @@ quasar {
|
|||||||
"io.github.classgraph**",
|
"io.github.classgraph**",
|
||||||
"io.netty*",
|
"io.netty*",
|
||||||
"liquibase**",
|
"liquibase**",
|
||||||
"net.i2p.crypto.**",
|
|
||||||
"nonapi.io.github.classgraph.**",
|
"nonapi.io.github.classgraph.**",
|
||||||
"org.apiguardian.**",
|
"org.apiguardian.**",
|
||||||
"org.bouncycastle**",
|
"org.bouncycastle**",
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
package net.corda.coretests.transactions
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.core.contracts.TransactionState
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.hash
|
||||||
|
import net.corda.core.internal.mapToSet
|
||||||
|
import net.corda.core.internal.toPath
|
||||||
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.coretesting.internal.delete
|
||||||
|
import net.corda.coretesting.internal.modifyJarManifest
|
||||||
|
import net.corda.coretesting.internal.useZipFile
|
||||||
|
import net.corda.finance.DOLLARS
|
||||||
|
import net.corda.finance.contracts.CommercialPaper
|
||||||
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.flows.CashIssueAndPaymentFlow
|
||||||
|
import net.corda.finance.issuedBy
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
|
import net.corda.testing.core.BOB_NAME
|
||||||
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
|
import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar
|
||||||
|
import net.corda.testing.core.singleIdentity
|
||||||
|
import net.corda.testing.driver.NodeHandle
|
||||||
|
import net.corda.testing.driver.NodeParameters
|
||||||
|
import net.corda.testing.node.NotarySpec
|
||||||
|
import net.corda.testing.node.TestCordapp
|
||||||
|
import net.corda.testing.node.internal.DriverDSLImpl
|
||||||
|
import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP
|
||||||
|
import net.corda.testing.node.internal.TestCordappInternal
|
||||||
|
import net.corda.testing.node.internal.UriTestCordapp
|
||||||
|
import net.corda.testing.node.internal.enclosedCordapp
|
||||||
|
import net.corda.testing.node.internal.internalDriver
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy
|
||||||
|
import org.junit.Test
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
import kotlin.io.path.absolutePathString
|
||||||
|
import kotlin.io.path.copyTo
|
||||||
|
import kotlin.io.path.createDirectories
|
||||||
|
import kotlin.io.path.inputStream
|
||||||
|
import kotlin.io.path.isRegularFile
|
||||||
|
import kotlin.io.path.moveTo
|
||||||
|
|
||||||
|
class TransactionBuilderDriverTest {
|
||||||
|
companion object {
|
||||||
|
val currentFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts.jar")!!.toPath()
|
||||||
|
val legacyFinanceContractsJar = this::class.java.getResource("/corda-finance-contracts-4.11.jar")!!.toPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `adds CorDapp dependencies`() {
|
||||||
|
internalDriver(cordappsForAllNodes = listOf(FINANCE_WORKFLOWS_CORDAPP), startNodesInProcess = false) {
|
||||||
|
val (cordapp, dependency) = splitFinanceContractCordapp(currentFinanceContractsJar)
|
||||||
|
|
||||||
|
cordapp.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment)
|
||||||
|
dependency.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment)
|
||||||
|
|
||||||
|
// Start the node with the CorDapp but without the dependency
|
||||||
|
val node = startNode(NodeParameters(ALICE_NAME, additionalCordapps = listOf(cordapp))).getOrThrow()
|
||||||
|
|
||||||
|
// First make sure the missing dependency causes an issue
|
||||||
|
assertThatThrownBy {
|
||||||
|
createTransaction(node)
|
||||||
|
}.hasMessageContaining("Transaction being built has a missing attachment for class net/corda/finance/contracts/asset/")
|
||||||
|
|
||||||
|
// Upload the missing dependency
|
||||||
|
dependency.jarFile.inputStream().use(node.rpc::uploadAttachment)
|
||||||
|
|
||||||
|
val stx = createTransaction(node)
|
||||||
|
assertThat(stx.tx.attachments).contains(cordapp.jarFile.hash, dependency.jarFile.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `adds legacy contracts CorDapp dependencies`() {
|
||||||
|
internalDriver(
|
||||||
|
cordappsForAllNodes = listOf(FINANCE_WORKFLOWS_CORDAPP),
|
||||||
|
startNodesInProcess = false,
|
||||||
|
networkParameters = testNetworkParameters(minimumPlatformVersion = 4),
|
||||||
|
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = false))
|
||||||
|
) {
|
||||||
|
val (legacyContracts, legacyDependency) = splitFinanceContractCordapp(legacyFinanceContractsJar)
|
||||||
|
val currentContracts = TestCordapp.of(currentFinanceContractsJar.toUri()).asSigned() as TestCordappInternal
|
||||||
|
|
||||||
|
currentContracts.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment)
|
||||||
|
|
||||||
|
// Start the node with the legacy CorDapp but without the dependency
|
||||||
|
val node = startNode(NodeParameters(
|
||||||
|
ALICE_NAME,
|
||||||
|
additionalCordapps = listOf(currentContracts),
|
||||||
|
legacyContracts = listOf(legacyContracts)
|
||||||
|
)).getOrThrow()
|
||||||
|
|
||||||
|
val nodeBob = startNode(NodeParameters(
|
||||||
|
BOB_NAME,
|
||||||
|
additionalCordapps = listOf(currentContracts),
|
||||||
|
legacyContracts = listOf(legacyContracts,legacyDependency)
|
||||||
|
)).getOrThrow()
|
||||||
|
val bobParty = nodeBob.nodeInfo.singleIdentity()
|
||||||
|
|
||||||
|
|
||||||
|
// First make sure the missing dependency causes an issue
|
||||||
|
assertThatThrownBy {
|
||||||
|
createTransaction(node, bobParty)
|
||||||
|
}.hasMessageContaining("Transaction being built has a missing legacy attachment for class net/corda/finance/contracts/asset/")
|
||||||
|
|
||||||
|
// Upload the missing dependency
|
||||||
|
legacyDependency.jarFile.inputStream().use(node.rpc::uploadAttachment)
|
||||||
|
|
||||||
|
val stx = createTransaction(node, bobParty)
|
||||||
|
assertThat(stx.tx.legacyAttachments).contains(legacyContracts.jarFile.hash, legacyDependency.jarFile.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `prevents transaction which is multi-contract but not backwards compatible because one of the contracts has missing legacy attachment`() {
|
||||||
|
internalDriver(
|
||||||
|
cordappsForAllNodes = listOf(FINANCE_WORKFLOWS_CORDAPP, enclosedCordapp()),
|
||||||
|
startNodesInProcess = false,
|
||||||
|
networkParameters = testNetworkParameters(minimumPlatformVersion = 4),
|
||||||
|
isDebug = true
|
||||||
|
) {
|
||||||
|
val (currentCashContract, currentCpContract) = splitJar(currentFinanceContractsJar) { "CommercialPaper" in it.absolutePathString() }
|
||||||
|
val (legacyCashContract, _) = splitJar(legacyFinanceContractsJar) { "CommercialPaper" in it.absolutePathString() }
|
||||||
|
|
||||||
|
currentCashContract.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment)
|
||||||
|
currentCpContract.jarFile.inputStream().use(defaultNotaryNode.getOrThrow().rpc::uploadAttachment)
|
||||||
|
|
||||||
|
// The node has the legacy CommericalPaper contract missing
|
||||||
|
val node = startNode(NodeParameters(
|
||||||
|
ALICE_NAME,
|
||||||
|
additionalCordapps = listOf(currentCashContract, currentCpContract),
|
||||||
|
legacyContracts = listOf(legacyCashContract)
|
||||||
|
)).getOrThrow()
|
||||||
|
|
||||||
|
assertThatThrownBy { node.rpc.startFlow(::TwoContractTransactionFlow).returnValue.getOrThrow() }
|
||||||
|
.hasMessageContaining("Transaction being built has a missing legacy attachment")
|
||||||
|
.hasMessageContaining("CommercialPaper")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split the given finance contracts jar into two such that the second jar becomes a dependency to the first.
|
||||||
|
*/
|
||||||
|
private fun DriverDSLImpl.splitFinanceContractCordapp(contractsJar: Path): Pair<UriTestCordapp, UriTestCordapp> {
|
||||||
|
return splitJar(contractsJar) { it.absolutePathString() == "/net/corda/finance/contracts/asset/CashUtilities.class" }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DriverDSLImpl.splitJar(path: Path, move: (Path) -> Boolean): Pair<UriTestCordapp, UriTestCordapp> {
|
||||||
|
val jar1 = Files.createTempFile(driverDirectory, "jar1-", ".jar")
|
||||||
|
val jar2 = Files.createTempFile(driverDirectory, "jar2-", ".jar")
|
||||||
|
|
||||||
|
path.copyTo(jar1, overwrite = true)
|
||||||
|
jar1.useZipFile { zipFs1 ->
|
||||||
|
jar2.useZipFile { zipFs2 ->
|
||||||
|
Files.walk(zipFs1.getPath("/")).filter { it.isRegularFile() && move(it) }.forEach { file ->
|
||||||
|
val target = zipFs2.getPath(file.absolutePathString())
|
||||||
|
target.parent?.createDirectories()
|
||||||
|
file.moveTo(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jar1.modifyJarManifest { manifest ->
|
||||||
|
manifest.mainAttributes.delete("Sealed")
|
||||||
|
}
|
||||||
|
jar1.unsignJar()
|
||||||
|
|
||||||
|
return Pair(
|
||||||
|
TestCordapp.of(jar1.toUri()).asSigned() as UriTestCordapp,
|
||||||
|
TestCordapp.of(jar2.toUri()).asSigned() as UriTestCordapp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DriverDSLImpl.createTransaction(node: NodeHandle, destination: Party = defaultNotaryIdentity): SignedTransaction {
|
||||||
|
return node.rpc.startFlow(
|
||||||
|
::CashIssueAndPaymentFlow,
|
||||||
|
1.DOLLARS,
|
||||||
|
OpaqueBytes.of(0x00),
|
||||||
|
destination,
|
||||||
|
false,
|
||||||
|
defaultNotaryIdentity
|
||||||
|
).returnValue.getOrThrow().stx
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class TwoContractTransactionFlow : FlowLogic<Unit>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val notary = serviceHub.networkMapCache.notaryIdentities[0]
|
||||||
|
val builder = TransactionBuilder(notary)
|
||||||
|
val issuer = ourIdentity.ref(OpaqueBytes.of(0x00))
|
||||||
|
val amount = 1.DOLLARS.issuedBy(issuer)
|
||||||
|
val signers = Cash().generateIssue(builder, amount, ourIdentity, notary)
|
||||||
|
builder.addOutputState(TransactionState(CommercialPaper.State(issuer, ourIdentity, amount, Instant.MAX), notary = notary))
|
||||||
|
builder.addCommand(CommercialPaper.Commands.Issue(), signers.first())
|
||||||
|
builder.setTimeWindow(Instant.now(), Duration.ofMinutes(1))
|
||||||
|
require(builder.outputStates().mapToSet { it.contract }.size > 1)
|
||||||
|
serviceHub.signInitialTransaction(builder, signers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,20 +4,20 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.PLATFORM_VERSION
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.nodeapi.internal.config.User
|
import net.corda.nodeapi.internal.config.User
|
||||||
import net.corda.smoketesting.NodeConfig
|
import net.corda.smoketesting.NodeParams
|
||||||
import net.corda.smoketesting.NodeProcess
|
import net.corda.smoketesting.NodeProcess
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
import kotlin.streams.toList
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.listDirectoryEntries
|
||||||
|
|
||||||
class NodeVersioningTest {
|
class NodeVersioningTest {
|
||||||
private companion object {
|
private companion object {
|
||||||
@ -27,60 +27,41 @@ class NodeVersioningTest {
|
|||||||
|
|
||||||
private val factory = NodeProcess.Factory()
|
private val factory = NodeProcess.Factory()
|
||||||
|
|
||||||
private val notaryConfig = NodeConfig(
|
private lateinit var notary: NodeProcess
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun startNotary() {
|
||||||
|
notary = factory.createNotaries(NodeParams(
|
||||||
legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"),
|
legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"),
|
||||||
p2pPort = port.andIncrement,
|
p2pPort = port.andIncrement,
|
||||||
rpcPort = port.andIncrement,
|
rpcPort = port.andIncrement,
|
||||||
rpcAdminPort = port.andIncrement,
|
rpcAdminPort = port.andIncrement,
|
||||||
isNotary = true,
|
users = listOf(superUser),
|
||||||
users = listOf(superUser)
|
// Find the jar file for the smoke tests of this module
|
||||||
)
|
cordappJars = Path("build", "libs").listDirectoryEntries("*-smokeTests*")
|
||||||
|
))[0]
|
||||||
private val aliceConfig = NodeConfig(
|
|
||||||
legalName = CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"),
|
|
||||||
p2pPort = port.andIncrement,
|
|
||||||
rpcPort = port.andIncrement,
|
|
||||||
rpcAdminPort = port.andIncrement,
|
|
||||||
isNotary = false,
|
|
||||||
users = listOf(superUser)
|
|
||||||
)
|
|
||||||
|
|
||||||
private lateinit var notary: NodeProcess
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
notary = factory.create(notaryConfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun done() {
|
fun done() {
|
||||||
notary.close()
|
factory.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `platform version in manifest file`() {
|
fun `platform version in manifest file`() {
|
||||||
val manifest = JarFile(factory.cordaJar.toFile()).manifest
|
val manifest = JarFile(NodeProcess.Factory.getCordaJar().toFile()).manifest
|
||||||
assertThat(manifest.mainAttributes.getValue("Corda-Platform-Version").toInt()).isEqualTo(PLATFORM_VERSION)
|
assertThat(manifest.mainAttributes.getValue("Corda-Platform-Version").toInt()).isEqualTo(PLATFORM_VERSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `platform version from RPC`() {
|
fun `platform version from RPC`() {
|
||||||
val cordappsDir = (factory.baseDirectory(aliceConfig) / NodeProcess.CORDAPPS_DIR_NAME).createDirectories()
|
notary.connect(superUser).use {
|
||||||
// Find the jar file for the smoke tests of this module
|
|
||||||
val selfCordapp = Paths.get("build", "libs").list {
|
|
||||||
it.filter { "-smokeTests" in it.toString() }.toList().single()
|
|
||||||
}
|
|
||||||
selfCordapp.copyToDirectory(cordappsDir)
|
|
||||||
|
|
||||||
factory.create(aliceConfig).use { alice ->
|
|
||||||
alice.connect(superUser).use {
|
|
||||||
val rpc = it.proxy
|
val rpc = it.proxy
|
||||||
assertThat(rpc.protocolVersion).isEqualTo(PLATFORM_VERSION)
|
assertThat(rpc.protocolVersion).isEqualTo(PLATFORM_VERSION)
|
||||||
assertThat(rpc.nodeInfo().platformVersion).isEqualTo(PLATFORM_VERSION)
|
assertThat(rpc.nodeInfo().platformVersion).isEqualTo(PLATFORM_VERSION)
|
||||||
assertThat(rpc.startFlow(NodeVersioningTest::GetPlatformVersionFlow).returnValue.getOrThrow()).isEqualTo(PLATFORM_VERSION)
|
assertThat(rpc.startFlow(NodeVersioningTest::GetPlatformVersionFlow).returnValue.getOrThrow()).isEqualTo(PLATFORM_VERSION)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
class GetPlatformVersionFlow : FlowLogic<Int>() {
|
class GetPlatformVersionFlow : FlowLogic<Int>() {
|
||||||
|
@ -3,11 +3,15 @@ package net.corda.coretests.cordapp
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.crypto.Crypto.generateKeyPair
|
import net.corda.core.crypto.Crypto.generateKeyPair
|
||||||
import net.corda.core.crypto.sign
|
import net.corda.core.crypto.sign
|
||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.FlowInfo
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.FlowSession
|
||||||
|
import net.corda.core.flows.InitiatedBy
|
||||||
|
import net.corda.core.flows.InitiatingFlow
|
||||||
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.*
|
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
@ -21,20 +25,23 @@ import net.corda.nodeapi.internal.config.User
|
|||||||
import net.corda.nodeapi.internal.createDevNodeCa
|
import net.corda.nodeapi.internal.createDevNodeCa
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import net.corda.smoketesting.NodeConfig
|
import net.corda.smoketesting.NodeParams
|
||||||
import net.corda.smoketesting.NodeProcess
|
import net.corda.smoketesting.NodeProcess
|
||||||
import net.corda.smoketesting.NodeProcess.Companion.CORDAPPS_DIR_NAME
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.streams.toList
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.createDirectories
|
||||||
|
import kotlin.io.path.div
|
||||||
|
import kotlin.io.path.listDirectoryEntries
|
||||||
|
import kotlin.io.path.name
|
||||||
|
import kotlin.io.path.writeBytes
|
||||||
|
|
||||||
class CordappSmokeTest {
|
class CordappSmokeTest {
|
||||||
private companion object {
|
private companion object {
|
||||||
@ -44,45 +51,35 @@ class CordappSmokeTest {
|
|||||||
|
|
||||||
private val factory = NodeProcess.Factory()
|
private val factory = NodeProcess.Factory()
|
||||||
|
|
||||||
private val notaryConfig = NodeConfig(
|
private val aliceConfig = NodeParams(
|
||||||
legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"),
|
|
||||||
p2pPort = port.andIncrement,
|
|
||||||
rpcPort = port.andIncrement,
|
|
||||||
rpcAdminPort = port.andIncrement,
|
|
||||||
isNotary = true,
|
|
||||||
users = listOf(superUser)
|
|
||||||
)
|
|
||||||
|
|
||||||
private val aliceConfig = NodeConfig(
|
|
||||||
legalName = CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"),
|
legalName = CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"),
|
||||||
p2pPort = port.andIncrement,
|
p2pPort = port.andIncrement,
|
||||||
rpcPort = port.andIncrement,
|
rpcPort = port.andIncrement,
|
||||||
rpcAdminPort = port.andIncrement,
|
rpcAdminPort = port.andIncrement,
|
||||||
isNotary = false,
|
users = listOf(superUser),
|
||||||
users = listOf(superUser)
|
// Find the jar file for the smoke tests of this module
|
||||||
|
cordappJars = Path("build", "libs").listDirectoryEntries("*-smokeTests*")
|
||||||
)
|
)
|
||||||
|
|
||||||
private lateinit var notary: NodeProcess
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun startNotary() {
|
||||||
notary = factory.create(notaryConfig)
|
factory.createNotaries(NodeParams(
|
||||||
|
legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"),
|
||||||
|
p2pPort = port.andIncrement,
|
||||||
|
rpcPort = port.andIncrement,
|
||||||
|
rpcAdminPort = port.andIncrement,
|
||||||
|
users = listOf(superUser)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun done() {
|
fun done() {
|
||||||
notary.close()
|
factory.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `FlowContent appName returns the filename of the CorDapp jar`() {
|
fun `FlowContent appName returns the filename of the CorDapp jar`() {
|
||||||
val baseDir = factory.baseDirectory(aliceConfig)
|
val baseDir = factory.baseDirectory(aliceConfig)
|
||||||
val cordappsDir = (baseDir / CORDAPPS_DIR_NAME).createDirectories()
|
|
||||||
// Find the jar file for the smoke tests of this module
|
|
||||||
val selfCordapp = Paths.get("build", "libs").list {
|
|
||||||
it.filter { "-smokeTests" in it.toString() }.toList().single()
|
|
||||||
}
|
|
||||||
selfCordapp.copyToDirectory(cordappsDir)
|
|
||||||
|
|
||||||
// The `nodeReadyFuture` in the persistent network map cache will not complete unless there is at least one other
|
// The `nodeReadyFuture` in the persistent network map cache will not complete unless there is at least one other
|
||||||
// node in the network. We work around this limitation by putting another node info file in the additional-node-info
|
// node in the network. We work around this limitation by putting another node info file in the additional-node-info
|
||||||
@ -91,23 +88,16 @@ class CordappSmokeTest {
|
|||||||
val additionalNodeInfoDir = (baseDir / "additional-node-infos").createDirectories()
|
val additionalNodeInfoDir = (baseDir / "additional-node-infos").createDirectories()
|
||||||
createDummyNodeInfo(additionalNodeInfoDir)
|
createDummyNodeInfo(additionalNodeInfoDir)
|
||||||
|
|
||||||
factory.create(aliceConfig).use { alice ->
|
val alice = factory.createNode(aliceConfig)
|
||||||
alice.connect(superUser).use { connectionToAlice ->
|
alice.connect(superUser).use { connectionToAlice ->
|
||||||
val aliceIdentity = connectionToAlice.proxy.nodeInfo().legalIdentitiesAndCerts.first().party
|
val aliceIdentity = connectionToAlice.proxy.nodeInfo().legalIdentitiesAndCerts.first().party
|
||||||
val future = connectionToAlice.proxy.startFlow(CordappSmokeTest::GatherContextsFlow, aliceIdentity).returnValue
|
val future = connectionToAlice.proxy.startFlow(CordappSmokeTest::GatherContextsFlow, aliceIdentity).returnValue
|
||||||
val (sessionInitContext, sessionConfirmContext) = future.getOrThrow()
|
val (sessionInitContext, sessionConfirmContext) = future.getOrThrow()
|
||||||
val selfCordappName = selfCordapp.fileName.toString().removeSuffix(".jar")
|
val selfCordappName = aliceConfig.cordappJars[0].name.removeSuffix(".jar")
|
||||||
assertThat(sessionInitContext.appName).isEqualTo(selfCordappName)
|
assertThat(sessionInitContext.appName).isEqualTo(selfCordappName)
|
||||||
assertThat(sessionConfirmContext.appName).isEqualTo(selfCordappName)
|
assertThat(sessionConfirmContext.appName).isEqualTo(selfCordappName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
|
||||||
fun `empty cordapps directory`() {
|
|
||||||
(factory.baseDirectory(aliceConfig) / CORDAPPS_DIR_NAME).createDirectories()
|
|
||||||
factory.create(aliceConfig).close()
|
|
||||||
}
|
|
||||||
|
|
||||||
@InitiatingFlow
|
@InitiatingFlow
|
||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
@ -139,7 +129,7 @@ class CordappSmokeTest {
|
|||||||
val dummyKeyPair = generateKeyPair()
|
val dummyKeyPair = generateKeyPair()
|
||||||
val nodeInfo = createNodeInfoWithSingleIdentity(CordaX500Name(organisation = "Bob Corp", locality = "Madrid", country = "ES"), dummyKeyPair, dummyKeyPair.public)
|
val nodeInfo = createNodeInfoWithSingleIdentity(CordaX500Name(organisation = "Bob Corp", locality = "Madrid", country = "ES"), dummyKeyPair, dummyKeyPair.public)
|
||||||
val signedNodeInfo = signWith(nodeInfo, listOf(dummyKeyPair.private))
|
val signedNodeInfo = signWith(nodeInfo, listOf(dummyKeyPair.private))
|
||||||
(additionalNodeInfoDir / "nodeInfo-41408E093F95EAD51F6892C34DEB65AE1A3569A4B0E5744769A1B485AF8E04B5").write(signedNodeInfo.serialize().bytes)
|
(additionalNodeInfoDir / "nodeInfo-41408E093F95EAD51F6892C34DEB65AE1A3569A4B0E5744769A1B485AF8E04B5").writeBytes(signedNodeInfo.serialize().bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNodeInfoWithSingleIdentity(name: CordaX500Name, nodeKeyPair: KeyPair, identityCertPublicKey: PublicKey): NodeInfo {
|
private fun createNodeInfoWithSingleIdentity(name: CordaX500Name, nodeKeyPair: KeyPair, identityCertPublicKey: PublicKey): NodeInfo {
|
||||||
|
@ -0,0 +1,327 @@
|
|||||||
|
package net.corda.coretests.verification
|
||||||
|
|
||||||
|
import net.corda.client.rpc.CordaRPCClientConfiguration
|
||||||
|
import net.corda.client.rpc.notUsed
|
||||||
|
import net.corda.core.contracts.Amount
|
||||||
|
import net.corda.core.contracts.StateRef
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.flows.UnexpectedFlowEndException
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.PlatformVersionSwitches.MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS
|
||||||
|
import net.corda.core.internal.toPath
|
||||||
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.node.NodeInfo
|
||||||
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.coretests.verification.VerificationType.BOTH
|
||||||
|
import net.corda.coretests.verification.VerificationType.EXTERNAL
|
||||||
|
import net.corda.finance.DOLLARS
|
||||||
|
import net.corda.finance.USD
|
||||||
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.flows.AbstractCashFlow
|
||||||
|
import net.corda.finance.flows.CashIssueFlow
|
||||||
|
import net.corda.finance.flows.CashPaymentFlow
|
||||||
|
import net.corda.finance.workflows.getCashBalance
|
||||||
|
import net.corda.legacy.workflows.LegacyIssuanceFlow
|
||||||
|
import net.corda.nodeapi.internal.config.User
|
||||||
|
import net.corda.smoketesting.NodeParams
|
||||||
|
import net.corda.smoketesting.NodeProcess
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
import net.corda.testing.cordapps.workflows411.IssueAndChangeNotaryFlow
|
||||||
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
|
import net.corda.testing.core.internal.JarSignatureTestUtils.unsignJar
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
|
import org.junit.AfterClass
|
||||||
|
import org.junit.BeforeClass
|
||||||
|
import org.junit.Test
|
||||||
|
import rx.Observable
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.util.Currency
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.copyTo
|
||||||
|
import kotlin.io.path.div
|
||||||
|
import kotlin.io.path.listDirectoryEntries
|
||||||
|
import kotlin.io.path.readText
|
||||||
|
import kotlin.io.path.useLines
|
||||||
|
|
||||||
|
class ExternalVerificationSignedCordappsTest {
|
||||||
|
private companion object {
|
||||||
|
private val factory = NodeProcess.Factory(testNetworkParameters(minimumPlatformVersion = MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS))
|
||||||
|
|
||||||
|
private lateinit var notaries: List<NodeProcess>
|
||||||
|
private lateinit var oldNode: NodeProcess
|
||||||
|
private lateinit var currentNode: NodeProcess
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun startNodes() {
|
||||||
|
val (legacyContractsCordapp, legacyWorkflowsCordapp) = listOf("contracts", "workflows").map { smokeTestResource("corda-finance-$it-4.11.jar") }
|
||||||
|
// The current version finance CorDapp jars
|
||||||
|
val currentCordapps = listOf("contracts", "workflows").map { smokeTestResource("corda-finance-$it.jar") }
|
||||||
|
val legacyJacksonCordapp411 = smokeTestResource("legacy411.jar")
|
||||||
|
val legacyJacksonCordapp412 = smokeTestResource("legacy412.jar")
|
||||||
|
|
||||||
|
notaries = factory.createNotaries(
|
||||||
|
nodeParams(DUMMY_NOTARY_NAME, cordappJars = currentCordapps, legacyContractJars = listOf(legacyContractsCordapp)),
|
||||||
|
nodeParams(CordaX500Name("Notary Service 2", "Zurich", "CH"), currentCordapps)
|
||||||
|
)
|
||||||
|
oldNode = factory.createNode(nodeParams(
|
||||||
|
CordaX500Name("Old", "Delhi", "IN"),
|
||||||
|
listOf(legacyContractsCordapp, legacyWorkflowsCordapp, smokeTestResource("4.11-workflows-cordapp.jar")),
|
||||||
|
clientRpcConfig = CordaRPCClientConfiguration(minimumServerProtocolVersion = 13),
|
||||||
|
version = "4.11"
|
||||||
|
))
|
||||||
|
currentNode = factory.createNode(nodeParams(
|
||||||
|
CordaX500Name("New", "York", "US"),
|
||||||
|
currentCordapps + listOf(legacyJacksonCordapp412),
|
||||||
|
listOf(legacyContractsCordapp, legacyJacksonCordapp411)
|
||||||
|
))
|
||||||
|
val legacyJars = currentNode.nodeDir / "legacy-jars"
|
||||||
|
legacyJars.toFile().mkdir()
|
||||||
|
|
||||||
|
val jacksonDestination = legacyJars / "jackson-core.jar"
|
||||||
|
val jacksonSource = smokeTestResource("jackson-core.jar")
|
||||||
|
jacksonSource.copyTo(jacksonDestination)
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
@JvmStatic
|
||||||
|
fun close() {
|
||||||
|
factory.close()
|
||||||
|
// Make sure all UNIX domain files are deleted
|
||||||
|
(notaries + currentNode).forEach { node ->
|
||||||
|
node.logFile("node")!!.useLines { lines ->
|
||||||
|
for (line in lines) {
|
||||||
|
if ("ExternalVerifierHandleImpl" in line && "Binding to UNIX domain file " in line) {
|
||||||
|
assertThat(Path(line.substringAfterLast("Binding to UNIX domain file "))).doesNotExist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `transaction containing 4_11 contract attachment only sent to current node`() {
|
||||||
|
val (issuanceTx, paymentTx) = cashIssuanceAndPayment(issuer = oldNode, recipient = currentNode)
|
||||||
|
notaries[0].assertTransactionsWereVerified(EXTERNAL, paymentTx.id)
|
||||||
|
currentNode.assertTransactionsWereVerified(EXTERNAL, issuanceTx.id, paymentTx.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `transaction containing 4_11 and 4_12 contract attachments sent to old node`() {
|
||||||
|
val (issuanceTx, paymentTx) = cashIssuanceAndPayment(issuer = currentNode, recipient = oldNode)
|
||||||
|
notaries[0].assertTransactionsWereVerified(BOTH, paymentTx.id)
|
||||||
|
currentNode.assertTransactionsWereVerified(BOTH, issuanceTx.id, paymentTx.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `notary change transaction`() {
|
||||||
|
val oldRpc = oldNode.connect(superUser).proxy
|
||||||
|
val oldNodeInfo = oldRpc.nodeInfo()
|
||||||
|
val notaryIdentities = oldRpc.notaryIdentities()
|
||||||
|
for (notary in notaries) {
|
||||||
|
notary.connect(superUser).use { it.proxy.waitForVisibility(oldNodeInfo) }
|
||||||
|
}
|
||||||
|
oldRpc.startFlow(::IssueAndChangeNotaryFlow, notaryIdentities[0], notaryIdentities[1]).returnValue.getOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `transaction containing 4_11 and 4_12 contract referencing Jackson dependency issued on new node`() {
|
||||||
|
val issuanceStateRef = legacyJackonIssuance(currentNode)
|
||||||
|
currentNode.assertTransactionsWereVerified(BOTH, issuanceStateRef.txhash)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun legacyJackonIssuance(issuer: NodeProcess): StateRef {
|
||||||
|
val issuerRpc = issuer.connect(superUser).proxy
|
||||||
|
val issuanceStateRef = issuerRpc.startFlowDynamic(LegacyIssuanceFlow::class.java, 2).returnValue.getOrThrow() as StateRef
|
||||||
|
return issuanceStateRef
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cashIssuanceAndPayment(issuer: NodeProcess, recipient: NodeProcess): Pair<SignedTransaction, SignedTransaction> {
|
||||||
|
val issuerRpc = issuer.connect(superUser).proxy
|
||||||
|
val recipientRpc = recipient.connect(superUser).proxy
|
||||||
|
val recipientNodeInfo = recipientRpc.nodeInfo()
|
||||||
|
val notaryIdentity = issuerRpc.notaryIdentities()[0]
|
||||||
|
|
||||||
|
val beforeAmount = recipientRpc.getCashBalance(USD)
|
||||||
|
|
||||||
|
val (issuanceTx) = issuerRpc.startFlow(
|
||||||
|
::CashIssueFlow,
|
||||||
|
10.DOLLARS,
|
||||||
|
OpaqueBytes.of(0x01),
|
||||||
|
notaryIdentity
|
||||||
|
).returnValue.getOrThrow()
|
||||||
|
|
||||||
|
issuerRpc.waitForVisibility(recipientNodeInfo)
|
||||||
|
recipientRpc.waitForVisibility(issuerRpc.nodeInfo())
|
||||||
|
|
||||||
|
val (_, update) = recipientRpc.vaultTrack(Cash.State::class.java)
|
||||||
|
val cashArrived = update.waitForFirst { true }
|
||||||
|
|
||||||
|
val (paymentTx) = issuerRpc.startFlow(
|
||||||
|
::CashPaymentFlow,
|
||||||
|
10.DOLLARS,
|
||||||
|
recipientNodeInfo.legalIdentities[0],
|
||||||
|
false,
|
||||||
|
).returnValue.getOrThrow()
|
||||||
|
|
||||||
|
cashArrived.getOrThrow()
|
||||||
|
assertThat(recipientRpc.getCashBalance(USD) - beforeAmount).isEqualTo(10.DOLLARS)
|
||||||
|
|
||||||
|
return Pair(issuanceTx, paymentTx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExternalVerificationUnsignedCordappsTest {
|
||||||
|
private companion object {
|
||||||
|
private val factory = NodeProcess.Factory(testNetworkParameters(minimumPlatformVersion = MIGRATE_ATTACHMENT_TO_SIGNATURE_CONSTRAINTS))
|
||||||
|
|
||||||
|
private lateinit var notary: NodeProcess
|
||||||
|
private lateinit var oldNode: NodeProcess
|
||||||
|
private lateinit var newNode: NodeProcess
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun startNodes() {
|
||||||
|
// The 4.11 finance CorDapp jars
|
||||||
|
val legacyCordapps = listOf(unsignedResourceJar("corda-finance-contracts-4.11.jar"), smokeTestResource("corda-finance-workflows-4.11.jar"))
|
||||||
|
val legacyCordappsWithoutContracts = listOf(smokeTestResource("corda-finance-workflows-4.11.jar"))
|
||||||
|
// The current version finance CorDapp jars
|
||||||
|
val currentCordapps = listOf(unsignedResourceJar("corda-finance-contracts.jar"), smokeTestResource("corda-finance-workflows.jar"))
|
||||||
|
|
||||||
|
notary = factory.createNotaries(nodeParams(DUMMY_NOTARY_NAME, currentCordapps, legacyCordapps))[0]
|
||||||
|
oldNode = factory.createNode(nodeParams(
|
||||||
|
CordaX500Name("Old", "Delhi", "IN"),
|
||||||
|
legacyCordapps,
|
||||||
|
clientRpcConfig = CordaRPCClientConfiguration(minimumServerProtocolVersion = 13),
|
||||||
|
version = "4.11"
|
||||||
|
))
|
||||||
|
newNode = factory.createNode(nodeParams(CordaX500Name("New", "York", "US"), currentCordapps, legacyCordappsWithoutContracts))
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
@JvmStatic
|
||||||
|
fun close() {
|
||||||
|
factory.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unsignedResourceJar(name: String): Path {
|
||||||
|
val signedJar = smokeTestResource(name)
|
||||||
|
val copy = signedJar.copyTo(Path("${signedJar.toString().substringBeforeLast(".")}-UNSIGNED.jar"), overwrite = true)
|
||||||
|
copy.unsignJar()
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `transactions can fail verification in external verifier`() {
|
||||||
|
val issuerRpc = oldNode.connect(superUser).proxy
|
||||||
|
val recipientRpc = newNode.connect(superUser).proxy
|
||||||
|
val recipientNodeInfo = recipientRpc.nodeInfo()
|
||||||
|
val notaryIdentity = issuerRpc.notaryIdentities()[0]
|
||||||
|
|
||||||
|
val (issuanceTx) = issuerRpc.startFlow(
|
||||||
|
::CashIssueFlow,
|
||||||
|
10.DOLLARS,
|
||||||
|
OpaqueBytes.of(0x01),
|
||||||
|
notaryIdentity
|
||||||
|
).returnValue.getOrThrow()
|
||||||
|
|
||||||
|
issuerRpc.waitForVisibility(recipientNodeInfo)
|
||||||
|
recipientRpc.waitForVisibility(issuerRpc.nodeInfo())
|
||||||
|
|
||||||
|
assertThatExceptionOfType(UnexpectedFlowEndException::class.java).isThrownBy {
|
||||||
|
issuerRpc.startFlow<AbstractCashFlow.Result, Amount<Currency>, Party, Boolean, CashPaymentFlow>(
|
||||||
|
::CashPaymentFlow,
|
||||||
|
10.DOLLARS,
|
||||||
|
recipientNodeInfo.legalIdentities[0],
|
||||||
|
false,
|
||||||
|
).returnValue.getOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(newNode.externalVerifierLogs()).contains("WireTransaction(id=${issuanceTx.id}) failed to verify")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val superUser = User("superUser", "test", permissions = setOf("ALL"))
|
||||||
|
private val portCounter = AtomicInteger(15100)
|
||||||
|
|
||||||
|
private fun smokeTestResource(name: String): Path = ExternalVerificationSignedCordappsTest::class.java.getResource("/$name")!!.toPath()
|
||||||
|
|
||||||
|
private fun nodeParams(
|
||||||
|
legalName: CordaX500Name,
|
||||||
|
cordappJars: List<Path> = emptyList(),
|
||||||
|
legacyContractJars: List<Path> = emptyList(),
|
||||||
|
clientRpcConfig: CordaRPCClientConfiguration = CordaRPCClientConfiguration.DEFAULT,
|
||||||
|
version: String? = null
|
||||||
|
): NodeParams {
|
||||||
|
return NodeParams(
|
||||||
|
legalName = legalName,
|
||||||
|
p2pPort = portCounter.andIncrement,
|
||||||
|
rpcPort = portCounter.andIncrement,
|
||||||
|
rpcAdminPort = portCounter.andIncrement,
|
||||||
|
users = listOf(superUser),
|
||||||
|
cordappJars = cordappJars,
|
||||||
|
legacyContractJars = legacyContractJars,
|
||||||
|
clientRpcConfig = clientRpcConfig,
|
||||||
|
version = version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CordaRPCOps.waitForVisibility(other: NodeInfo) {
|
||||||
|
val (snapshot, updates) = networkMapFeed()
|
||||||
|
if (other in snapshot) {
|
||||||
|
updates.notUsed()
|
||||||
|
} else {
|
||||||
|
updates.waitForFirst { it.node == other }.getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> Observable<T>.waitForFirst(predicate: (T) -> Boolean): CompletableFuture<Unit> {
|
||||||
|
val found = CompletableFuture<Unit>()
|
||||||
|
val subscription = subscribe {
|
||||||
|
if (predicate(it)) {
|
||||||
|
found.complete(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found.whenComplete { _, _ -> subscription.unsubscribe() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NodeProcess.assertTransactionsWereVerified(verificationType: VerificationType, vararg txIds: SecureHash) {
|
||||||
|
val nodeLogs = logContents("node")!!
|
||||||
|
val externalVerifierLogs = externalVerifierLogs()
|
||||||
|
for (txId in txIds) {
|
||||||
|
assertThat(nodeLogs).contains("WireTransaction(id=$txId) will be verified ${verificationType.logStatement}")
|
||||||
|
if (verificationType != VerificationType.IN_PROCESS) {
|
||||||
|
assertThat(externalVerifierLogs).describedAs("External verifier was not started").isNotNull()
|
||||||
|
assertThat(externalVerifierLogs).contains("WireTransaction(id=$txId) verified")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NodeProcess.externalVerifierLogs(): String? = logContents("verifier")
|
||||||
|
|
||||||
|
private fun NodeProcess.logFile(name: String): Path? {
|
||||||
|
return (nodeDir / "logs").listDirectoryEntries("$name-${InetAddress.getLocalHost().hostName}.log").singleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NodeProcess.logContents(name: String): String? = logFile(name)?.readText()
|
||||||
|
|
||||||
|
private enum class VerificationType {
|
||||||
|
IN_PROCESS, EXTERNAL, BOTH;
|
||||||
|
|
||||||
|
val logStatement: String
|
||||||
|
get() = when (this) {
|
||||||
|
IN_PROCESS -> "in-process"
|
||||||
|
EXTERNAL -> "by the external verifer"
|
||||||
|
BOTH -> "both in-process and by the external verifer"
|
||||||
|
}
|
||||||
|
}
|
@ -56,8 +56,8 @@ class AmountTests {
|
|||||||
val splits = baseAmount.splitEvenly(partitionCount)
|
val splits = baseAmount.splitEvenly(partitionCount)
|
||||||
assertEquals(partitionCount, splits.size)
|
assertEquals(partitionCount, splits.size)
|
||||||
assertEquals(baseAmount, splits.sumOrZero(baseAmount.token))
|
assertEquals(baseAmount, splits.sumOrZero(baseAmount.token))
|
||||||
val min = splits.min()!!
|
val min = splits.min()
|
||||||
val max = splits.max()!!
|
val max = splits.max()
|
||||||
assertTrue(max.quantity - min.quantity <= 1L, "Amount quantities should differ by at most one token")
|
assertTrue(max.quantity - min.quantity <= 1L, "Amount quantities should differ by at most one token")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package net.corda.coretests.contracts
|
package net.corda.coretests.contracts
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint
|
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint
|
||||||
import net.corda.core.contracts.AutomaticPlaceholderConstraint
|
import net.corda.core.contracts.AutomaticPlaceholderConstraint
|
||||||
import net.corda.core.contracts.BelongsToContract
|
import net.corda.core.contracts.BelongsToContract
|
||||||
@ -26,17 +23,16 @@ import net.corda.core.crypto.sign
|
|||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.canBeTransitionedFrom
|
import net.corda.core.internal.canBeTransitionedFrom
|
||||||
import net.corda.core.internal.inputStream
|
import net.corda.core.internal.read
|
||||||
import net.corda.core.internal.requireSupportedHashType
|
import net.corda.core.internal.requireSupportedHashType
|
||||||
import net.corda.core.internal.toPath
|
|
||||||
import net.corda.core.node.NotaryInfo
|
import net.corda.core.node.NotaryInfo
|
||||||
import net.corda.core.node.services.IdentityService
|
import net.corda.core.node.services.IdentityService
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.finance.POUNDS
|
import net.corda.finance.POUNDS
|
||||||
import net.corda.finance.`issued by`
|
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.`issued by`
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
@ -48,7 +44,15 @@ import net.corda.testing.core.internal.SelfCleaningDir
|
|||||||
import net.corda.testing.internal.MockCordappProvider
|
import net.corda.testing.internal.MockCordappProvider
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.ledger
|
import net.corda.testing.node.ledger
|
||||||
import org.junit.*
|
import org.junit.AfterClass
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.BeforeClass
|
||||||
|
import org.junit.Ignore
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.jar.Attributes
|
import java.util.jar.Attributes
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
@ -103,8 +107,8 @@ class ConstraintsPropagationTests {
|
|||||||
},
|
},
|
||||||
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
networkParameters = testNetworkParameters(minimumPlatformVersion = 4)
|
||||||
.copy(whitelistedContractImplementations = mapOf(
|
.copy(whitelistedContractImplementations = mapOf(
|
||||||
Cash.PROGRAM_ID to listOf(SecureHash.zeroHash, SecureHash.allOnesHash),
|
Cash.PROGRAM_ID to listOf(zeroHash, allOnesHash),
|
||||||
noPropagationContractClassName to listOf(SecureHash.zeroHash)),
|
noPropagationContractClassName to listOf(zeroHash)),
|
||||||
notaries = listOf(NotaryInfo(DUMMY_NOTARY, true)))
|
notaries = listOf(NotaryInfo(DUMMY_NOTARY, true)))
|
||||||
) {
|
) {
|
||||||
override fun loadContractAttachment(stateRef: StateRef) = servicesForResolution.loadContractAttachment(stateRef)
|
override fun loadContractAttachment(stateRef: StateRef) = servicesForResolution.loadContractAttachment(stateRef)
|
||||||
@ -115,13 +119,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Happy path with the HashConstraint`() {
|
fun `Happy path with the HashConstraint`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash)
|
attachment(Cash.PROGRAM_ID, allOnesHash)
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash)
|
attachment(Cash.PROGRAM_ID, allOnesHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -137,13 +141,13 @@ class ConstraintsPropagationTests {
|
|||||||
val cordappAttachmentIds =
|
val cordappAttachmentIds =
|
||||||
cordapps.map { cordapp ->
|
cordapps.map { cordapp ->
|
||||||
val unsignedAttId =
|
val unsignedAttId =
|
||||||
cordapp.jarPath.toPath().inputStream().use { unsignedJarStream ->
|
cordapp.jarPath.openStream().use { unsignedJarStream ->
|
||||||
ledgerServices.attachments.importContractAttachment(cordapp.contractClassNames, "rpc", unsignedJarStream, null)
|
ledgerServices.attachments.importContractAttachment(cordapp.contractClassNames, "rpc", unsignedJarStream, null)
|
||||||
}
|
}
|
||||||
val jarAndSigner = ContractJarTestUtils.signContractJar(cordapp.jarPath, copyFirst = true, keyStoreDir = keyStoreDir.path)
|
val jarAndSigner = ContractJarTestUtils.signContractJar(cordapp.jarPath, copyFirst = true, keyStoreDir = keyStoreDir.path)
|
||||||
val signedJar = jarAndSigner.first
|
val signedJar = jarAndSigner.first
|
||||||
val signedAttId =
|
val signedAttId =
|
||||||
signedJar.inputStream().use { signedJarStream ->
|
signedJar.read { signedJarStream ->
|
||||||
ledgerServices.attachments.importContractAttachment(cordapp.contractClassNames, "rpc", signedJarStream, null, listOf(jarAndSigner.second))
|
ledgerServices.attachments.importContractAttachment(cordapp.contractClassNames, "rpc", signedJarStream, null, listOf(jarAndSigner.second))
|
||||||
}
|
}
|
||||||
Pair(unsignedAttId, signedAttId)
|
Pair(unsignedAttId, signedAttId)
|
||||||
@ -175,14 +179,14 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Fail early in the TransactionBuilder when attempting to change the hash of the HashConstraint on the spending transaction`() {
|
fun `Fail early in the TransactionBuilder when attempting to change the hash of the HashConstraint on the spending transaction`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash)
|
attachment(Cash.PROGRAM_ID, allOnesHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(allOnesHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -196,27 +200,27 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Transaction validation fails, when constraints do not propagate correctly`() {
|
fun `Transaction validation fails, when constraints do not propagate correctly`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
failsWith("are not propagated correctly")
|
failsWith("are not propagated correctly")
|
||||||
})
|
})
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c3", DUMMY_NOTARY, null, SignatureAttachmentConstraint(ALICE_PUBKEY), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c3", DUMMY_NOTARY, null, SignatureAttachmentConstraint(ALICE_PUBKEY), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
fails()
|
fails()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c4", DUMMY_NOTARY, null, AlwaysAcceptAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c4", DUMMY_NOTARY, null, AlwaysAcceptAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -229,13 +233,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `When the constraint of the output state is a valid transition from the input state, transaction validation works`() {
|
fun `When the constraint of the output state is a valid transition from the input state, transaction validation works`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -249,7 +253,7 @@ class ConstraintsPropagationTests {
|
|||||||
|
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
output(Cash.PROGRAM_ID, "w1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "w1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
@ -257,7 +261,7 @@ class ConstraintsPropagationTests {
|
|||||||
|
|
||||||
// the attachment is signed
|
// the attachment is signed
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey))
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey))
|
||||||
input("w1")
|
input("w1")
|
||||||
output(Cash.PROGRAM_ID, "w2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "w2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -270,14 +274,14 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Switching from the WhitelistConstraint to the Signature Constraint fails if the signature constraint does not inherit all jar signatures`() {
|
fun `Switching from the WhitelistConstraint to the Signature Constraint fails if the signature constraint does not inherit all jar signatures`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
output(Cash.PROGRAM_ID, "w1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "w1", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
// the attachment is not signed
|
// the attachment is not signed
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash)
|
attachment(Cash.PROGRAM_ID, zeroHash)
|
||||||
input("w1")
|
input("w1")
|
||||||
output(Cash.PROGRAM_ID, "w2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(ALICE_PUBKEY), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "w2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(ALICE_PUBKEY), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -291,13 +295,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `On contract annotated with NoConstraintPropagation there is no platform check for propagation, but the transaction builder can't use the AutomaticPlaceholderConstraint`() {
|
fun `On contract annotated with NoConstraintPropagation there is no platform check for propagation, but the transaction builder can't use the AutomaticPlaceholderConstraint`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(noPropagationContractClassName, SecureHash.zeroHash)
|
attachment(noPropagationContractClassName, zeroHash)
|
||||||
output(noPropagationContractClassName, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), NoPropagationContractState())
|
output(noPropagationContractClassName, "c1", DUMMY_NOTARY, null, HashAttachmentConstraint(zeroHash), NoPropagationContractState())
|
||||||
command(ALICE_PUBKEY, NoPropagationContract.Create())
|
command(ALICE_PUBKEY, NoPropagationContract.Create())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(noPropagationContractClassName, SecureHash.zeroHash)
|
attachment(noPropagationContractClassName, zeroHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(noPropagationContractClassName, "c2", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, NoPropagationContractState())
|
output(noPropagationContractClassName, "c2", DUMMY_NOTARY, null, WhitelistedByZoneAttachmentConstraint, NoPropagationContractState())
|
||||||
command(ALICE_PUBKEY, NoPropagationContract.Create())
|
command(ALICE_PUBKEY, NoPropagationContract.Create())
|
||||||
@ -305,7 +309,7 @@ class ConstraintsPropagationTests {
|
|||||||
})
|
})
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
transaction {
|
transaction {
|
||||||
attachment(noPropagationContractClassName, SecureHash.zeroHash)
|
attachment(noPropagationContractClassName, zeroHash)
|
||||||
input("c1")
|
input("c1")
|
||||||
output(noPropagationContractClassName, "c3", DUMMY_NOTARY, null, AutomaticPlaceholderConstraint, NoPropagationContractState())
|
output(noPropagationContractClassName, "c3", DUMMY_NOTARY, null, AutomaticPlaceholderConstraint, NoPropagationContractState())
|
||||||
command(ALICE_PUBKEY, NoPropagationContract.Create())
|
command(ALICE_PUBKEY, NoPropagationContract.Create())
|
||||||
@ -400,13 +404,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Input state contract version may be incompatible with lower version`() {
|
fun `Input state contract version may be incompatible with lower version`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1"))
|
attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1"))
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -419,13 +423,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Input state contract version is compatible with the same version`() {
|
fun `Input state contract version is compatible with the same version`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3"))
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3"))
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3"))
|
attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "3"))
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -438,13 +442,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Input state contract version is compatible with higher version`() {
|
fun `Input state contract version is compatible with higher version`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1"))
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1"))
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -457,13 +461,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Input states contract version may be lower that current contract version`() {
|
fun `Input states contract version may be lower that current contract version`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1"))
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "1"))
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
@ -482,13 +486,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Input state with contract version can be downgraded to no version`() {
|
fun `Input state with contract version can be downgraded to no version`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), emptyMap())
|
attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), emptyMap())
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
@ -501,13 +505,13 @@ class ConstraintsPropagationTests {
|
|||||||
fun `Input state without contract version is compatible with any version`() {
|
fun `Input state without contract version is compatible with any version`() {
|
||||||
ledgerServices.ledger(DUMMY_NOTARY) {
|
ledgerServices.ledger(DUMMY_NOTARY) {
|
||||||
ledgerServices.recordTransaction(transaction {
|
ledgerServices.recordTransaction(transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.allOnesHash, listOf(hashToSignatureConstraintsKey), emptyMap())
|
attachment(Cash.PROGRAM_ID, allOnesHash, listOf(hashToSignatureConstraintsKey), emptyMap())
|
||||||
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
output(Cash.PROGRAM_ID, "c1", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), ALICE_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
command(ALICE_PUBKEY, Cash.Commands.Issue())
|
||||||
verifies()
|
verifies()
|
||||||
})
|
})
|
||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID, SecureHash.zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
attachment(Cash.PROGRAM_ID, zeroHash, listOf(hashToSignatureConstraintsKey), mapOf(Attributes.Name.IMPLEMENTATION_VERSION.toString() to "2"))
|
||||||
input("c1")
|
input("c1")
|
||||||
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
output(Cash.PROGRAM_ID, "c2", DUMMY_NOTARY, null, SignatureAttachmentConstraint(hashToSignatureConstraintsKey), Cash.State(1000.POUNDS `issued by` ALICE_PARTY.ref(1), BOB_PARTY))
|
||||||
command(ALICE_PUBKEY, Cash.Commands.Move())
|
command(ALICE_PUBKEY, Cash.Commands.Move())
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package net.corda.coretests.contracts
|
package net.corda.coretests.contracts
|
||||||
|
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.CommandData
|
||||||
|
import net.corda.core.contracts.CommandWithParties
|
||||||
|
import net.corda.core.contracts.TypeOnlyCommandData
|
||||||
|
import net.corda.core.contracts.requireSingleCommand
|
||||||
|
import net.corda.core.contracts.select
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
import org.assertj.core.api.Assertions
|
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||||
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
@ -35,8 +40,8 @@ class RequireSingleCommandTests(private val testFunction: (Collection<CommandWit
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Parameterized.Parameters(name = "{1}")
|
@Parameterized.Parameters(name = "{1}")
|
||||||
fun data(): Collection<Array<Any>> = listOf(
|
fun data(): Collection<Array<Any>> = listOf(
|
||||||
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>> -> commands.requireSingleCommand<TestCommands>() }, "Inline version"),
|
arrayOf({ commands: Collection<CommandWithParties<CommandData>> -> commands.requireSingleCommand<TestCommands>() }, "Inline version"),
|
||||||
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>> -> commands.requireSingleCommand(TestCommands::class.java) }, "Interop version")
|
arrayOf({ commands: Collection<CommandWithParties<CommandData>> -> commands.requireSingleCommand(TestCommands::class.java) }, "Interop version")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,16 +52,18 @@ class RequireSingleCommandTests(private val testFunction: (Collection<CommandWit
|
|||||||
assertEquals(returnedCommand, validCommandOne, "they should be the same")
|
assertEquals(returnedCommand, validCommandOne, "they should be the same")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class, timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `check error is thrown if more than one valid command`() {
|
fun `check error is thrown if more than one valid command`() {
|
||||||
val commands = listOf(validCommandOne, validCommandTwo)
|
val commands = listOf(validCommandOne, validCommandTwo)
|
||||||
|
assertThatIllegalArgumentException().isThrownBy {
|
||||||
testFunction(commands)
|
testFunction(commands)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `check error is thrown when command is of wrong type`() {
|
fun `check error is thrown when command is of wrong type`() {
|
||||||
val commands = listOf(invalidCommand)
|
val commands = listOf(invalidCommand)
|
||||||
Assertions.assertThatThrownBy { testFunction(commands) }
|
assertThatThrownBy { testFunction(commands) }
|
||||||
.isInstanceOf(IllegalStateException::class.java)
|
.isInstanceOf(IllegalStateException::class.java)
|
||||||
.hasMessage("Required net.corda.coretests.contracts.TestCommands command")
|
.hasMessage("Required net.corda.coretests.contracts.TestCommands command")
|
||||||
}
|
}
|
||||||
@ -69,8 +76,8 @@ class SelectWithSingleInputsTests(private val testFunction: (Collection<CommandW
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Parameterized.Parameters(name = "{1}")
|
@Parameterized.Parameters(name = "{1}")
|
||||||
fun data(): Collection<Array<Any>> = listOf(
|
fun data(): Collection<Array<Any>> = listOf(
|
||||||
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signer: PublicKey?, party: AbstractParty? -> commands.select<TestCommands>(signer, party) }, "Inline version"),
|
arrayOf({ commands: Collection<CommandWithParties<CommandData>>, signer: PublicKey?, party: AbstractParty? -> commands.select<TestCommands>(signer, party) }, "Inline version"),
|
||||||
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signer: PublicKey?, party: AbstractParty? -> commands.select(TestCommands::class.java, signer, party) }, "Interop version")
|
arrayOf({ commands: Collection<CommandWithParties<CommandData>>, signer: PublicKey?, party: AbstractParty? -> commands.select(TestCommands::class.java, signer, party) }, "Interop version")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +125,8 @@ class SelectWithMultipleInputsTests(private val testFunction: (Collection<Comman
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Parameterized.Parameters(name = "{1}")
|
@Parameterized.Parameters(name = "{1}")
|
||||||
fun data(): Collection<Array<Any>> = listOf(
|
fun data(): Collection<Array<Any>> = listOf(
|
||||||
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signers: Collection<PublicKey>?, party: Collection<Party>? -> commands.select<TestCommands>(signers, party) }, "Inline version"),
|
arrayOf({ commands: Collection<CommandWithParties<CommandData>>, signers: Collection<PublicKey>?, party: Collection<Party>? -> commands.select<TestCommands>(signers, party) }, "Inline version"),
|
||||||
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signers: Collection<PublicKey>?, party: Collection<Party>? -> commands.select(TestCommands::class.java, signers, party) }, "Interop version")
|
arrayOf({ commands: Collection<CommandWithParties<CommandData>>, signers: Collection<PublicKey>?, party: Collection<Party>? -> commands.select(TestCommands::class.java, signers, party) }, "Interop version")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.coretests.contracts
|
package net.corda.coretests.contracts
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
@ -1,31 +1,16 @@
|
|||||||
package net.corda.coretests.contracts
|
package net.corda.coretests.contracts
|
||||||
|
|
||||||
import net.corda.core.contracts.CordaRotatedKeys
|
|
||||||
import net.corda.core.contracts.RotatedKeys
|
import net.corda.core.contracts.RotatedKeys
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.identity.CordaX500Name
|
|
||||||
import net.corda.core.internal.hash
|
import net.corda.core.internal.hash
|
||||||
import net.corda.core.internal.retrieveRotatedKeys
|
|
||||||
import net.corda.core.node.ServiceHub
|
|
||||||
import net.corda.testing.core.TestIdentity
|
|
||||||
import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey
|
import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey
|
||||||
import net.corda.testing.core.internal.SelfCleaningDir
|
import net.corda.testing.core.internal.SelfCleaningDir
|
||||||
import net.corda.testing.node.MockServices
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class RotatedKeysTest {
|
class RotatedKeysTest {
|
||||||
|
|
||||||
@Test(timeout = 300_000)
|
|
||||||
fun `validateDefaultRotatedKeysAreRetrievableFromMockServices`() {
|
|
||||||
val services: ServiceHub = MockServices(TestIdentity(CordaX500Name("MegaCorp", "London", "GB")))
|
|
||||||
val rotatedKeys = services.retrieveRotatedKeys()
|
|
||||||
assertEquals( CordaRotatedKeys.keys.rotatedSigningKeys, rotatedKeys.rotatedSigningKeys)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(timeout = 300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `when input and output keys are the same canBeTransitioned returns true`() {
|
fun `when input and output keys are the same canBeTransitioned returns true`() {
|
||||||
SelfCleaningDir().use { file ->
|
SelfCleaningDir().use { file ->
|
||||||
|
@ -3,7 +3,6 @@ package net.corda.coretests.crypto
|
|||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.CompositeKey.NodeAndWeight
|
import net.corda.core.crypto.CompositeKey.NodeAndWeight
|
||||||
import net.corda.core.internal.declaredField
|
import net.corda.core.internal.declaredField
|
||||||
import net.corda.core.internal.div
|
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.toBase58String
|
import net.corda.core.utilities.toBase58String
|
||||||
@ -19,6 +18,7 @@ import org.junit.Test
|
|||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import javax.security.auth.x500.X500Principal
|
import javax.security.auth.x500.X500Principal
|
||||||
|
import kotlin.io.path.div
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
@ -295,21 +295,19 @@ class CompositeKeyTests {
|
|||||||
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||||
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||||
val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||||
val keyPairSP = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
|
||||||
|
|
||||||
val RSASignature = keyPairRSA.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairRSA.public).schemeNumberID)))
|
val RSASignature = keyPairRSA.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairRSA.public).schemeNumberID)))
|
||||||
val K1Signature = keyPairK1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairK1.public).schemeNumberID)))
|
val K1Signature = keyPairK1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairK1.public).schemeNumberID)))
|
||||||
val R1Signature = keyPairR1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairR1.public).schemeNumberID)))
|
val R1Signature = keyPairR1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairR1.public).schemeNumberID)))
|
||||||
val EdSignature = keyPairEd.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairEd.public).schemeNumberID)))
|
val EdSignature = keyPairEd.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairEd.public).schemeNumberID)))
|
||||||
val SPSignature = keyPairSP.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairSP.public).schemeNumberID)))
|
|
||||||
|
|
||||||
val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public, keyPairSP.public).build() as CompositeKey
|
val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public).build() as CompositeKey
|
||||||
|
|
||||||
val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature, SPSignature)
|
val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature)
|
||||||
assertTrue { compositeKey.isFulfilledBy(signatures.byKeys()) }
|
assertTrue { compositeKey.isFulfilledBy(signatures.byKeys()) }
|
||||||
|
|
||||||
// One signature is missing.
|
// One signature is missing.
|
||||||
val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature, SPSignature)
|
val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature)
|
||||||
assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) }
|
assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,20 +318,18 @@ class CompositeKeyTests {
|
|||||||
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
val keyPairK1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||||
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
val keyPairR1 = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||||
val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
val keyPairEd = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||||
val keyPairSP = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
|
||||||
|
|
||||||
val RSASignature = keyPairRSA.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairRSA.public).schemeNumberID)))
|
val RSASignature = keyPairRSA.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairRSA.public).schemeNumberID)))
|
||||||
val K1Signature = keyPairK1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairK1.public).schemeNumberID)))
|
val K1Signature = keyPairK1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairK1.public).schemeNumberID)))
|
||||||
val R1Signature = keyPairR1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairR1.public).schemeNumberID)))
|
val R1Signature = keyPairR1.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairR1.public).schemeNumberID)))
|
||||||
val EdSignature = keyPairEd.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairEd.public).schemeNumberID)))
|
val EdSignature = keyPairEd.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairEd.public).schemeNumberID)))
|
||||||
val SPSignature = keyPairSP.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(keyPairSP.public).schemeNumberID)))
|
|
||||||
|
|
||||||
val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public, keyPairSP.public).build() as CompositeKey
|
val compositeKey = CompositeKey.Builder().addKeys(keyPairRSA.public, keyPairK1.public, keyPairR1.public, keyPairEd.public).build() as CompositeKey
|
||||||
|
|
||||||
val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature, SPSignature)
|
val signatures = listOf(RSASignature, K1Signature, R1Signature, EdSignature)
|
||||||
assertTrue { compositeKey.isFulfilledBy(signatures.byKeys()) }
|
assertTrue { compositeKey.isFulfilledBy(signatures.byKeys()) }
|
||||||
// One signature is missing.
|
// One signature is missing.
|
||||||
val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature, SPSignature)
|
val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature)
|
||||||
assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) }
|
assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) }
|
||||||
|
|
||||||
// Create self sign CA.
|
// Create self sign CA.
|
||||||
@ -374,13 +370,12 @@ class CompositeKeyTests {
|
|||||||
val (_, pub3) = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
val (_, pub3) = Crypto.generateKeyPair(Crypto.RSA_SHA256)
|
||||||
val (_, pub4) = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
val (_, pub4) = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
|
||||||
val (_, pub5) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
val (_, pub5) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||||
val (_, pub6) = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
|
val (_, pub6) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
||||||
val (_, pub7) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
|
|
||||||
|
|
||||||
// Using default weight = 1, thus all weights are equal.
|
// Using default weight = 1, thus all weights are equal.
|
||||||
val composite1 = CompositeKey.Builder().addKeys(pub1, pub2, pub3, pub4, pub5, pub6, pub7).build() as CompositeKey
|
val composite1 = CompositeKey.Builder().addKeys(pub1, pub2, pub3, pub4, pub5, pub6).build() as CompositeKey
|
||||||
// Store in reverse order.
|
// Store in reverse order.
|
||||||
val composite2 = CompositeKey.Builder().addKeys(pub7, pub6, pub5, pub4, pub3, pub2, pub1).build() as CompositeKey
|
val composite2 = CompositeKey.Builder().addKeys(pub6, pub5, pub4, pub3, pub2, pub1).build() as CompositeKey
|
||||||
// There are 7! = 5040 permutations, but as sorting is deterministic the following should never fail.
|
// There are 7! = 5040 permutations, but as sorting is deterministic the following should never fail.
|
||||||
assertEquals(composite1.children, composite2.children)
|
assertEquals(composite1.children, composite2.children)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
package net.corda.coretests.crypto
|
package net.corda.coretests.crypto
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
import net.corda.core.contracts.Command
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
import net.corda.core.contracts.PrivacySalt
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.TimeWindow
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.contracts.TransactionState
|
||||||
|
import net.corda.core.crypto.DigestService
|
||||||
|
import net.corda.core.crypto.MerkleTree
|
||||||
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
|
import net.corda.core.crypto.PartialMerkleTree
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.internal.DigestAlgorithmFactory
|
import net.corda.core.crypto.internal.DigestAlgorithmFactory
|
||||||
|
import net.corda.core.crypto.keys
|
||||||
|
import net.corda.core.crypto.randomHash
|
||||||
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.BLAKE2s256DigestAlgorithm
|
import net.corda.core.internal.BLAKE2s256DigestAlgorithm
|
||||||
@ -16,9 +24,10 @@ import net.corda.core.serialization.deserialize
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.transactions.ReferenceStateRef
|
import net.corda.core.transactions.ReferenceStateRef
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
|
import net.corda.coretesting.internal.TEST_TX_TIME
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
import net.corda.finance.`issued by`
|
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.`issued by`
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
@ -26,20 +35,29 @@ import net.corda.testing.core.TestIdentity
|
|||||||
import net.corda.testing.dsl.LedgerDSL
|
import net.corda.testing.dsl.LedgerDSL
|
||||||
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
||||||
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
||||||
import net.corda.coretesting.internal.TEST_TX_TIME
|
|
||||||
import net.corda.testing.internal.createWireTransaction
|
import net.corda.testing.internal.createWireTransaction
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.ledger
|
import net.corda.testing.node.ledger
|
||||||
|
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import java.util.stream.IntStream
|
import java.util.stream.IntStream
|
||||||
import kotlin.streams.toList
|
import kotlin.streams.toList
|
||||||
import kotlin.test.*
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@RunWith(Parameterized::class)
|
@RunWith(Parameterized::class)
|
||||||
class PartialMerkleTreeTest(private var digestService: DigestService) {
|
class PartialMerkleTreeTest(private var digestService: DigestService) {
|
||||||
@ -204,7 +222,7 @@ class PartialMerkleTreeTest(private var digestService: DigestService) {
|
|||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `nothing filtered`() {
|
fun `nothing filtered`() {
|
||||||
val ftxNothing = testTx.buildFilteredTransaction(Predicate { false })
|
val ftxNothing = testTx.buildFilteredTransaction { false }
|
||||||
assertTrue(ftxNothing.componentGroups.isEmpty())
|
assertTrue(ftxNothing.componentGroups.isEmpty())
|
||||||
assertTrue(ftxNothing.attachments.isEmpty())
|
assertTrue(ftxNothing.attachments.isEmpty())
|
||||||
assertTrue(ftxNothing.commands.isEmpty())
|
assertTrue(ftxNothing.commands.isEmpty())
|
||||||
@ -291,11 +309,13 @@ class PartialMerkleTreeTest(private var digestService: DigestService) {
|
|||||||
assertFalse(pmt.verify(wrongRoot, inclHashes))
|
assertFalse(pmt.verify(wrongRoot, inclHashes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = Exception::class, timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `hash map serialization not allowed`() {
|
fun `hash map serialization not allowed`() {
|
||||||
val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4)
|
val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4)
|
||||||
|
assertThatIllegalArgumentException().isThrownBy {
|
||||||
hm1.serialize()
|
hm1.serialize()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun makeSimpleCashWtx(
|
private fun makeSimpleCashWtx(
|
||||||
notary: Party,
|
notary: Party,
|
||||||
@ -322,11 +342,11 @@ class PartialMerkleTreeTest(private var digestService: DigestService) {
|
|||||||
val merkleTree = MerkleTree.getMerkleTree(sampleLeaves, digestService)
|
val merkleTree = MerkleTree.getMerkleTree(sampleLeaves, digestService)
|
||||||
|
|
||||||
// Provided hashes are not in the tree.
|
// Provided hashes are not in the tree.
|
||||||
assertFailsWith<MerkleTreeException> { PartialMerkleTree.build(merkleTree, listOf<SecureHash>(digestService.hash("20"))) }
|
assertFailsWith<MerkleTreeException> { PartialMerkleTree.build(merkleTree, listOf(digestService.hash("20"))) }
|
||||||
// One of the provided hashes is not in the tree.
|
// One of the provided hashes is not in the tree.
|
||||||
assertFailsWith<MerkleTreeException> { PartialMerkleTree.build(merkleTree, listOf<SecureHash>(digestService.hash("20"), digestService.hash("1"), digestService.hash("5"))) }
|
assertFailsWith<MerkleTreeException> { PartialMerkleTree.build(merkleTree, listOf(digestService.hash("20"), digestService.hash("1"), digestService.hash("5"))) }
|
||||||
|
|
||||||
val pmt = PartialMerkleTree.build(merkleTree, listOf<SecureHash>(digestService.hash("1"), digestService.hash("5"), digestService.hash("0"), digestService.hash("19")))
|
val pmt = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("1"), digestService.hash("5"), digestService.hash("0"), digestService.hash("19")))
|
||||||
// First leaf.
|
// First leaf.
|
||||||
assertEquals(0, pmt.leafIndex(digestService.hash("0")))
|
assertEquals(0, pmt.leafIndex(digestService.hash("0")))
|
||||||
// Second leaf.
|
// Second leaf.
|
||||||
@ -340,17 +360,17 @@ class PartialMerkleTreeTest(private var digestService: DigestService) {
|
|||||||
// The provided hash is not in the tree (using a leaf that didn't exist in the original Merkle tree).
|
// The provided hash is not in the tree (using a leaf that didn't exist in the original Merkle tree).
|
||||||
assertFailsWith<MerkleTreeException> { pmt.leafIndex(digestService.hash("30")) }
|
assertFailsWith<MerkleTreeException> { pmt.leafIndex(digestService.hash("30")) }
|
||||||
|
|
||||||
val pmtFirstElementOnly = PartialMerkleTree.build(merkleTree, listOf<SecureHash>(digestService.hash("0")))
|
val pmtFirstElementOnly = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("0")))
|
||||||
assertEquals(0, pmtFirstElementOnly.leafIndex(digestService.hash("0")))
|
assertEquals(0, pmtFirstElementOnly.leafIndex(digestService.hash("0")))
|
||||||
// The provided hash is not in the tree.
|
// The provided hash is not in the tree.
|
||||||
assertFailsWith<MerkleTreeException> { pmtFirstElementOnly.leafIndex(digestService.hash("10")) }
|
assertFailsWith<MerkleTreeException> { pmtFirstElementOnly.leafIndex(digestService.hash("10")) }
|
||||||
|
|
||||||
val pmtLastElementOnly = PartialMerkleTree.build(merkleTree, listOf<SecureHash>(digestService.hash("19")))
|
val pmtLastElementOnly = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("19")))
|
||||||
assertEquals(19, pmtLastElementOnly.leafIndex(digestService.hash("19")))
|
assertEquals(19, pmtLastElementOnly.leafIndex(digestService.hash("19")))
|
||||||
// The provided hash is not in the tree.
|
// The provided hash is not in the tree.
|
||||||
assertFailsWith<MerkleTreeException> { pmtLastElementOnly.leafIndex(digestService.hash("10")) }
|
assertFailsWith<MerkleTreeException> { pmtLastElementOnly.leafIndex(digestService.hash("10")) }
|
||||||
|
|
||||||
val pmtOneElement = PartialMerkleTree.build(merkleTree, listOf<SecureHash>(digestService.hash("5")))
|
val pmtOneElement = PartialMerkleTree.build(merkleTree, listOf(digestService.hash("5")))
|
||||||
assertEquals(5, pmtOneElement.leafIndex(digestService.hash("5")))
|
assertEquals(5, pmtOneElement.leafIndex(digestService.hash("5")))
|
||||||
// The provided hash is not in the tree.
|
// The provided hash is not in the tree.
|
||||||
assertFailsWith<MerkleTreeException> { pmtOneElement.leafIndex(digestService.hash("10")) }
|
assertFailsWith<MerkleTreeException> { pmtOneElement.leafIndex(digestService.hash("10")) }
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
package net.corda.coretests.crypto
|
package net.corda.coretests.crypto
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import net.corda.core.contracts.Command
|
import net.corda.core.contracts.Command
|
||||||
import net.corda.core.contracts.PrivacySalt
|
import net.corda.core.contracts.PrivacySalt
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.TimeWindow
|
import net.corda.core.contracts.TimeWindow
|
||||||
import net.corda.core.contracts.TransactionState
|
import net.corda.core.contracts.TransactionState
|
||||||
|
import net.corda.core.crypto.DigestService
|
||||||
import net.corda.core.crypto.MerkleTree
|
import net.corda.core.crypto.MerkleTree
|
||||||
import net.corda.core.crypto.MerkleTreeException
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
import net.corda.core.crypto.PartialMerkleTree
|
import net.corda.core.crypto.PartialMerkleTree
|
||||||
import net.corda.core.crypto.DigestService
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SecureHash.Companion.SHA2_384
|
import net.corda.core.crypto.SecureHash.Companion.SHA2_384
|
||||||
import net.corda.core.crypto.SecureHash.Companion.hashAs
|
import net.corda.core.crypto.SecureHash.Companion.hashAs
|
||||||
@ -26,9 +23,10 @@ import net.corda.core.serialization.serialize
|
|||||||
import net.corda.core.transactions.ReferenceStateRef
|
import net.corda.core.transactions.ReferenceStateRef
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.coretesting.internal.TEST_TX_TIME
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
import net.corda.finance.`issued by`
|
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.`issued by`
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
@ -36,10 +34,10 @@ import net.corda.testing.core.TestIdentity
|
|||||||
import net.corda.testing.dsl.LedgerDSL
|
import net.corda.testing.dsl.LedgerDSL
|
||||||
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
||||||
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
||||||
import net.corda.coretesting.internal.TEST_TX_TIME
|
|
||||||
import net.corda.testing.internal.createWireTransaction
|
import net.corda.testing.internal.createWireTransaction
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.ledger
|
import net.corda.testing.node.ledger
|
||||||
|
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertNotEquals
|
import org.junit.Assert.assertNotEquals
|
||||||
import org.junit.Assert.assertNotNull
|
import org.junit.Assert.assertNotNull
|
||||||
@ -49,6 +47,9 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import java.util.stream.IntStream
|
import java.util.stream.IntStream
|
||||||
@ -209,7 +210,7 @@ class PartialMerkleTreeWithNamedHashMultiAlgTreeTest {
|
|||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `nothing filtered`() {
|
fun `nothing filtered`() {
|
||||||
val ftxNothing = testTx.buildFilteredTransaction(Predicate { false })
|
val ftxNothing = testTx.buildFilteredTransaction { false }
|
||||||
assertTrue(ftxNothing.componentGroups.isEmpty())
|
assertTrue(ftxNothing.componentGroups.isEmpty())
|
||||||
assertTrue(ftxNothing.attachments.isEmpty())
|
assertTrue(ftxNothing.attachments.isEmpty())
|
||||||
assertTrue(ftxNothing.commands.isEmpty())
|
assertTrue(ftxNothing.commands.isEmpty())
|
||||||
@ -296,11 +297,13 @@ class PartialMerkleTreeWithNamedHashMultiAlgTreeTest {
|
|||||||
assertFalse(pmt.verify(wrongRoot, inclHashes))
|
assertFalse(pmt.verify(wrongRoot, inclHashes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = Exception::class, timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `hash map serialization not allowed`() {
|
fun `hash map serialization not allowed`() {
|
||||||
val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4)
|
val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4)
|
||||||
|
assertThatIllegalArgumentException().isThrownBy {
|
||||||
hm1.serialize()
|
hm1.serialize()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun makeSimpleCashWtx(
|
private fun makeSimpleCashWtx(
|
||||||
notary: Party,
|
notary: Party,
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
package net.corda.coretests.crypto
|
package net.corda.coretests.crypto
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import net.corda.core.contracts.Command
|
import net.corda.core.contracts.Command
|
||||||
import net.corda.core.contracts.PrivacySalt
|
import net.corda.core.contracts.PrivacySalt
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.TimeWindow
|
import net.corda.core.contracts.TimeWindow
|
||||||
import net.corda.core.contracts.TransactionState
|
import net.corda.core.contracts.TransactionState
|
||||||
|
import net.corda.core.crypto.DigestService
|
||||||
import net.corda.core.crypto.MerkleTree
|
import net.corda.core.crypto.MerkleTree
|
||||||
import net.corda.core.crypto.MerkleTreeException
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
import net.corda.core.crypto.PartialMerkleTree
|
import net.corda.core.crypto.PartialMerkleTree
|
||||||
import net.corda.core.crypto.DigestService
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SecureHash.Companion.SHA2_384
|
import net.corda.core.crypto.SecureHash.Companion.SHA2_384
|
||||||
import net.corda.core.crypto.SecureHash.Companion.hashAs
|
import net.corda.core.crypto.SecureHash.Companion.hashAs
|
||||||
@ -26,9 +23,10 @@ import net.corda.core.serialization.serialize
|
|||||||
import net.corda.core.transactions.ReferenceStateRef
|
import net.corda.core.transactions.ReferenceStateRef
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
|
import net.corda.coretesting.internal.TEST_TX_TIME
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
import net.corda.finance.`issued by`
|
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.`issued by`
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
@ -36,10 +34,10 @@ import net.corda.testing.core.TestIdentity
|
|||||||
import net.corda.testing.dsl.LedgerDSL
|
import net.corda.testing.dsl.LedgerDSL
|
||||||
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
||||||
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
||||||
import net.corda.coretesting.internal.TEST_TX_TIME
|
|
||||||
import net.corda.testing.internal.createWireTransaction
|
import net.corda.testing.internal.createWireTransaction
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.ledger
|
import net.corda.testing.node.ledger
|
||||||
|
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertNotEquals
|
import org.junit.Assert.assertNotEquals
|
||||||
import org.junit.Assert.assertNotNull
|
import org.junit.Assert.assertNotNull
|
||||||
@ -49,6 +47,9 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import java.util.stream.IntStream
|
import java.util.stream.IntStream
|
||||||
@ -209,7 +210,7 @@ class PartialMerkleTreeWithNamedHashTest {
|
|||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `nothing filtered`() {
|
fun `nothing filtered`() {
|
||||||
val ftxNothing = testTx.buildFilteredTransaction(Predicate { false })
|
val ftxNothing = testTx.buildFilteredTransaction { false }
|
||||||
assertTrue(ftxNothing.componentGroups.isEmpty())
|
assertTrue(ftxNothing.componentGroups.isEmpty())
|
||||||
assertTrue(ftxNothing.attachments.isEmpty())
|
assertTrue(ftxNothing.attachments.isEmpty())
|
||||||
assertTrue(ftxNothing.commands.isEmpty())
|
assertTrue(ftxNothing.commands.isEmpty())
|
||||||
@ -296,11 +297,13 @@ class PartialMerkleTreeWithNamedHashTest {
|
|||||||
assertFalse(pmt.verify(wrongRoot, inclHashes))
|
assertFalse(pmt.verify(wrongRoot, inclHashes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = Exception::class, timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `hash map serialization not allowed`() {
|
fun `hash map serialization not allowed`() {
|
||||||
val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4)
|
val hm1 = hashMapOf("a" to 1, "b" to 2, "c" to 3, "e" to 4)
|
||||||
|
assertThatIllegalArgumentException().isThrownBy {
|
||||||
hm1.serialize()
|
hm1.serialize()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun makeSimpleCashWtx(
|
private fun makeSimpleCashWtx(
|
||||||
notary: Party,
|
notary: Party,
|
||||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.sign
|
|||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -35,12 +36,14 @@ class SignedDataTest {
|
|||||||
assertEquals(data, unwrappedData)
|
assertEquals(data, unwrappedData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SignatureException::class, timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `make sure incorrectly signed data raises an exception`() {
|
fun `make sure incorrectly signed data raises an exception`() {
|
||||||
val keyPairA = generateKeyPair()
|
val keyPairA = generateKeyPair()
|
||||||
val keyPairB = generateKeyPair()
|
val keyPairB = generateKeyPair()
|
||||||
val sig = keyPairA.private.sign(serialized.bytes, keyPairB.public)
|
val sig = keyPairA.private.sign(serialized.bytes, keyPairB.public)
|
||||||
val wrappedData = SignedData(serialized, sig)
|
val wrappedData = SignedData(serialized, sig)
|
||||||
|
assertThatExceptionOfType(SignatureException::class.java).isThrownBy {
|
||||||
wrappedData.verified()
|
wrappedData.verified()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
package net.corda.coretests.crypto
|
package net.corda.coretests.crypto
|
||||||
|
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.Crypto
|
||||||
|
import net.corda.core.crypto.MerkleTree
|
||||||
|
import net.corda.core.crypto.MerkleTreeException
|
||||||
|
import net.corda.core.crypto.PartialMerkleTree
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.SignableData
|
||||||
|
import net.corda.core.crypto.SignatureMetadata
|
||||||
|
import net.corda.core.crypto.TransactionSignature
|
||||||
|
import net.corda.core.crypto.sha256
|
||||||
|
import net.corda.core.crypto.sign
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
@ -39,13 +49,15 @@ class TransactionSignatureTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Verification should fail; corrupted metadata - clearData (Merkle root) has changed. */
|
/** Verification should fail; corrupted metadata - clearData (Merkle root) has changed. */
|
||||||
@Test(expected = SignatureException::class,timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `Signature metadata full failure clearData has changed`() {
|
fun `Signature metadata full failure clearData has changed`() {
|
||||||
val keyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
val keyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||||
val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
|
val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
|
||||||
val transactionSignature = keyPair.sign(signableData)
|
val transactionSignature = keyPair.sign(signableData)
|
||||||
|
assertThatExceptionOfType(SignatureException::class.java).isThrownBy {
|
||||||
Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature)
|
Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `Verify multi-tx signature`() {
|
fun `Verify multi-tx signature`() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.coretests.flows
|
package net.corda.coretests.flows
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import co.paralleluniverse.strands.Strand
|
||||||
import net.corda.core.CordaException
|
import net.corda.core.CordaException
|
||||||
import net.corda.core.flows.FlowExternalAsyncOperation
|
import net.corda.core.flows.FlowExternalAsyncOperation
|
||||||
import net.corda.core.flows.FlowExternalOperation
|
import net.corda.core.flows.FlowExternalOperation
|
||||||
@ -133,7 +134,7 @@ abstract class AbstractFlowExternalOperationTest {
|
|||||||
fun createFuture(): CompletableFuture<Any> {
|
fun createFuture(): CompletableFuture<Any> {
|
||||||
return CompletableFuture.supplyAsync(Supplier<Any> {
|
return CompletableFuture.supplyAsync(Supplier<Any> {
|
||||||
log.info("Starting sleep inside of future")
|
log.info("Starting sleep inside of future")
|
||||||
Thread.sleep(1000)
|
Strand.sleep(1000)
|
||||||
log.info("Finished sleep inside of future")
|
log.info("Finished sleep inside of future")
|
||||||
"Here is your return value"
|
"Here is your return value"
|
||||||
}, executorService)
|
}, executorService)
|
||||||
|
@ -23,22 +23,22 @@ import net.corda.core.identity.groupAbstractPartyByWellKnownParty
|
|||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.coretesting.internal.matchers.flow.willReturn
|
||||||
|
import net.corda.coretesting.internal.matchers.flow.willThrow
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.BOB_NAME
|
import net.corda.testing.core.BOB_NAME
|
||||||
import net.corda.testing.core.CHARLIE_NAME
|
import net.corda.testing.core.CHARLIE_NAME
|
||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
import net.corda.testing.core.singleIdentity
|
import net.corda.testing.core.singleIdentity
|
||||||
import net.corda.coretesting.internal.matchers.flow.willReturn
|
|
||||||
import net.corda.coretesting.internal.matchers.flow.willThrow
|
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
|
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
|
||||||
import net.corda.testing.node.internal.InternalMockNetwork
|
import net.corda.testing.node.internal.InternalMockNetwork
|
||||||
import net.corda.testing.node.internal.TestStartedNode
|
import net.corda.testing.node.internal.TestStartedNode
|
||||||
import net.corda.testing.node.internal.enclosedCordapp
|
import net.corda.testing.node.internal.enclosedCordapp
|
||||||
import org.hamcrest.CoreMatchers.`is`
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||||
import org.junit.AfterClass
|
import org.junit.AfterClass
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
|||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
val stx = future.get()
|
val stx = future.get()
|
||||||
val missingSigners = stx.getMissingSigners()
|
val missingSigners = stx.getMissingSigners()
|
||||||
Assert.assertThat(missingSigners, `is`(emptySet()))
|
assertThat(missingSigners).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -122,10 +122,10 @@ class CollectSignaturesFlowTests : WithContracts {
|
|||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
val stx = future.get()
|
val stx = future.get()
|
||||||
val missingSigners = stx.getMissingSigners()
|
val missingSigners = stx.getMissingSigners()
|
||||||
Assert.assertThat(missingSigners, `is`(emptySet()))
|
assertThat(missingSigners).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class, timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `throws exception when extra sessions are initiated`() {
|
fun `throws exception when extra sessions are initiated`() {
|
||||||
bobNode.registerInitiatedFlow(ExtraSessionsFlowResponder::class.java)
|
bobNode.registerInitiatedFlow(ExtraSessionsFlowResponder::class.java)
|
||||||
charlieNode.registerInitiatedFlow(ExtraSessionsFlowResponder::class.java)
|
charlieNode.registerInitiatedFlow(ExtraSessionsFlowResponder::class.java)
|
||||||
@ -137,8 +137,10 @@ class CollectSignaturesFlowTests : WithContracts {
|
|||||||
listOf(bobNode.info.singleIdentity(), alice)))
|
listOf(bobNode.info.singleIdentity(), alice)))
|
||||||
.resultFuture
|
.resultFuture
|
||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
|
assertThatIllegalArgumentException().isThrownBy {
|
||||||
future.getOrThrow()
|
future.getOrThrow()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `it is possible to collect from multiple well known sessions`() {
|
fun `it is possible to collect from multiple well known sessions`() {
|
||||||
@ -152,7 +154,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
|||||||
listOf(bobNode.info.singleIdentity(), alice))).resultFuture
|
listOf(bobNode.info.singleIdentity(), alice))).resultFuture
|
||||||
mockNet.runNetwork()
|
mockNet.runNetwork()
|
||||||
val signedTx = future.getOrThrow()
|
val signedTx = future.getOrThrow()
|
||||||
Assert.assertThat(signedTx.getMissingSigners(), `is`(emptySet()))
|
assertThat(signedTx.getMissingSigners()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -216,7 +218,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@InitiatedBy(TestFlow.Initiator::class)
|
@InitiatedBy(Initiator::class)
|
||||||
class Responder(private val otherSideSession: FlowSession) : FlowLogic<Unit>() {
|
class Responder(private val otherSideSession: FlowSession) : FlowLogic<Unit>() {
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call() {
|
override fun call() {
|
||||||
@ -251,7 +253,7 @@ class AnonymousSessionTestFlow(private val cis: List<PartyAndCertificate>) : Flo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val state = DummyContract.MultiOwnerState(owners = cis.map { AnonymousParty(it.owningKey) })
|
val state = DummyContract.MultiOwnerState(owners = cis.map { AnonymousParty(it.owningKey) })
|
||||||
val create = net.corda.testing.contracts.DummyContract.Commands.Create()
|
val create = DummyContract.Commands.Create()
|
||||||
val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first())
|
val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first())
|
||||||
.addOutputState(state)
|
.addOutputState(state)
|
||||||
.addCommand(create, cis.map { it.owningKey })
|
.addCommand(create, cis.map { it.owningKey })
|
||||||
@ -289,7 +291,7 @@ class MixAndMatchAnonymousSessionTestFlow(private val cis: List<PartyAndCertific
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val state = DummyContract.MultiOwnerState(owners = cis.map { AnonymousParty(it.owningKey) })
|
val state = DummyContract.MultiOwnerState(owners = cis.map { AnonymousParty(it.owningKey) })
|
||||||
val create = net.corda.testing.contracts.DummyContract.Commands.Create()
|
val create = DummyContract.Commands.Create()
|
||||||
val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first())
|
val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first())
|
||||||
.addOutputState(state)
|
.addOutputState(state)
|
||||||
.addCommand(create, cis.map { it.owningKey })
|
.addCommand(create, cis.map { it.owningKey })
|
||||||
@ -324,7 +326,7 @@ class ExtraSessionsFlow(private val openFor: List<Party>, private val involve: L
|
|||||||
|
|
||||||
val sessions = openFor.map { initiateFlow(it) }
|
val sessions = openFor.map { initiateFlow(it) }
|
||||||
val state = DummyContract.MultiOwnerState(owners = involve.map { AnonymousParty(it.owningKey) })
|
val state = DummyContract.MultiOwnerState(owners = involve.map { AnonymousParty(it.owningKey) })
|
||||||
val create = net.corda.testing.contracts.DummyContract.Commands.Create()
|
val create = DummyContract.Commands.Create()
|
||||||
val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first())
|
val txBuilder = TransactionBuilder(notary = serviceHub.networkMapCache.notaryIdentities.first())
|
||||||
.addOutputState(state)
|
.addOutputState(state)
|
||||||
.addCommand(create, involve.map { it.owningKey })
|
.addCommand(create, involve.map { it.owningKey })
|
||||||
|
@ -9,19 +9,27 @@ import net.corda.core.CordaRuntimeException
|
|||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.flows.ContractUpgradeFlow
|
import net.corda.core.flows.ContractUpgradeFlow
|
||||||
|
import net.corda.core.internal.getRequiredTransaction
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.transactions.ContractUpgradeLedgerTransaction
|
import net.corda.core.transactions.ContractUpgradeLedgerTransaction
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.coretesting.internal.matchers.rpc.willReturn
|
||||||
|
import net.corda.coretesting.internal.matchers.rpc.willThrow
|
||||||
import net.corda.node.services.Permissions.Companion.startFlow
|
import net.corda.node.services.Permissions.Companion.startFlow
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.contracts.DummyContractV2
|
import net.corda.testing.contracts.DummyContractV2
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.BOB_NAME
|
import net.corda.testing.core.BOB_NAME
|
||||||
import net.corda.testing.core.singleIdentity
|
import net.corda.testing.core.singleIdentity
|
||||||
import net.corda.coretesting.internal.matchers.rpc.willReturn
|
|
||||||
import net.corda.coretesting.internal.matchers.rpc.willThrow
|
|
||||||
import net.corda.testing.node.User
|
import net.corda.testing.node.User
|
||||||
import net.corda.testing.node.internal.*
|
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
|
||||||
|
import net.corda.testing.node.internal.InternalMockNetwork
|
||||||
|
import net.corda.testing.node.internal.RPCDriverDSL
|
||||||
|
import net.corda.testing.node.internal.TestStartedNode
|
||||||
|
import net.corda.testing.node.internal.enclosedCordapp
|
||||||
|
import net.corda.testing.node.internal.rpcDriver
|
||||||
|
import net.corda.testing.node.internal.rpcTestUser
|
||||||
|
import net.corda.testing.node.internal.startRpcClient
|
||||||
import org.junit.AfterClass
|
import org.junit.AfterClass
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@ -120,8 +128,7 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
|
|||||||
isUpgrade<FROM, TO>())
|
isUpgrade<FROM, TO>())
|
||||||
|
|
||||||
private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
|
private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
|
||||||
services.validatedTransactions.getTransaction(state.ref.txhash)!!
|
services.getRequiredTransaction(state.ref.txhash).resolveContractUpgradeTransaction(services)
|
||||||
.resolveContractUpgradeTransaction(services)
|
|
||||||
|
|
||||||
private inline fun <reified FROM : Any, reified TO : Any> isUpgrade() =
|
private inline fun <reified FROM : Any, reified TO : Any> isUpgrade() =
|
||||||
isUpgradeFrom<FROM>() and isUpgradeTo<TO>()
|
isUpgradeFrom<FROM>() and isUpgradeTo<TO>()
|
||||||
|
@ -1,31 +1,54 @@
|
|||||||
package net.corda.coretests.flows
|
package net.corda.coretests.flows
|
||||||
|
|
||||||
import com.natpryce.hamkrest.*
|
import com.natpryce.hamkrest.Matcher
|
||||||
|
import com.natpryce.hamkrest.and
|
||||||
|
import com.natpryce.hamkrest.anything
|
||||||
import com.natpryce.hamkrest.assertion.assertThat
|
import com.natpryce.hamkrest.assertion.assertThat
|
||||||
import net.corda.core.contracts.*
|
import com.natpryce.hamkrest.equalTo
|
||||||
|
import com.natpryce.hamkrest.has
|
||||||
|
import com.natpryce.hamkrest.isA
|
||||||
|
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint
|
||||||
|
import net.corda.core.contracts.Amount
|
||||||
|
import net.corda.core.contracts.AttachmentConstraint
|
||||||
|
import net.corda.core.contracts.BelongsToContract
|
||||||
|
import net.corda.core.contracts.CommandAndState
|
||||||
|
import net.corda.core.contracts.ContractState
|
||||||
|
import net.corda.core.contracts.FungibleAsset
|
||||||
|
import net.corda.core.contracts.Issued
|
||||||
|
import net.corda.core.contracts.StateAndRef
|
||||||
|
import net.corda.core.contracts.TypeOnlyCommandData
|
||||||
|
import net.corda.core.contracts.UpgradedContractWithLegacyConstraint
|
||||||
import net.corda.core.flows.UnexpectedFlowEndException
|
import net.corda.core.flows.UnexpectedFlowEndException
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
|
import net.corda.core.internal.getRequiredTransaction
|
||||||
|
import net.corda.core.internal.mapToSet
|
||||||
import net.corda.core.transactions.ContractUpgradeLedgerTransaction
|
import net.corda.core.transactions.ContractUpgradeLedgerTransaction
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.coretesting.internal.matchers.flow.willReturn
|
||||||
|
import net.corda.coretesting.internal.matchers.flow.willThrow
|
||||||
import net.corda.finance.USD
|
import net.corda.finance.USD
|
||||||
import net.corda.finance.`issued by`
|
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
import net.corda.finance.flows.CashIssueFlow
|
import net.corda.finance.flows.CashIssueFlow
|
||||||
|
import net.corda.finance.`issued by`
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.contracts.DummyContractV2
|
import net.corda.testing.contracts.DummyContractV2
|
||||||
import net.corda.testing.contracts.DummyContractV3
|
import net.corda.testing.contracts.DummyContractV3
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.BOB_NAME
|
import net.corda.testing.core.BOB_NAME
|
||||||
import net.corda.testing.core.singleIdentity
|
import net.corda.testing.core.singleIdentity
|
||||||
import net.corda.coretesting.internal.matchers.flow.willReturn
|
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
|
||||||
import net.corda.coretesting.internal.matchers.flow.willThrow
|
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
|
||||||
import net.corda.testing.node.internal.*
|
import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP
|
||||||
|
import net.corda.testing.node.internal.InternalMockNetwork
|
||||||
|
import net.corda.testing.node.internal.TestStartedNode
|
||||||
|
import net.corda.testing.node.internal.enclosedCordapp
|
||||||
|
import net.corda.testing.node.internal.startFlow
|
||||||
import org.junit.AfterClass
|
import org.junit.AfterClass
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.Currency
|
||||||
|
|
||||||
class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||||
|
|
||||||
@ -159,7 +182,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
|||||||
@BelongsToContract(CashV2::class)
|
@BelongsToContract(CashV2::class)
|
||||||
data class State(override val amount: Amount<Issued<Currency>>, val owners: List<AbstractParty>) : FungibleAsset<Currency> {
|
data class State(override val amount: Amount<Issued<Currency>>, val owners: List<AbstractParty>) : FungibleAsset<Currency> {
|
||||||
override val owner: AbstractParty = owners.first()
|
override val owner: AbstractParty = owners.first()
|
||||||
override val exitKeys = (owners + amount.token.issuer.party).map { it.owningKey }.toSet()
|
override val exitKeys = (owners + amount.token.issuer.party).mapToSet { it.owningKey }
|
||||||
override val participants = owners
|
override val participants = owners
|
||||||
|
|
||||||
override fun withNewOwnerAndAmount(newAmount: Amount<Issued<Currency>>, newOwner: AbstractParty) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner))
|
override fun withNewOwnerAndAmount(newAmount: Amount<Issued<Currency>>, newOwner: AbstractParty) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner))
|
||||||
@ -180,8 +203,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
|||||||
isUpgrade<FROM, TO>())
|
isUpgrade<FROM, TO>())
|
||||||
|
|
||||||
private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
|
private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
|
||||||
services.validatedTransactions.getTransaction(state.ref.txhash)!!
|
services.getRequiredTransaction(state.ref.txhash).resolveContractUpgradeTransaction(services)
|
||||||
.resolveContractUpgradeTransaction(services)
|
|
||||||
|
|
||||||
private inline fun <reified FROM : Any, reified TO : Any> isUpgrade() =
|
private inline fun <reified FROM : Any, reified TO : Any> isUpgrade() =
|
||||||
isUpgradeFrom<FROM>() and isUpgradeTo<TO>()
|
isUpgradeFrom<FROM>() and isUpgradeTo<TO>()
|
||||||
|
@ -13,7 +13,7 @@ import net.corda.core.internal.rootCause
|
|||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import org.assertj.core.api.Assertions.catchThrowable
|
import org.assertj.core.api.Assertions.catchThrowable
|
||||||
import org.hamcrest.Matchers.lessThanOrEqualTo
|
import org.hamcrest.Matchers.lessThanOrEqualTo
|
||||||
import org.junit.Assert.assertThat
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
@ -85,7 +85,7 @@ class FastThreadLocalTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class UnserializableObj {
|
private class UnserializableObj {
|
||||||
@Suppress("unused")
|
@Suppress("unused", "IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION")
|
||||||
private val fail: Nothing by lazy { throw UnsupportedOperationException("Nice try.") }
|
private val fail: Nothing by lazy { throw UnsupportedOperationException("Nice try.") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import net.corda.testing.core.singleIdentity
|
|||||||
import net.corda.testing.driver.DriverParameters
|
import net.corda.testing.driver.DriverParameters
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.io.Serializable
|
||||||
import java.sql.SQLTransientConnectionException
|
import java.sql.SQLTransientConnectionException
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
@ -22,6 +23,8 @@ import kotlin.test.assertTrue
|
|||||||
|
|
||||||
class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
||||||
|
|
||||||
|
private fun interface SerializableLambda2<S, T, R> : (S, T) -> R, Serializable
|
||||||
|
|
||||||
@Test(timeout = 300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation`() {
|
fun `external async operation`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
@ -196,15 +199,15 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
class FlowWithExternalAsyncOperationPropagatesException<T>(party: Party, private val exceptionType: Class<T>) :
|
class FlowWithExternalAsyncOperationPropagatesException<T>(party: Party, private val exceptionType: Class<T>) :
|
||||||
FlowWithExternalProcess(party) {
|
FlowWithExternalProcess(party) {
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any {
|
override fun testCode(): Any {
|
||||||
val e = createException()
|
val e = createException()
|
||||||
return await(ExternalAsyncOperation(serviceHub) { _, _ ->
|
|
||||||
|
return await(ExternalAsyncOperation(serviceHub, (SerializableLambda2 { _, _ ->
|
||||||
CompletableFuture<Any>().apply {
|
CompletableFuture<Any>().apply {
|
||||||
completeExceptionally(e)
|
completeExceptionally(e)
|
||||||
}
|
}
|
||||||
})
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createException() = when (exceptionType) {
|
private fun createException() = when (exceptionType) {
|
||||||
@ -252,7 +255,6 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
class FlowWithExternalAsyncOperationThatDirectlyAccessesServiceHubFailsRetry(party: Party) : FlowWithExternalProcess(party) {
|
class FlowWithExternalAsyncOperationThatDirectlyAccessesServiceHubFailsRetry(party: Party) : FlowWithExternalProcess(party) {
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any {
|
override fun testCode(): Any {
|
||||||
return await(ExternalAsyncOperation(serviceHub) { _, _ ->
|
return await(ExternalAsyncOperation(serviceHub) { _, _ ->
|
||||||
|
@ -21,12 +21,15 @@ import net.corda.testing.driver.DriverParameters
|
|||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import net.corda.testing.node.internal.cordappsForPackages
|
import net.corda.testing.node.internal.cordappsForPackages
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.io.Serializable
|
||||||
import java.sql.SQLTransientConnectionException
|
import java.sql.SQLTransientConnectionException
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
||||||
|
|
||||||
|
private fun interface SerializableLambda2<S, T, R> : (S, T) -> R, Serializable
|
||||||
|
|
||||||
@Test(timeout = 300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation`() {
|
fun `external operation`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
@ -254,7 +257,7 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode() {
|
override fun testCode() {
|
||||||
val e = createException()
|
val e = createException()
|
||||||
await(ExternalOperation(serviceHub) { _, _ -> throw e })
|
await<Nothing>(ExternalOperation(serviceHub, (SerializableLambda2 { _, _ -> throw e })))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createException() = when (exceptionType) {
|
private fun createException() = when (exceptionType) {
|
||||||
@ -270,7 +273,7 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any = try {
|
override fun testCode(): Any = try {
|
||||||
await(ExternalOperation(serviceHub) { _, _ ->
|
await<Nothing>(ExternalOperation(serviceHub) { _, _ ->
|
||||||
throw IllegalStateException("threw exception in background process")
|
throw IllegalStateException("threw exception in background process")
|
||||||
})
|
})
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
@ -284,7 +287,7 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any =
|
override fun testCode(): Any =
|
||||||
await(ExternalOperation(serviceHub) { serviceHub, _ ->
|
await<Nothing>(ExternalOperation(serviceHub) { serviceHub, _ ->
|
||||||
serviceHub.cordaService(FutureService::class.java).throwHospitalHandledException()
|
serviceHub.cordaService(FutureService::class.java).throwHospitalHandledException()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -292,11 +295,10 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
class FlowWithExternalOperationThatDirectlyAccessesServiceHubFailsRetry(party: Party) : FlowWithExternalProcess(party) {
|
class FlowWithExternalOperationThatDirectlyAccessesServiceHubFailsRetry(party: Party) : FlowWithExternalProcess(party) {
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any {
|
override fun testCode(): Any {
|
||||||
try {
|
try {
|
||||||
await(ExternalOperation(serviceHub) { _, _ ->
|
await<Nothing>(ExternalOperation(serviceHub) { _, _ ->
|
||||||
serviceHub.cordaService(FutureService::class.java).throwHospitalHandledException()
|
serviceHub.cordaService(FutureService::class.java).throwHospitalHandledException()
|
||||||
})
|
})
|
||||||
} catch (e: NullPointerException) {
|
} catch (e: NullPointerException) {
|
||||||
|
@ -79,7 +79,7 @@ class FlowSleepTest {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): Pair<Instant, Instant> {
|
override fun call(): Pair<Instant, Instant> {
|
||||||
val start = Instant.now()
|
val start = Instant.now()
|
||||||
sleep(5.seconds)
|
sleep(6.seconds)
|
||||||
return start to Instant.now()
|
return start to Instant.now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,9 +90,9 @@ class FlowSleepTest {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): Triple<Instant, Instant, Instant> {
|
override fun call(): Triple<Instant, Instant, Instant> {
|
||||||
val start = Instant.now()
|
val start = Instant.now()
|
||||||
sleep(5.seconds)
|
sleep(6.seconds)
|
||||||
val middle = Instant.now()
|
val middle = Instant.now()
|
||||||
sleep(10.seconds)
|
sleep(11.seconds)
|
||||||
return Triple(start, middle, Instant.now())
|
return Triple(start, middle, Instant.now())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ class ReceiveMultipleFlowTests : WithMockNet {
|
|||||||
assertEquals(message, receivedMessage)
|
assertEquals(message, receivedMessage)
|
||||||
session.send(answer)
|
session.send(answer)
|
||||||
}
|
}
|
||||||
} as FlowLogic<Unit>
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.core.flows.ReceiveFinalityFlow
|
|||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FlowStateMachineHandle
|
import net.corda.core.internal.FlowStateMachineHandle
|
||||||
|
import net.corda.core.internal.getRequiredTransaction
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.FlowHandle
|
import net.corda.core.messaging.FlowHandle
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
@ -26,9 +27,7 @@ interface WithFinality : WithMockNet {
|
|||||||
return startFlowAndRunNetwork(FinalityInvoker(stx, recipients.toSet(), emptySet()))
|
return startFlowAndRunNetwork(FinalityInvoker(stx, recipients.toSet(), emptySet()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TestStartedNode.getValidatedTransaction(stx: SignedTransaction): SignedTransaction {
|
fun TestStartedNode.getValidatedTransaction(stx: SignedTransaction): SignedTransaction = services.getRequiredTransaction(stx.id)
|
||||||
return services.validatedTransactions.getTransaction(stx.id)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
fun CordaRPCOps.finalise(stx: SignedTransaction, vararg recipients: Party): FlowHandle<SignedTransaction> {
|
fun CordaRPCOps.finalise(stx: SignedTransaction, vararg recipients: Party): FlowHandle<SignedTransaction> {
|
||||||
return startFlow(WithFinality::FinalityInvoker, stx, recipients.toSet(), emptySet()).andRunNetwork()
|
return startFlow(WithFinality::FinalityInvoker, stx, recipients.toSet(), emptySet()).andRunNetwork()
|
||||||
|
@ -240,6 +240,7 @@ class ResolveTransactionsFlowTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
|
@Ignore("Need to pass legacy contracts to internal mock network & need to create a legacy contract for test below")
|
||||||
fun `can resolve a chain of transactions containing a contract upgrade transaction`() {
|
fun `can resolve a chain of transactions containing a contract upgrade transaction`() {
|
||||||
val tx = contractUpgradeChain()
|
val tx = contractUpgradeChain()
|
||||||
var numUpdates = 0
|
var numUpdates = 0
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
package net.corda.coretests.internal.verification
|
||||||
|
|
||||||
|
import net.corda.core.internal.verification.AttachmentFixups
|
||||||
|
import net.corda.core.node.services.AttachmentId
|
||||||
|
import net.corda.node.internal.cordapp.JarScanningCordappLoader
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.util.jar.JarOutputStream
|
||||||
|
import java.util.zip.Deflater
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import kotlin.io.path.outputStream
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
|
class AttachmentFixupsTest {
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val ID1 = AttachmentId.randomSHA256()
|
||||||
|
@JvmField
|
||||||
|
val ID2 = AttachmentId.randomSHA256()
|
||||||
|
@JvmField
|
||||||
|
val ID3 = AttachmentId.randomSHA256()
|
||||||
|
@JvmField
|
||||||
|
val ID4 = AttachmentId.randomSHA256()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test fixup rule that adds attachment`() {
|
||||||
|
val fixupJar = Files.createTempFile("fixup", ".jar")
|
||||||
|
.writeFixupRules("$ID1 => $ID2, $ID3")
|
||||||
|
val fixedIDs = with(newFixupService(fixupJar)) {
|
||||||
|
fixupAttachmentIds(listOf(ID1))
|
||||||
|
}
|
||||||
|
assertThat(fixedIDs).containsExactly(ID2, ID3)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test fixup rule that deletes attachment`() {
|
||||||
|
val fixupJar = Files.createTempFile("fixup", ".jar")
|
||||||
|
.writeFixupRules("$ID1 =>")
|
||||||
|
val fixedIDs = with(newFixupService(fixupJar)) {
|
||||||
|
fixupAttachmentIds(listOf(ID1))
|
||||||
|
}
|
||||||
|
assertThat(fixedIDs).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test fixup rule with blank LHS`() {
|
||||||
|
val fixupJar = Files.createTempFile("fixup", ".jar")
|
||||||
|
.writeFixupRules(" => $ID2")
|
||||||
|
val ex = assertFailsWith<IllegalArgumentException> {
|
||||||
|
newFixupService(fixupJar)
|
||||||
|
}
|
||||||
|
assertThat(ex).hasMessageContaining(
|
||||||
|
"Forbidden empty list of source attachment IDs in '$fixupJar'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test fixup rule without arrows`() {
|
||||||
|
val rule = " $ID1 "
|
||||||
|
val fixupJar = Files.createTempFile("fixup", ".jar")
|
||||||
|
.writeFixupRules(rule)
|
||||||
|
val ex = assertFailsWith<IllegalArgumentException> {
|
||||||
|
newFixupService(fixupJar)
|
||||||
|
}
|
||||||
|
assertThat(ex).hasMessageContaining(
|
||||||
|
"Invalid fix-up line '${rule.trim()}' in '$fixupJar'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test fixup rule with too many arrows`() {
|
||||||
|
val rule = " $ID1 => $ID2 => $ID3 "
|
||||||
|
val fixupJar = Files.createTempFile("fixup", ".jar")
|
||||||
|
.writeFixupRules(rule)
|
||||||
|
val ex = assertFailsWith<IllegalArgumentException> {
|
||||||
|
newFixupService(fixupJar)
|
||||||
|
}
|
||||||
|
assertThat(ex).hasMessageContaining(
|
||||||
|
"Invalid fix-up line '${rule.trim()}' in '$fixupJar'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test fixup file containing multiple rules and comments`() {
|
||||||
|
val fixupJar = Files.createTempFile("fixup", ".jar").writeFixupRules(
|
||||||
|
"# Whole line comment",
|
||||||
|
"\t$ID1,$ID2 => $ID2,, $ID3 # EOl comment",
|
||||||
|
" # Empty line with comment",
|
||||||
|
"",
|
||||||
|
"$ID3 => $ID4"
|
||||||
|
)
|
||||||
|
val fixedIDs = with(newFixupService(fixupJar)) {
|
||||||
|
fixupAttachmentIds(listOf(ID2, ID1))
|
||||||
|
}
|
||||||
|
assertThat(fixedIDs).containsExactlyInAnyOrder(ID2, ID4)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Path.writeFixupRules(vararg lines: String): Path {
|
||||||
|
JarOutputStream(outputStream()).use { jar ->
|
||||||
|
jar.setMethod(ZipEntry.DEFLATED)
|
||||||
|
jar.setLevel(Deflater.NO_COMPRESSION)
|
||||||
|
jar.putNextEntry(directoryEntry("META-INF"))
|
||||||
|
jar.putNextEntry(fileEntry("META-INF/Corda-Fixups"))
|
||||||
|
for (line in lines) {
|
||||||
|
jar.write(line.toByteArray())
|
||||||
|
jar.write('\r'.code)
|
||||||
|
jar.write('\n'.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun directoryEntry(internalName: String): ZipEntry {
|
||||||
|
return ZipEntry("$internalName/").apply {
|
||||||
|
method = ZipEntry.STORED
|
||||||
|
compressedSize = 0
|
||||||
|
size = 0
|
||||||
|
crc = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fileEntry(internalName: String): ZipEntry {
|
||||||
|
return ZipEntry(internalName).apply {
|
||||||
|
method = ZipEntry.DEFLATED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newFixupService(vararg paths: Path): AttachmentFixups {
|
||||||
|
val loader = JarScanningCordappLoader(paths.toSet())
|
||||||
|
return AttachmentFixups().apply { load(loader.appClassLoader) }
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package net.corda.coretests.node
|
package net.corda.coretests.node
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.internal.getPackageOwnerOf
|
import net.corda.core.internal.getPackageOwnerOf
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
|
@ -15,7 +15,7 @@ class VaultUpdateTests {
|
|||||||
private companion object {
|
private companion object {
|
||||||
const val DUMMY_PROGRAM_ID = "net.corda.coretests.node.VaultUpdateTests\$DummyContract"
|
const val DUMMY_PROGRAM_ID = "net.corda.coretests.node.VaultUpdateTests\$DummyContract"
|
||||||
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
|
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
|
||||||
val emptyUpdate = Vault.Update(emptySet(), emptySet(), type = Vault.UpdateType.GENERAL, references = emptySet())
|
val emptyUpdate = Vault.Update(emptySet<StateAndRef<*>>(), emptySet(), type = Vault.UpdateType.GENERAL, references = emptySet())
|
||||||
}
|
}
|
||||||
|
|
||||||
object DummyContract : Contract {
|
object DummyContract : Contract {
|
||||||
|
@ -116,6 +116,7 @@ class AttachmentSerializationTest {
|
|||||||
private class CustomAttachment(override val id: SecureHash, internal val customContent: String) : Attachment {
|
private class CustomAttachment(override val id: SecureHash, internal val customContent: String) : Attachment {
|
||||||
override fun open() = throw UnsupportedOperationException("Not implemented.")
|
override fun open() = throw UnsupportedOperationException("Not implemented.")
|
||||||
override val signerKeys get() = throw UnsupportedOperationException()
|
override val signerKeys get() = throw UnsupportedOperationException()
|
||||||
|
@Suppress("OVERRIDE_DEPRECATION")
|
||||||
override val signers: List<Party> get() = throw UnsupportedOperationException()
|
override val signers: List<Party> get() = throw UnsupportedOperationException()
|
||||||
override val size get() = throw UnsupportedOperationException()
|
override val size get() = throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.coretests.serialization
|
package net.corda.coretests.serialization
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SignatureMetadata
|
import net.corda.core.crypto.SignatureMetadata
|
||||||
|
@ -11,13 +11,13 @@ import net.corda.core.utilities.ByteSequence
|
|||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.isolated.contracts.DummyContractBackdoor
|
import net.corda.isolated.contracts.DummyContractBackdoor
|
||||||
import net.corda.node.services.attachments.NodeAttachmentTrustCalculator
|
import net.corda.node.services.attachments.NodeAttachmentTrustCalculator
|
||||||
|
import net.corda.node.services.persistence.toInternal
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||||
import net.corda.testing.internal.fakeAttachment
|
import net.corda.testing.internal.fakeAttachment
|
||||||
import net.corda.testing.internal.services.InternalMockAttachmentStorage
|
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
@ -30,7 +30,7 @@ import kotlin.test.assertFailsWith
|
|||||||
class AttachmentsClassLoaderSerializationTests {
|
class AttachmentsClassLoaderSerializationTests {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderSerializationTests::class.java.getResource("/isolated.jar")
|
val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderSerializationTests::class.java.getResource("/isolated.jar")!!
|
||||||
private const val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.isolated.contracts.AnotherDummyContract"
|
private const val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.isolated.contracts.AnotherDummyContract"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,20 +38,19 @@ class AttachmentsClassLoaderSerializationTests {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule()
|
val testSerialization = SerializationEnvironmentRule()
|
||||||
|
|
||||||
private val storage = InternalMockAttachmentStorage(MockAttachmentStorage())
|
private val storage = MockAttachmentStorage().toInternal()
|
||||||
private val attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage, TestingNamedCacheFactory())
|
private val attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage, TestingNamedCacheFactory())
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `Can serialize and deserialize with an attachment classloader`() {
|
fun `Can serialize and deserialize with an attachment classloader`() {
|
||||||
|
val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20).party
|
||||||
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
|
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party
|
||||||
val MEGA_CORP = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party
|
|
||||||
|
|
||||||
val isolatedId = storage.importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
val isolatedId = storage.importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
||||||
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream(), "app", "file1.jar")
|
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream(), "app", "file1.jar")
|
||||||
val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream(), "app", "file2.jar")
|
val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
val serialisedState = AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext(
|
val serialisedState = AttachmentsClassLoaderBuilder.withAttachmentsClassLoaderContext(
|
||||||
arrayOf(isolatedId, att1, att2).map { storage.openAttachment(it)!! },
|
arrayOf(isolatedId, att1, att2).map { storage.openAttachment(it)!! },
|
||||||
testNetworkParameters(),
|
testNetworkParameters(),
|
||||||
SecureHash.zeroHash,
|
SecureHash.zeroHash,
|
||||||
@ -64,7 +63,7 @@ class AttachmentsClassLoaderSerializationTests {
|
|||||||
val txt = IOUtils.toString(classLoader.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
val txt = IOUtils.toString(classLoader.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
||||||
assertEquals("some data", txt)
|
assertEquals("some data", txt)
|
||||||
|
|
||||||
val state = (contract as DummyContractBackdoor).generateInitial(MEGA_CORP.ref(1), 1, DUMMY_NOTARY).outputStates().first()
|
val state = (contract as DummyContractBackdoor).generateInitial(megaCorp.ref(1), 1, dummyNotary).outputStates().first()
|
||||||
val serialisedState = state.serialize()
|
val serialisedState = state.serialize()
|
||||||
|
|
||||||
val state1 = serialisedState.deserialize()
|
val state1 = serialisedState.deserialize()
|
||||||
|
@ -19,13 +19,13 @@ import net.corda.core.internal.AttachmentTrustCalculator
|
|||||||
import net.corda.core.internal.createLedgerTransaction
|
import net.corda.core.internal.createLedgerTransaction
|
||||||
import net.corda.core.internal.declaredField
|
import net.corda.core.internal.declaredField
|
||||||
import net.corda.core.internal.hash
|
import net.corda.core.internal.hash
|
||||||
import net.corda.core.internal.inputStream
|
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.serialization.internal.AttachmentsClassLoader
|
import net.corda.core.serialization.internal.AttachmentsClassLoader
|
||||||
import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl
|
import net.corda.core.serialization.internal.AttachmentsClassLoaderCacheImpl
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.node.services.attachments.NodeAttachmentTrustCalculator
|
import net.corda.node.services.attachments.NodeAttachmentTrustCalculator
|
||||||
|
import net.corda.node.services.persistence.toInternal
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
@ -37,14 +37,12 @@ import net.corda.testing.core.internal.ContractJarTestUtils
|
|||||||
import net.corda.testing.core.internal.ContractJarTestUtils.signContractJar
|
import net.corda.testing.core.internal.ContractJarTestUtils.signContractJar
|
||||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||||
import net.corda.testing.internal.fakeAttachment
|
import net.corda.testing.internal.fakeAttachment
|
||||||
import net.corda.testing.internal.services.InternalMockAttachmentStorage
|
|
||||||
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
|
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Assert.assertArrayEquals
|
import org.junit.Assert.assertArrayEquals
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertNull
|
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@ -55,14 +53,16 @@ import java.io.InputStream
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import kotlin.io.path.inputStream
|
||||||
|
import kotlin.io.path.readBytes
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.fail
|
import kotlin.test.fail
|
||||||
|
|
||||||
class AttachmentsClassLoaderTests {
|
class AttachmentsClassLoaderTests {
|
||||||
companion object {
|
companion object {
|
||||||
// TODO Update this test to use the new isolated.jar
|
// TODO Update this test to use the new isolated.jar
|
||||||
val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderTests::class.java.getResource("old-isolated.jar")
|
val ISOLATED_CONTRACTS_JAR_PATH: URL = AttachmentsClassLoaderTests::class.java.getResource("old-isolated.jar")!!
|
||||||
val ISOLATED_CONTRACTS_JAR_PATH_V4: URL = AttachmentsClassLoaderTests::class.java.getResource("isolated-4.0.jar")
|
val ISOLATED_CONTRACTS_JAR_PATH_V4: URL = AttachmentsClassLoaderTests::class.java.getResource("isolated-4.0.jar")!!
|
||||||
private const val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
private const val ISOLATED_CONTRACT_CLASS_NAME = "net.corda.finance.contracts.isolated.AnotherDummyContract"
|
||||||
|
|
||||||
private fun readAttachment(attachment: Attachment, filepath: String): ByteArray {
|
private fun readAttachment(attachment: Attachment, filepath: String): ByteArray {
|
||||||
@ -87,7 +87,6 @@ class AttachmentsClassLoaderTests {
|
|||||||
val testSerialization = SerializationEnvironmentRule()
|
val testSerialization = SerializationEnvironmentRule()
|
||||||
|
|
||||||
private lateinit var storage: MockAttachmentStorage
|
private lateinit var storage: MockAttachmentStorage
|
||||||
private lateinit var internalStorage: InternalMockAttachmentStorage
|
|
||||||
private lateinit var attachmentTrustCalculator: AttachmentTrustCalculator
|
private lateinit var attachmentTrustCalculator: AttachmentTrustCalculator
|
||||||
private val networkParameters = testNetworkParameters()
|
private val networkParameters = testNetworkParameters()
|
||||||
private val cacheFactory = TestingNamedCacheFactory(1)
|
private val cacheFactory = TestingNamedCacheFactory(1)
|
||||||
@ -114,8 +113,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
storage = MockAttachmentStorage()
|
storage = MockAttachmentStorage()
|
||||||
internalStorage = InternalMockAttachmentStorage(storage)
|
attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage.toInternal(), cacheFactory)
|
||||||
attachmentTrustCalculator = NodeAttachmentTrustCalculator(internalStorage, cacheFactory)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -128,8 +126,6 @@ class AttachmentsClassLoaderTests {
|
|||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `test contracts have no permissions for protection domain`() {
|
fun `test contracts have no permissions for protection domain`() {
|
||||||
val isolatedId = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
val isolatedId = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
||||||
assertNull(System.getSecurityManager())
|
|
||||||
|
|
||||||
createClassloader(isolatedId).use { classLoader ->
|
createClassloader(isolatedId).use { classLoader ->
|
||||||
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, classLoader)
|
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, classLoader)
|
||||||
val protectionDomain = contractClass.protectionDomain ?: fail("Protection Domain missing")
|
val protectionDomain = contractClass.protectionDomain ?: fail("Protection Domain missing")
|
||||||
@ -353,7 +349,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val keyPairA = Crypto.generateKeyPair()
|
val keyPairA = Crypto.generateKeyPair()
|
||||||
|
|
||||||
attachmentTrustCalculator = NodeAttachmentTrustCalculator(
|
attachmentTrustCalculator = NodeAttachmentTrustCalculator(
|
||||||
InternalMockAttachmentStorage(storage),
|
storage.toInternal(),
|
||||||
cacheFactory,
|
cacheFactory,
|
||||||
blacklistedAttachmentSigningKeys = listOf(keyPairA.public.hash)
|
blacklistedAttachmentSigningKeys = listOf(keyPairA.public.hash)
|
||||||
)
|
)
|
||||||
@ -479,7 +475,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
|
|
||||||
private fun createAttachments(contractJarPath: Path) : List<Attachment> {
|
private fun createAttachments(contractJarPath: Path) : List<Attachment> {
|
||||||
|
|
||||||
val attachment = object : AbstractAttachment({contractJarPath.inputStream().readBytes()}, uploader = "app") {
|
val attachment = object : AbstractAttachment(contractJarPath::readBytes, uploader = "app") {
|
||||||
@Suppress("OverridingDeprecatedMember")
|
@Suppress("OverridingDeprecatedMember")
|
||||||
@Deprecated("Use signerKeys. There is no requirement that attachment signers are Corda parties.")
|
@Deprecated("Use signerKeys. There is no requirement that attachment signers are Corda parties.")
|
||||||
override val signers: List<Party> = emptyList()
|
override val signers: List<Party> = emptyList()
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
package net.corda.coretests.transactions
|
package net.corda.coretests.transactions
|
||||||
|
|
||||||
import com.codahale.metrics.MetricRegistry
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import net.corda.core.contracts.TransactionVerificationException
|
import net.corda.core.contracts.TransactionVerificationException
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.AttachmentTrustCalculator
|
import net.corda.core.internal.AttachmentTrustCalculator
|
||||||
import net.corda.core.internal.hash
|
import net.corda.core.internal.hash
|
||||||
|
import net.corda.core.internal.verification.NodeVerificationSupport
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.ServicesForResolution
|
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.serialization.internal.AttachmentsClassLoader
|
import net.corda.core.serialization.internal.AttachmentsClassLoader
|
||||||
import net.corda.coretesting.internal.rigorousMock
|
import net.corda.coretesting.internal.rigorousMock
|
||||||
import net.corda.node.services.attachments.NodeAttachmentTrustCalculator
|
import net.corda.node.services.attachments.NodeAttachmentTrustCalculator
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
|
import net.corda.node.services.persistence.toInternal
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
@ -31,6 +30,8 @@ import net.corda.testing.node.MockServices
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
@ -48,11 +49,12 @@ class AttachmentsClassLoaderWithStoragePersistenceTests {
|
|||||||
|
|
||||||
private lateinit var database: CordaPersistence
|
private lateinit var database: CordaPersistence
|
||||||
private lateinit var storage: NodeAttachmentService
|
private lateinit var storage: NodeAttachmentService
|
||||||
|
private lateinit var attachmentTrustCalculator: AttachmentTrustCalculator
|
||||||
private lateinit var attachmentTrustCalculator2: AttachmentTrustCalculator
|
private lateinit var attachmentTrustCalculator2: AttachmentTrustCalculator
|
||||||
private val networkParameters = testNetworkParameters()
|
private val networkParameters = testNetworkParameters()
|
||||||
private val cacheFactory = TestingNamedCacheFactory(1)
|
private val cacheFactory = TestingNamedCacheFactory(1)
|
||||||
private val cacheFactory2 = TestingNamedCacheFactory()
|
private val cacheFactory2 = TestingNamedCacheFactory()
|
||||||
private val services = rigorousMock<ServicesForResolution>().also {
|
private val nodeVerificationSupport = rigorousMock<NodeVerificationSupport>().also {
|
||||||
doReturn(testNetworkParameters()).whenever(it).networkParameters
|
doReturn(testNetworkParameters()).whenever(it).networkParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +86,8 @@ class AttachmentsClassLoaderWithStoragePersistenceTests {
|
|||||||
it.start()
|
it.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
storage.servicesForResolution = services
|
storage.nodeVerificationSupport = nodeVerificationSupport
|
||||||
|
attachmentTrustCalculator = NodeAttachmentTrustCalculator(storage.toInternal(), cacheFactory)
|
||||||
attachmentTrustCalculator2 = NodeAttachmentTrustCalculator(storage, database, cacheFactory2)
|
attachmentTrustCalculator2 = NodeAttachmentTrustCalculator(storage, database, cacheFactory2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user