Merge branch 'release/os/4.11' into merge-release/os/4.10-release/os/4.11-2024-10-14-372

This commit is contained in:
Adel El-Beik 2024-10-15 16:33:13 +01:00
commit 5b812a56c2
599 changed files with 6643 additions and 13936 deletions

View File

@ -2523,6 +2523,8 @@ public class net.corda.core.flows.DataVendingFlow extends net.corda.core.flows.F
@Nullable
public Void call()
@NotNull
public final java.util.Set<net.corda.core.flows.FlowSession> getOtherSessions()
@NotNull
public final net.corda.core.flows.FlowSession getOtherSideSession()
@NotNull
public final Object getPayload()
@ -8048,6 +8050,8 @@ public static final class net.corda.testing.core.TestIdentity$Companion extends
public final net.corda.testing.core.TestIdentity fresh(String, net.corda.core.crypto.SignatureScheme)
##
public final class net.corda.testing.core.TestUtils extends java.lang.Object
@NotNull
public static final java.security.cert.X509CRL createCRL(net.corda.nodeapi.internal.crypto.CertificateAndKeyPair, java.util.List<? extends java.security.cert.X509Certificate>, java.net.URI, java.time.Instant, java.time.Instant, boolean, java.time.Instant, int, String)
public static final T executeTest(java.time.Duration, kotlin.jvm.functions.Function0<kotlin.Unit>, java.time.Duration, kotlin.jvm.functions.Function0<? extends T>)
@NotNull
public static final net.corda.core.utilities.NetworkHostAndPort freeLocalHostAndPort()
@ -8380,10 +8384,12 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.nio.file.Path, java.util.List, java.util.Map, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean, boolean)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.nio.file.Path, java.util.List, java.util.Map, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.util.Map<String, String>, boolean)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.util.Map, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.util.Map<String, String>, boolean, boolean)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.util.Map, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.util.Map<String, String>, boolean, boolean, java.time.Duration)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map, boolean, boolean, boolean, java.util.List, java.util.List, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map, boolean, java.util.Collection, java.util.Map, boolean, boolean, java.time.Duration, int, kotlin.jvm.internal.DefaultConstructorMarker)
public <init>(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, boolean)
public final boolean component1()
@NotNull
@ -8397,16 +8403,14 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public final boolean component14()
@Nullable
public final java.util.Collection<net.corda.testing.node.TestCordapp> component15()
@Nullable
public final java.nio.file.Path component16()
@NotNull
public final java.util.List<java.nio.file.Path> component17()
public final java.util.Map<String, String> component16()
public final boolean component17()
public final boolean component18()
@NotNull
public final java.util.Map<String, String> component18()
public final boolean component19()
public final java.time.Duration component19()
@NotNull
public final java.nio.file.Path component2()
public final boolean component20()
@NotNull
public final net.corda.testing.driver.PortAllocation component3()
@NotNull
@ -8423,9 +8427,11 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
@NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>)
@NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean)
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.util.Map<String, String>, boolean)
@NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.nio.file.Path, java.util.List<? extends java.nio.file.Path>, java.util.Map<String, String>, boolean, boolean)
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.util.Map<String, String>, boolean, boolean)
@NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Map<String, ?>, boolean, java.util.Collection<? extends net.corda.testing.node.TestCordapp>, java.util.Map<String, String>, boolean, boolean, java.time.Duration)
@NotNull
public final net.corda.testing.driver.DriverParameters copy(boolean, java.nio.file.Path, net.corda.testing.driver.PortAllocation, net.corda.testing.driver.PortAllocation, java.util.Map<String, String>, boolean, boolean, boolean, java.util.List<net.corda.testing.node.NotarySpec>, java.util.List<String>, net.corda.testing.driver.JmxPolicy, net.corda.core.node.NetworkParameters, java.util.Set<? extends net.corda.testing.node.TestCordapp>)
public boolean equals(Object)
@ -8434,10 +8440,6 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
public final java.util.Collection<net.corda.testing.node.TestCordapp> getCordappsForAllNodes()
@NotNull
public final net.corda.testing.driver.PortAllocation getDebugPortAllocation()
@Nullable
public final java.nio.file.Path getDjvmBootstrapSource()
@NotNull
public final java.util.List<java.nio.file.Path> getDjvmCordaSource()
@NotNull
public final java.nio.file.Path getDriverDirectory()
@NotNull
@ -8452,6 +8454,8 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
@NotNull
public final java.util.Map<String, Object> getNotaryCustomOverrides()
@NotNull
public final java.time.Duration getNotaryHandleTimeout()
@NotNull
public final java.util.List<net.corda.testing.node.NotarySpec> getNotarySpecs()
@NotNull
public final net.corda.testing.driver.PortAllocation getPortAllocation()
@ -8472,10 +8476,6 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
@NotNull
public final net.corda.testing.driver.DriverParameters withDebugPortAllocation(net.corda.testing.driver.PortAllocation)
@NotNull
public final net.corda.testing.driver.DriverParameters withDjvmBootstrapSource(java.nio.file.Path)
@NotNull
public final net.corda.testing.driver.DriverParameters withDjvmCordaSource(java.util.List<? extends java.nio.file.Path>)
@NotNull
public final net.corda.testing.driver.DriverParameters withDriverDirectory(java.nio.file.Path)
@NotNull
public final net.corda.testing.driver.DriverParameters withEnvironmentVariables(java.util.Map<String, String>)
@ -8492,6 +8492,8 @@ public final class net.corda.testing.driver.DriverParameters extends java.lang.O
@NotNull
public final net.corda.testing.driver.DriverParameters withNotaryCustomOverrides(java.util.Map<String, ?>)
@NotNull
public final net.corda.testing.driver.DriverParameters withNotaryHandleTimeout(java.time.Duration)
@NotNull
public final net.corda.testing.driver.DriverParameters withNotarySpecs(java.util.List<net.corda.testing.node.NotarySpec>)
@NotNull
public final net.corda.testing.driver.DriverParameters withPortAllocation(net.corda.testing.driver.PortAllocation)

View File

@ -13,13 +13,13 @@
* the branch name of origin branch, it should match the current branch
* and it acts as a fail-safe inside {@code forwardMerger} pipeline
*/
String originBranch = 'release/os/4.10'
String originBranch = 'release/os/4.11'
/**
* the branch name of target branch, it should be the branch with the next version
* after the one in current branch.
*/
String targetBranch = 'release/os/4.11'
String targetBranch = 'release/os/4.12'
/**
* Forward merge any changes between #originBranch and #targetBranch

View File

@ -57,6 +57,7 @@ pipeline {
steps {
authenticateGradleWrapper()
sh 'mkdir -p ${GRADLE_USER_HOME}'
authenticateGradleWrapper()
snykDeltaScan(env.SNYK_API_TOKEN, env.C4_OS_SNYK_ORG_ID)
}
}

8
.github/CODEOWNERS vendored
View File

@ -7,14 +7,6 @@ node-api @rick-r3
node/src/main/kotlin/net/corda/node/internal @rick-r3
node/src/main/kotlin/net/corda/node/services @rick-r3
# Determinstic components
core-deterministic @rick-r3
jdk8u-deterministic @rick-r3
node/djvm @rick-r3
serialization-deterministic @rick-r3
serialization-djvm @rick-r3
serialization-tests @rick-r3
# Demobench defaults to Chris, but Viktor for the main code
tools/demobench @rick-r3

View File

@ -9,6 +9,6 @@ jobs:
steps:
- uses: morrisoncole/pr-lint-action@v1.7.1
with:
title-regex: '^((CORDA|AG|EG|ENT|INFRA|ES)-\d+|NOTICK)(.*)'
title-regex: '^((CORDA|AG|EG|ENT|INFRA|ES)-\d+)(.*)'
on-failed-regex-comment: "PR title failed to match regex -> `%regex%`"
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -8,12 +8,18 @@ jobs:
sync_assigned:
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.AUTH_APP_ID }}
private-key: ${{ secrets.AUTH_APP_PK }}
- name: Assign
uses: corda/jira-sync-assigned-action@master
with:
jiraBaseUrl: ${{ secrets.JIRA_BASE_URL }}
jiraEmail: ${{ secrets.JIRA_USER_EMAIL }}
jiraToken: ${{ secrets.JIRA_API_TOKEN }}
token: ${{ secrets.GH_TOKEN }}
token: ${{ steps.generate_token.outputs.token }}
owner: corda
repository: corda

View File

@ -8,12 +8,18 @@ jobs:
sync_closed:
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.AUTH_APP_ID }}
private-key: ${{ secrets.AUTH_APP_PK }}
- name: Close
uses: corda/jira-sync-closed-action@master
with:
jiraBaseUrl: https://r3-cev.atlassian.net
jiraEmail: ${{ secrets.JIRA_USER_EMAIL }}
jiraToken: ${{ secrets.JIRA_API_TOKEN }}
token: ${{ secrets.GH_TOKEN }}
token: ${{ steps.generate_token.outputs.token }}
owner: corda
repository: corda

View File

@ -10,6 +10,13 @@ jobs:
steps:
- uses: actions/checkout@v4.1.1
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.AUTH_APP_ID }}
private-key: ${{ secrets.AUTH_APP_PK }}
- name: Jira Create issue
id: create
uses: corda/jira-create-issue-action@master
@ -30,7 +37,7 @@ jobs:
- name: Create comment
uses: peter-evans/create-or-update-comment@v4.0.0
with:
token: ${{ secrets.GH_TOKEN }}
token: ${{ steps.generate_token.outputs.token }}
issue-number: ${{ github.event.issue.number }}
body: |
Automatically created Jira issue: ${{ steps.create.outputs.issue }}

View File

@ -75,8 +75,6 @@ buildscript {
ext.disruptor_version = constants.getProperty("disruptorVersion")
ext.metrics_version = constants.getProperty("metricsVersion")
ext.metrics_new_relic_version = constants.getProperty("metricsNewRelicVersion")
ext.djvm_version = constants.getProperty("djvmVersion")
ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion')
ext.okhttp_version = constants.getProperty("okhttpVersion")
ext.netty_version = constants.getProperty("nettyVersion")
ext.tcnative_version = constants.getProperty("tcnativeVersion")
@ -126,6 +124,8 @@ buildscript {
ext.commons_configuration2_version = constants.getProperty("commonsConfiguration2Version")
ext.commons_text_version = constants.getProperty("commonsTextVersion")
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")
@ -134,9 +134,6 @@ buildscript {
ext.fontawesomefx_fontawesome_version = constants.getProperty("fontawesomefxFontawesomeVersion")
}
// Name of the IntelliJ SDK created for the deterministic Java rt.jar.
// ext.deterministic_idea_sdk = '1.8 (Deterministic)'
// 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
@ -615,28 +612,6 @@ task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) {
it.exists()
})
}
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
// these exclusions are necessary because jacoco gets confused by same class names
// which occur due to deterministic versions of non deterministic classes
exclude: ['**/net/corda/core/crypto/DigestSupplier**',
'**/net/corda/core/crypto/DelegatingSecureRandomService',
'**/net/corda/core/internal/ThreadLocalToggleField**',
'**/net/corda/core/internal/InheritableThreadLocalToggleField**',
'**/net/corda/core/internal/ToggleField**',
'net/corda/core/internal/rules/StateContractValidationEnforcementRule**',
'net/corda/core/internal/SimpleToggleField**',
'net/corda/core/serialization/SerializationFactory**',
'net/corda/serialization/internal/amqp/AMQPStreams**',
'net/corda/serialization/internal/amqp/AMQPSerializerFactories**',
'net/corda/serialization/internal/amqp/AMQPSerializationThreadContext**',
'net/corda/serialization/internal/ByteBufferStreams**',
'net/corda/serialization/internal/model/DefaultCacheProvider**',
'net/corda/serialization/internal/DefaultWhitelist**'
])
})
}
}
tasks.register('detekt', JavaExec) {
@ -689,15 +664,11 @@ bintrayConfig {
'corda-mock',
'corda-rpc',
'corda-core',
'corda-core-deterministic',
'corda-deterministic-verifier',
'corda-deserializers-djvm',
'corda',
'corda-finance-workflows',
'corda-finance-contracts',
'corda-node',
'corda-node-api',
'corda-node-djvm',
'corda-test-common',
'corda-core-test-utils',
'corda-test-utils',
@ -710,8 +681,6 @@ bintrayConfig {
'corda-shell',
'corda-tools-shell-cli',
'corda-serialization',
'corda-serialization-deterministic',
'corda-serialization-djvm',
'corda-tools-blob-inspector',
'corda-tools-explorer',
'corda-tools-network-bootstrapper',
@ -837,8 +806,4 @@ distributedTesting {
distribution DistributeTestsBy.METHOD
}
}
ignoredTests = [
':core-deterministic:testing:data:test'
]
}

View File

@ -9,4 +9,4 @@ package net.corda.common.logging
* (originally added to source control for ease of use)
*/
internal const val CURRENT_MAJOR_RELEASE = "4.10-SNAPSHOT"
internal const val CURRENT_MAJOR_RELEASE = "4.11-SNAPSHOT"

View File

@ -3,7 +3,7 @@
# their own projects. So don't get fancy with syntax!
# Fancy syntax - multi pass ${whatever} replacement
cordaVersion=4.10
cordaVersion=4.11
versionSuffix=SNAPSHOT
gradlePluginsVersion=5.0.12
kotlinVersion=1.2.71
@ -12,17 +12,18 @@ java8MinUpdateVersion=171
# When incrementing platformVersion make sure to update #
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
# ***************************************************************#
platformVersion=12
platformVersion=13
openTelemetryVersion=1.20.1
openTelemetrySemConvVersion=1.20.1-alpha
guavaVersion=28.0-jre
# Quasar version to use with Java 8:
quasarVersion=0.7.15_r3
quasarVersion=0.7.16_r3
# Quasar version to use with Java 11:
quasarVersion11=0.8.1_r3
jdkClassifier11=jdk11
dockerJavaVersion=3.2.5
proguardVersion=6.1.1
// bouncy castle version must not be changed on a patch release. Needs a full release test cycle to flush out any issues.
bouncycastleVersion=1.78.1
classgraphVersion=4.8.135
disruptorVersion=3.4.2
@ -33,8 +34,6 @@ snakeYamlVersion=1.33
caffeineVersion=2.9.3
metricsVersion=4.1.0
metricsNewRelicVersion=1.1.1
djvmVersion=1.1.1
deterministicRtVersion=1.0-RC02
openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4
openSourceSamplesBranch=https://github.com/corda/samples/blob/release-V4
jolokiaAgentVersion=1.6.1
@ -77,9 +76,9 @@ mockitoKotlinVersion=1.6.0
hamkrestVersion=1.7.0.0
joptSimpleVersion=5.0.2
jansiVersion=1.18
hibernateVersion=5.4.32.Final
hibernateVersion=5.6.14.Final
# h2Version - Update docs if renamed or removed.
h2Version=1.4.199
h2Version=2.2.224
rxjavaVersion=1.3.8
dokkaVersion=0.10.1
eddsaVersion=0.3.0
@ -88,7 +87,7 @@ commonsCollectionsVersion=4.3
beanutilsVersion=1.9.4
shiroVersion=1.10.0
hikariVersion=3.3.1
liquibaseVersion=3.6.3
liquibaseVersion=4.20.0
dockerComposeRuleVersion=1.5.0
seleniumVersion=3.141.59
ghostdriverVersion=2.1.0
@ -107,3 +106,4 @@ fontawesomefxFontawesomeJava8Version=4.7.0-5
# FontAwesomeFX for a more recent version of the Java Runtime (class file version 55.0)
fontawesomefxCommonsVersion=11.0
fontawesomefxFontawesomeVersion=4.7.0-11
javaassistVersion=3.27.0-GA

View File

@ -1,2 +0,0 @@
## corda-core-deterministic.
This artifact is a deterministic subset of the binary contents of `corda-core`.

View File

@ -1,248 +0,0 @@
import net.corda.gradle.jarfilter.JarFilterTask
import net.corda.gradle.jarfilter.MetaFixerTask
import proguard.gradle.ProGuardTask
import static org.gradle.api.JavaVersion.VERSION_1_8
plugins {
id 'org.jetbrains.kotlin.jvm'
id 'net.corda.plugins.publish-utils'
id 'com.jfrog.artifactory'
id 'java-library'
id 'idea'
}
apply from: "${rootProject.projectDir}/deterministic.gradle"
description 'Corda core (deterministic)'
evaluationDependsOn(":core")
// required by DJVM and Avian JVM (for running inside the SGX enclave) which only supports Java 8.
targetCompatibility = VERSION_1_8
def javaHome = System.getProperty('java.home')
def jarBaseName = "corda-${project.name}".toString()
configurations {
deterministicLibraries {
canBeConsumed = false
extendsFrom api
}
deterministicArtifacts.extendsFrom deterministicLibraries
}
dependencies {
compileOnly project(':core')
// Configure these by hand. It should be a minimal subset of core's dependencies,
// and without any obviously non-deterministic ones such as Hibernate.
// These "api" dependencies will become "compile" scoped in our published POM.
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
api "javax.persistence:javax.persistence-api:2.2"
api "com.google.code.findbugs:jsr305:$jsr305_version"
api "org.slf4j:slf4j-api:$slf4j_version"
compileOnly "io.opentelemetry:opentelemetry-api:${open_telemetry_version}"
compileOnly project(':opentelemetry')
// These dependencies will become "runtime" scoped in our published POM.
// See publish.dependenciesFrom.defaultScope.
deterministicLibraries "org.bouncycastle:bcprov-jdk18on:$bouncycastle_version"
deterministicLibraries "org.bouncycastle:bcpkix-jdk18on:$bouncycastle_version"
deterministicLibraries "net.i2p.crypto:eddsa:$eddsa_version"
}
tasks.named('jar', Jar) {
archiveBaseName = 'DOES-NOT-EXIST'
// Don't build a jar here because it would be the wrong one.
// The jar we really want will be built by the metafix task.
enabled = false
}
def coreJarTask = project(':core').tasks.named('jar', Jar)
def originalJar = coreJarTask.map { it.outputs.files.singleFile }
def patchCore = tasks.register('patchCore', Zip) {
dependsOn coreJarTask
destinationDirectory = layout.buildDirectory.dir('source-libs')
metadataCharset 'UTF-8'
archiveClassifier = 'transient'
archiveExtension = 'jar'
from(compileKotlin)
from(processResources)
from(zipTree(originalJar)) {
exclude 'net/corda/core/crypto/DelegatingSecureRandomService*.class'
exclude 'net/corda/core/crypto/DigestSupplier.class'
exclude 'net/corda/core/internal/*ToggleField*.class'
exclude 'net/corda/core/serialization/*SerializationFactory*.class'
exclude 'net/corda/core/serialization/internal/AttachmentsHolderImpl.class'
exclude 'net/corda/core/serialization/internal/CheckpointSerializationFactory*.class'
exclude 'net/corda/core/internal/rules/*.class'
exclude 'net/corda/core/contracts/CordaRotatedKeys.class'
exclude 'net/corda/core/contracts/RotatedKeysKt.class'
exclude 'net/corda/core/contracts/RotatedKeys.class'
exclude 'net/corda/core/internal/utilities/PrivateInterner*.class'
}
reproducibleFileOrder = true
includeEmptyDirs = false
}
def predeterminise = tasks.register('predeterminise', ProGuardTask) {
injars patchCore
outjars file("$buildDir/proguard/pre-deterministic-${project.version}.jar")
if (JavaVersion.current().isJava9Compatible()) {
libraryjars "$javaHome/jmods"
} else {
libraryjars "$javaHome/lib/rt.jar"
libraryjars "$javaHome/lib/jce.jar"
}
configurations.compileClasspath.forEach {
if (originalJar != it) {
libraryjars it, filter: '!META-INF/versions/**'
}
}
keepattributes '*'
keepdirectories
dontwarn '**$1$1,org.hibernate.annotations.*'
dontpreverify
dontobfuscate
dontoptimize
dontnote
printseeds
verbose
keep '@interface net.corda.core.* { *; }'
keep '@interface net.corda.core.contracts.** { *; }'
keep '@interface net.corda.core.serialization.** { *; }'
keep '@net.corda.core.KeepForDJVM class * { *; }', includedescriptorclasses:true
keepclassmembers 'class net.corda.core.** { public synthetic <methods>; }'
}
def jarFilter = tasks.register('jarFilter', JarFilterTask) {
jars predeterminise
annotations {
forDelete = [
"net.corda.core.DeleteForDJVM"
]
forStub = [
"net.corda.core.StubOutForDJVM"
]
forRemove = [
"co.paralleluniverse.fibers.Suspendable",
"org.hibernate.annotations.Immutable"
]
forSanitise = [
"net.corda.core.DeleteForDJVM"
]
}
}
def determinise = tasks.register('determinise', ProGuardTask) {
injars jarFilter
outjars file("$buildDir/proguard/$jarBaseName-${project.version}.jar")
if (JavaVersion.current().isJava9Compatible()) {
libraryjars "$javaHome/jmods"
} else {
libraryjars "$javaHome/lib/rt.jar"
libraryjars "$javaHome/lib/jce.jar"
}
configurations.deterministicLibraries.forEach {
libraryjars it, filter: '!META-INF/versions/**'
}
// Analyse the JAR for dead code, and remove (some of) it.
optimizations 'code/removal/simple,code/removal/advanced'
printconfiguration
keepattributes '*'
keepdirectories
dontobfuscate
dontnote
printseeds
verbose
keep '@interface net.corda.core.CordaInternal { *; }'
keep '@interface net.corda.core.DoNotImplement { *; }'
keep '@interface net.corda.core.KeepForDJVM { *; }'
keep '@interface net.corda.core.contracts.** { *; }'
keep '@interface net.corda.core.serialization.** { *; }'
keep '@net.corda.core.KeepForDJVM class * { *; }', includedescriptorclasses:true
keepclassmembers 'class net.corda.core.** { public synthetic <methods>; }'
}
def checkDeterminism = tasks.register('checkDeterminism', ProGuardTask)
def metafix = tasks.register('metafix', MetaFixerTask) {
outputDir = layout.buildDirectory.dir('libs')
jars determinise
suffix ""
// Strip timestamps from the JAR to make it reproducible.
preserveTimestamps = false
finalizedBy checkDeterminism
}
// DOCSTART 01
checkDeterminism.configure {
dependsOn jdkTask
injars metafix
libraryjars deterministic_rt_jar
configurations.deterministicLibraries.forEach {
libraryjars it, filter: '!META-INF/versions/**'
}
keepattributes '*'
dontpreverify
dontobfuscate
dontoptimize
verbose
keep 'class *'
}
// DOCEND 01
defaultTasks "determinise"
determinise.configure {
finalizedBy metafix
}
tasks.named('assemble') {
dependsOn checkDeterminism
}
def deterministicJar = metafix.map { it.outputs.files.singleFile }
artifacts {
deterministicArtifacts deterministicJar
publish deterministicJar
}
tasks.named('sourceJar', Jar) {
from 'README.md'
include 'README.md'
}
tasks.named('javadocJar', Jar) {
from 'README.md'
include 'README.md'
}
publish {
dependenciesFrom configurations.deterministicArtifacts
name jarBaseName
}
idea {
module {
if (project.hasProperty("deterministic_idea_sdk")) {
jdkName project.property("deterministic_idea_sdk") as String
}
}
}

View File

@ -1,19 +0,0 @@
package net.corda.core.crypto
import java.security.Provider
import java.security.SecureRandomSpi
@Suppress("unused")
class DelegatingSecureRandomService(provider: CordaSecurityProvider)
: Provider.Service(provider, "SecureRandom", "dummy-algorithm", UnsupportedSecureRandomSpi::javaClass.name, null, null) {
private val instance: SecureRandomSpi = UnsupportedSecureRandomSpi(algorithm)
override fun newInstance(param: Any?) = instance
private class UnsupportedSecureRandomSpi(private val algorithm: String) : SecureRandomSpi() {
override fun engineSetSeed(seed: ByteArray) = unsupported()
override fun engineNextBytes(bytes: ByteArray) = unsupported()
override fun engineGenerateSeed(numBytes: Int) = unsupported()
private fun unsupported(): Nothing = throw UnsupportedOperationException("$algorithm not supported")
}
}

View File

@ -1,10 +0,0 @@
package net.corda.core.crypto
import net.corda.core.crypto.internal.DigestAlgorithmFactory
import java.util.function.Supplier
@Suppress("unused")
private class DigestSupplier(private val algorithm: String) : Supplier<DigestAlgorithm> {
override fun get(): DigestAlgorithm = DigestAlgorithmFactory.create(algorithm)
val digestLength: Int by lazy { get().digestLength }
}

View File

@ -1,62 +0,0 @@
package net.corda.core.internal
import net.corda.core.KeepForDJVM
import net.corda.core.utilities.contextLogger
import org.slf4j.Logger
import kotlin.reflect.KProperty
/** May go from null to non-null and vice-versa, and that's it. */
abstract class ToggleField<T>(val name: String) {
abstract fun get(): T?
fun set(value: T?) {
if (value != null) {
check(get() == null) { "$name already has a value." }
setImpl(value)
} else {
check(get() != null) { "$name is already null." }
clear()
}
}
protected abstract fun setImpl(value: T)
protected abstract fun clear()
operator fun getValue(thisRef: Any?, property: KProperty<*>) = get()
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) = set(value)
}
@KeepForDJVM
class SimpleToggleField<T>(name: String, private val once: Boolean = false) : ToggleField<T>(name) {
private var holder: T? = null // Force T? in API for safety.
override fun get() = holder
override fun setImpl(value: T) { holder = value }
override fun clear() {
check(!once) { "Value of $name cannot be changed." }
holder = null
}
}
@KeepForDJVM
class ThreadLocalToggleField<T>(name: String) : ToggleField<T>(name) {
private var holder: T? = null // Force T? in API for safety.
override fun get() = holder
override fun setImpl(value: T) { holder = value }
override fun clear() {
holder = null
}
}
@Suppress("UNUSED")
@KeepForDJVM
class InheritableThreadLocalToggleField<T>(name: String,
private val log: Logger = staticLog,
private val isAGlobalThreadBeingCreated: (Array<StackTraceElement>) -> Boolean) : ToggleField<T>(name) {
private companion object {
private val staticLog = contextLogger()
}
private var holder: T? = null // Force T? in API for safety.
override fun get() = holder
override fun setImpl(value: T) { holder = value }
override fun clear() {
holder = null
}
}

View File

@ -1,12 +0,0 @@
package net.corda.core.internal.rules
import net.corda.core.contracts.ContractState
// This file provides rules that depend on the targetVersion of the current Contract or Flow.
// In core, this is determined by means which are unavailable in the DJVM,
// so we must provide deterministic alternatives here.
@Suppress("unused")
object StateContractValidationEnforcementRule {
fun shouldEnforce(@Suppress("UNUSED_PARAMETER") state: ContractState): Boolean = true
}

View File

@ -1,16 +0,0 @@
package net.corda.core.internal.utilities
import net.corda.core.KeepForDJVM
@KeepForDJVM
class PrivateInterner<T>(val verifier: IternabilityVerifier<T> = AlwaysInternableVerifier()) {
// DJVM implementation does not intern and does not use Guava
fun <S : T> intern(sample: S): S = sample
@KeepForDJVM
companion object {
@Suppress("UNUSED_PARAMETER")
fun findFor(clazz: Class<*>?): PrivateInterner<Any>? = null
}
}

View File

@ -1,99 +0,0 @@
package net.corda.core.serialization
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.internal.effectiveSerializationEnv
import net.corda.core.utilities.ByteSequence
/**
* An abstraction for serializing and deserializing objects, with support for versioning of the wire format via
* a header / prefix in the bytes.
*/
@KeepForDJVM
abstract class SerializationFactory {
/**
* Deserialize the bytes in to an object, using the prefixed bytes to determine the format.
*
* @param byteSequence The bytes to deserialize, including a format header prefix.
* @param clazz The class or superclass or the object to be deserialized, or [Any] or [Object] if unknown.
* @param context A context that configures various parameters to deserialization.
*/
abstract fun <T : Any> deserialize(byteSequence: ByteSequence, clazz: Class<T>, context: SerializationContext): T
/**
* Deserialize the bytes in to an object, using the prefixed bytes to determine the format.
*
* @param byteSequence The bytes to deserialize, including a format header prefix.
* @param clazz The class or superclass or the object to be deserialized, or [Any] or [Object] if unknown.
* @param context A context that configures various parameters to deserialization.
* @return deserialized object along with [SerializationContext] to identify encoding used.
*/
abstract fun <T : Any> deserializeWithCompatibleContext(byteSequence: ByteSequence, clazz: Class<T>, context: SerializationContext): ObjectWithCompatibleContext<T>
/**
* Serialize an object to bytes using the preferred serialization format version from the context.
*
* @param obj The object to be serialized.
* @param context A context that configures various parameters to serialization, including the serialization format version.
*/
abstract fun <T : Any> serialize(obj: T, context: SerializationContext): SerializedBytes<T>
/**
* If there is a need to nest serialization/deserialization with a modified context during serialization or deserialization,
* this will return the current context used to start serialization/deserialization.
*/
val currentContext: SerializationContext? get() = _currentContext
/**
* A context to use as a default if you do not require a specially configured context. It will be the current context
* if the use is somehow nested (see [currentContext]).
*/
val defaultContext: SerializationContext get() = currentContext ?: effectiveSerializationEnv.p2pContext
private var _currentContext: SerializationContext? = null
/**
* Change the current context inside the block to that supplied.
*/
fun <T> withCurrentContext(context: SerializationContext?, block: () -> T): T {
return if (context == null) {
block()
} else {
val priorContext = _currentContext
_currentContext = context
try {
block()
} finally {
_currentContext = priorContext
}
}
}
/**
* Allow subclasses to temporarily mark themselves as the current factory for the current thread during serialization/deserialization.
* Will restore the prior context on exiting the block.
*/
fun <T> asCurrent(block: SerializationFactory.() -> T): T {
val priorContext = _currentFactory
_currentFactory= this
try {
return this.block()
} finally {
_currentFactory = priorContext
}
}
companion object {
private var _currentFactory: SerializationFactory? = null
/**
* A default factory for serialization/deserialization, taking into account the [currentFactory] if set.
*/
val defaultFactory: SerializationFactory get() = currentFactory ?: effectiveSerializationEnv.serializationFactory
/**
* If there is a need to nest serialization/deserialization with a modified context during serialization or deserialization,
* this will return the current factory used to start serialization/deserialization.
*/
val currentFactory: SerializationFactory? get() = _currentFactory
}
}

View File

@ -1,23 +0,0 @@
package net.corda.core.serialization.internal
import net.corda.core.contracts.Attachment
import java.net.URL
@Suppress("unused")
private class AttachmentsHolderImpl : AttachmentsHolder {
private val attachments = LinkedHashMap<URL, Pair<URL, Attachment>>()
override val size: Int get() = attachments.size
override fun getKey(key: URL): URL? {
return attachments[key]?.first
}
override fun get(key: URL): Attachment? {
return attachments[key]?.second
}
override fun set(key: URL, value: Attachment) {
attachments[key] = key to value
}
}

View File

@ -1,29 +0,0 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
}
dependencies {
testImplementation project(path: ':core-deterministic', configuration: 'deterministicArtifacts')
testImplementation project(path: ':serialization-deterministic', configuration: 'deterministicArtifacts')
testImplementation project(path: ':core-deterministic:testing:verifier', configuration: 'deterministicArtifacts')
testImplementation project(path: ':core-deterministic:testing:data', configuration: 'testData')
testImplementation(project(':finance:contracts')) {
transitive = false
}
testImplementation(project(':finance:workflows')) {
transitive = false
}
testImplementation "org.slf4j:slf4j-api:$slf4j_version"
testRuntimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation "org.assertj:assertj-core:$assertj_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}"
}
// This module has no artifact and only contains tests.
tasks.named('jar', Jar) {
enabled = false
}

View File

@ -1,44 +0,0 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
}
configurations {
testData {
canBeResolved = false
}
}
dependencies {
testImplementation project(':core')
testImplementation project(':finance:workflows')
testImplementation project(':node-driver')
testImplementation project(path: ':core-deterministic:testing:verifier', configuration: 'runtimeArtifacts')
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testImplementation "org.jetbrains.kotlin:kotlin-reflect"
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}"
}
tasks.named('jar', Jar) {
enabled = false
}
def test = tasks.named('test', Test) {
filter {
// Running this class is the whole point, so include it explicitly.
includeTestsMatching "net.corda.deterministic.data.GenerateData"
}
// force execution of these tests to generate artifacts required by other module (eg. VerifyTransactionTest)
// note: required by Gradle Build Cache.
outputs.upToDateWhen { false }
}
def testDataJar = file("$buildDir/test-data.jar")
artifacts {
archives file: testDataJar, type: 'jar', builtBy: test
testData file: testDataJar, type: 'jar', builtBy: test
}

View File

@ -1,92 +0,0 @@
package net.corda.deterministic.data
import net.corda.core.serialization.deserialize
import net.corda.deterministic.verifier.LocalSerializationRule
import net.corda.deterministic.verifier.TransactionVerificationRequest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.io.FileNotFoundException
import java.net.URLClassLoader
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.attribute.FileTime
import java.util.*
import java.util.Calendar.*
import java.util.jar.JarOutputStream
import java.util.zip.Deflater.NO_COMPRESSION
import java.util.zip.ZipEntry
import java.util.zip.ZipEntry.*
import kotlin.reflect.jvm.jvmName
/**
* Use the JUnit framework to generate a JAR of test data.
*/
class GenerateData {
companion object {
private val CONSTANT_TIME: FileTime = FileTime.fromMillis(
GregorianCalendar(1980, FEBRUARY, 1).apply { timeZone = TimeZone.getTimeZone("UTC") }.timeInMillis
)
private const val KEYSTORE_ALIAS = "tx"
private val KEYSTORE_PASSWORD = "deterministic".toCharArray()
private val TEST_DATA: Path = Paths.get("build", "test-data.jar")
private fun compressed(name: String) = ZipEntry(name).apply {
lastModifiedTime = CONSTANT_TIME
method = DEFLATED
}
private fun directory(name: String) = ZipEntry(name).apply {
lastModifiedTime = CONSTANT_TIME
method = STORED
compressedSize = 0
size = 0
crc = 0
}
}
@Rule
@JvmField
val testSerialization = LocalSerializationRule(GenerateData::class.jvmName)
@Before
fun createTransactions() {
JarOutputStream(Files.newOutputStream(TEST_DATA)).use { jar ->
jar.setComment("Test data for Deterministic Corda")
jar.setLevel(NO_COMPRESSION)
// Serialised transactions for the Enclavelet
jar.putNextEntry(directory("txverify"))
jar.putNextEntry(compressed("txverify/tx-success.bin"))
TransactionGenerator.writeSuccess(jar)
jar.putNextEntry(compressed("txverify/tx-failure.bin"))
TransactionGenerator.writeFailure(jar)
// KeyStore containing an EC private key.
jar.putNextEntry(directory("keystore"))
jar.putNextEntry(compressed("keystore/txsignature.pfx"))
KeyStoreGenerator.writeKeyStore(jar, KEYSTORE_ALIAS, KEYSTORE_PASSWORD)
}
testSerialization.reset()
}
@Test(timeout = 300_000)
fun verifyTransactions() {
URLClassLoader(arrayOf(TEST_DATA.toUri().toURL())).use { cl ->
cl.loadResource("txverify/tx-success.bin")
.deserialize<TransactionVerificationRequest>()
.toLedgerTransaction()
.verify()
cl.loadResource("txverify/tx-failure.bin")
.deserialize<TransactionVerificationRequest>()
.toLedgerTransaction()
}
}
private fun ClassLoader.loadResource(resourceName: String): ByteArray {
return getResourceAsStream(resourceName)?.use { it.readBytes() }
?: throw FileNotFoundException(resourceName)
}
}

View File

@ -1,50 +0,0 @@
package net.corda.deterministic.data
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import java.io.OutputStream
import java.math.BigInteger.TEN
import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.spec.ECGenParameterSpec
import java.util.*
import java.util.Calendar.*
object KeyStoreGenerator {
private val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("EC").apply {
initialize(ECGenParameterSpec("secp256k1"))
}
fun writeKeyStore(output: OutputStream, alias: String, password: CharArray) {
val keyPair = keyPairGenerator.generateKeyPair()
val signer = JcaContentSignerBuilder("SHA256WithECDSA").build(keyPair.private)
val dname = X500Name("CN=Enclavelet")
val startDate = Calendar.getInstance().let { cal ->
cal.time = Date()
cal.add(HOUR, -1)
cal.time
}
val endDate = Calendar.getInstance().let { cal ->
cal.time = startDate
cal.add(YEAR, 1)
cal.time
}
val certificate = JcaX509v3CertificateBuilder(
dname,
TEN,
startDate,
endDate,
dname,
keyPair.public
).build(signer)
val x509 = JcaX509CertificateConverter().getCertificate(certificate)
KeyStore.getInstance("PKCS12").apply {
load(null, password)
setKeyEntry(alias, keyPair.private, password, arrayOf(x509))
store(output, password)
}
}
}

View File

@ -1,115 +0,0 @@
package net.corda.deterministic.data
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.node.services.IdentityService
import net.corda.core.serialization.serialize
import net.corda.deterministic.verifier.MockContractAttachment
import net.corda.deterministic.verifier.SampleCommandData
import net.corda.deterministic.verifier.TransactionVerificationRequest
import net.corda.finance.POUNDS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash.Commands.Issue
import net.corda.finance.contracts.asset.Cash.Commands.Move
import net.corda.finance.contracts.asset.Cash.Companion.PROGRAM_ID
import net.corda.finance.contracts.asset.Cash.State
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.core.TestIdentity
import net.corda.testing.core.getTestPartyAndCertificate
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
import java.io.OutputStream
import java.math.BigInteger
import java.security.KeyPair
import java.security.PublicKey
object TransactionGenerator {
private val DUMMY_NOTARY: Party = TestIdentity(DUMMY_NOTARY_NAME, 20).party
private val DUMMY_CASH_ISSUER_KEY: KeyPair = entropyToKeyPair(BigInteger.valueOf(10))
private val DUMMY_CASH_ISSUER_IDENTITY = getTestPartyAndCertificate(Party(CordaX500Name("Snake Oil Issuer", "London", "GB"), DUMMY_CASH_ISSUER_KEY.public))
private val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1)
private val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
private val MEGA_CORP: Party = megaCorp.party
private val MEGA_CORP_PUBKEY: PublicKey = megaCorp.keyPair.public
private val MINI_CORP_PUBKEY: PublicKey = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).keyPair.public
private val ledgerServices = MockServices(emptyList(), MEGA_CORP.name, mock<IdentityService>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
doReturn(DUMMY_CASH_ISSUER.party).whenever(it).partyFromKey(DUMMY_CASH_ISSUER_KEY.public)
})
fun writeSuccess(output: OutputStream) {
ledgerServices.ledger(DUMMY_NOTARY) {
// Issue a couple of cash states and spend them.
val wtx1 = transaction {
attachments(PROGRAM_ID)
output(PROGRAM_ID, "c1", State(1000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY)))
command(DUMMY_CASH_ISSUER.party.owningKey, Issue())
verifies()
}
val wtx2 = transaction {
attachments(PROGRAM_ID)
output(PROGRAM_ID, "c2", State(2000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY)))
command(DUMMY_CASH_ISSUER.party.owningKey, Issue())
verifies()
}
val wtx3 = transaction {
attachments(PROGRAM_ID)
input("c1")
input("c2")
output(PROGRAM_ID, "c3", State(3000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MINI_CORP_PUBKEY)))
command(MEGA_CORP_PUBKEY, Move())
verifies()
}
val contractAttachment = MockContractAttachment(interpreter.services.cordappProvider.getContractAttachmentID(PROGRAM_ID)!!, PROGRAM_ID)
TransactionVerificationRequest(
wtx3.serialize(),
arrayOf(wtx1.serialize(), wtx2.serialize()),
arrayOf(contractAttachment.serialize().bytes),
ledgerServices.networkParameters.serialize())
.serialize()
.writeTo(output)
}
}
fun writeFailure(output: OutputStream) {
ledgerServices.ledger(DUMMY_NOTARY) {
// Issue a couple of cash states and spend them.
val wtx1 = transaction {
attachments(PROGRAM_ID)
output(PROGRAM_ID, "c1", State(1000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY)))
command(DUMMY_CASH_ISSUER.party.owningKey, Issue())
verifies()
}
val wtx2 = transaction {
attachments(PROGRAM_ID)
output(PROGRAM_ID, "c2", State(2000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY)))
command(DUMMY_CASH_ISSUER.party.owningKey, Issue())
verifies()
}
val wtx3 = transaction {
attachments(PROGRAM_ID)
input("c1")
input("c2")
command(DUMMY_CASH_ISSUER.party.owningKey, SampleCommandData)
output(PROGRAM_ID, "c3", State(3000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MINI_CORP_PUBKEY)))
failsWith("Required ${Move::class.java.canonicalName} command")
}
val contractAttachment = MockContractAttachment(interpreter.services.cordappProvider.getContractAttachmentID(PROGRAM_ID)!!, PROGRAM_ID)
TransactionVerificationRequest(
wtx3.serialize(),
arrayOf(wtx1.serialize(), wtx2.serialize()),
arrayOf(contractAttachment.serialize().bytes),
ledgerServices.networkParameters.serialize())
.serialize()
.writeTo(output)
}
}
}

View File

@ -1,61 +0,0 @@
package net.corda.deterministic;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
import java.security.Security;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
/**
* Temporarily restore Sun's [SecureRandom] provider.
* This is ONLY for allowing us to generate test data, e.g. signatures.
*
* JDK11 upgrade: rewritten in Java to gain access to private internal JDK classes via module directives (not available to Kotlin compiler):
* sun.security.provider.SecureRandom()
*/
public class CheatingSecurityProvider extends Provider implements AutoCloseable {
private static AtomicInteger counter = new AtomicInteger();
@SuppressWarnings("deprecation") // JDK11: should replace with Provider(String name, double version, String info) (since 9)
public CheatingSecurityProvider() {
super("Cheat-" + counter.getAndIncrement(), 1.8, "Cheat security provider");
putService(new CheatingSecureRandomService(this));
assertEquals(1, Security.insertProviderAt(this, 1));
}
public void close() {
Security.removeProvider(getName());
}
private class SunSecureRandom extends SecureRandom {
public SunSecureRandom() {
// JDK11 upgrade: rewritten in Java to gain access to private internal JDK classes via open module directive
super(new sun.security.provider.SecureRandom(), null);
}
}
private class CheatingSecureRandomService extends Provider.Service {
public CheatingSecureRandomService(Provider provider) {
super(provider, "SecureRandom", "CheatingPRNG", CheatingSecureRandomSpi.class.getName(), null, null);
}
private SecureRandomSpi instance = new CheatingSecureRandomSpi();
public Object newInstance(Object constructorParameter){
return instance;
}
}
private class CheatingSecureRandomSpi extends SecureRandomSpi {
private SecureRandom secureRandom = new SunSecureRandom();
public void engineSetSeed(byte[] seed) { secureRandom.setSeed(seed); }
public void engineNextBytes(byte[] bytes) { secureRandom.nextBytes(bytes); }
public byte[] engineGenerateSeed(int numBytes) { return secureRandom.generateSeed(numBytes); }
}
}

View File

@ -1,9 +0,0 @@
package net.corda.core.internal
/**
* Stubbing out non-deterministic method.
*/
fun <T: Any> createInstancesOfClassesImplementing(@Suppress("UNUSED_PARAMETER") classloader: ClassLoader, @Suppress("UNUSED_PARAMETER") clazz: Class<T>,
@Suppress("UNUSED_PARAMETER") classVersionRange: IntRange? = null): Set<T> {
return emptySet()
}

View File

@ -1,70 +0,0 @@
package net.corda.deterministic
import net.corda.core.CordaException
import net.corda.core.contracts.AttachmentResolutionException
import net.corda.core.contracts.TransactionResolutionException
import net.corda.core.contracts.TransactionVerificationException.*
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import org.junit.Assert.*
import org.junit.Test
import java.security.PublicKey
import kotlin.test.assertFailsWith
class CordaExceptionTest {
companion object {
const val CONTRACT_CLASS = "com.r3.corda.contracts.TestContract"
val TEST_HASH = SecureHash.zeroHash
val TX_ID = SecureHash.allOnesHash
val ALICE_NAME = CordaX500Name("Alice Corp", "Madrid", "ES")
val ALICE_KEY: PublicKey = object : PublicKey {
override fun getAlgorithm(): String = "TEST-256"
override fun getFormat(): String = "<none>"
override fun getEncoded() = byteArrayOf()
}
val ALICE = Party(ALICE_NAME, ALICE_KEY)
val BOB_NAME = CordaX500Name("Bob Plc", "Rome", "IT")
val BOB_KEY: PublicKey = object : PublicKey {
override fun getAlgorithm(): String = "TEST-512"
override fun getFormat(): String = "<none>"
override fun getEncoded() = byteArrayOf()
}
val BOB = Party(BOB_NAME, BOB_KEY)
}
@Test(timeout=300_000)
fun testCordaException() {
val ex = assertFailsWith<CordaException> { throw CordaException("BAD THING") }
assertEquals("BAD THING", ex.message)
}
@Test(timeout=300_000)
fun testAttachmentResolutionException() {
val ex = assertFailsWith<AttachmentResolutionException> { throw AttachmentResolutionException(TEST_HASH) }
assertEquals(TEST_HASH, ex.hash)
}
@Test(timeout=300_000)
fun testTransactionResolutionException() {
val ex = assertFailsWith<TransactionResolutionException> { throw TransactionResolutionException(TEST_HASH) }
assertEquals(TEST_HASH, ex.hash)
}
@Test(timeout=300_000)
fun testConflictingAttachmentsRejection() {
val ex = assertFailsWith<ConflictingAttachmentsRejection> { throw ConflictingAttachmentsRejection(TX_ID, CONTRACT_CLASS) }
assertEquals(TX_ID, ex.txId)
assertEquals(CONTRACT_CLASS, ex.contractClass)
}
@Test(timeout=300_000)
fun testNotaryChangeInWrongTransactionType() {
val ex = assertFailsWith<NotaryChangeInWrongTransactionType> { throw NotaryChangeInWrongTransactionType(TX_ID, ALICE, BOB) }
assertEquals(TX_ID, ex.txId)
assertEquals(ALICE, ex.txNotary)
assertEquals(BOB, ex.outputNotary)
}
}

View File

@ -1,44 +0,0 @@
package net.corda.deterministic
import org.junit.AssumptionViolatedException
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import java.security.KeyPair
import java.security.KeyStore
import java.security.PrivateKey
import java.security.cert.TrustAnchor
import java.security.cert.X509Certificate
class KeyStoreProvider(private val storeName: String, private val storePassword: String) : TestRule {
private lateinit var keyStore: KeyStore
private fun loadKeyStoreResource(resourceName: String, password: CharArray, type: String = "PKCS12"): KeyStore {
return KeyStore.getInstance(type).apply {
// Skip these tests if we cannot load the keystore.
val keyStream = KeyStoreProvider::class.java.classLoader.getResourceAsStream(resourceName)
?: throw AssumptionViolatedException("KeyStore $resourceName not found")
keyStream.use { input ->
load(input, password)
}
}
}
override fun apply(statement: Statement, description: Description?): Statement {
return object : Statement() {
override fun evaluate() {
keyStore = loadKeyStoreResource(storeName, storePassword.toCharArray())
statement.evaluate()
}
}
}
fun getKeyPair(alias: String): KeyPair {
val privateKey = keyStore.getKey(alias, storePassword.toCharArray()) as PrivateKey
return KeyPair(keyStore.getCertificate(alias).publicKey, privateKey)
}
@Suppress("UNUSED")
fun trustAnchorsFor(vararg aliases: String): Set<TrustAnchor>
= aliases.map { alias -> TrustAnchor(keyStore.getCertificate(alias) as X509Certificate, null) }.toSet()
}

View File

@ -1,14 +0,0 @@
package net.corda.deterministic
import java.io.ByteArrayOutputStream
import java.io.IOException
private val classLoader: ClassLoader = object {}.javaClass.classLoader
@Throws(IOException::class)
fun bytesOfResource(resourceName: String): ByteArray {
return ByteArrayOutputStream().let { baos ->
classLoader.getResourceAsStream(resourceName).copyTo(baos)
baos.toByteArray()
}
}

View File

@ -1,79 +0,0 @@
package net.corda.deterministic.contracts
import net.corda.core.contracts.Attachment
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.security.PublicKey
import java.util.jar.JarOutputStream
import java.util.zip.Deflater.*
import java.util.zip.ZipEntry
class AttachmentTest {
private companion object {
private val data = byteArrayOf(0x73, 0x71, 0x18, 0x5F, 0x3A, 0x47, -0x22, 0x38)
private val jarData: ByteArray = ByteArrayOutputStream().let { baos ->
JarOutputStream(baos).use { jar ->
jar.setLevel(BEST_COMPRESSION)
jar.putNextEntry(ZipEntry("data.bin").apply { method = DEFLATED })
data.inputStream().copyTo(jar)
}
baos.toByteArray()
}
private val ALICE_NAME = CordaX500Name("Alice Corp", "Madrid", "ES")
private val ALICE_KEY: PublicKey = object : PublicKey {
override fun getAlgorithm(): String = "TEST-256"
override fun getFormat(): String = "<none>"
override fun getEncoded() = byteArrayOf()
}
private val ALICE = Party(ALICE_NAME, ALICE_KEY)
}
private lateinit var attachment: Attachment
@Before
fun setup() {
attachment = object : Attachment {
override val signerKeys: List<PublicKey>
get() = listOf(ALICE_KEY)
override val id: SecureHash
get() = SecureHash.allOnesHash
override val signers: List<Party>
get() = listOf(ALICE)
override val size: Int
get() = jarData.size
override fun open(): InputStream {
return jarData.inputStream()
}
}
}
@Test(timeout=300_000)
fun testAttachmentJar() {
attachment.openAsJAR().use { jar ->
val entry = jar.nextJarEntry ?: return@use
assertEquals("data.bin", entry.name)
val entryData = ByteArrayOutputStream().use {
jar.copyTo(it)
it.toByteArray()
}
assertArrayEquals(data, entryData)
}
}
@Test(timeout=300_000)
fun testExtractFromAttachment() {
val resultData = ByteArrayOutputStream().use {
attachment.extractFile("data.bin", it)
it.toByteArray()
}
assertArrayEquals(data, resultData)
}
}

View File

@ -1,28 +0,0 @@
package net.corda.deterministic.contracts
import net.corda.core.contracts.PrivacySalt
import org.junit.Test
import kotlin.test.*
class PrivacySaltTest {
private companion object {
private const val SALT_SIZE = 32
}
@Test(timeout=300_000)
fun testValidSalt() {
PrivacySalt(ByteArray(SALT_SIZE) { 0x14 })
}
@Test(timeout=300_000)
fun testInvalidSaltWithAllZeros() {
val ex = assertFailsWith<IllegalArgumentException> { PrivacySalt(ByteArray(SALT_SIZE)) }
assertEquals("Privacy salt should not be all zeros.", ex.message)
}
@Test(timeout=300_000)
fun testTooShortPrivacySaltForSHA256() {
val ex = assertFailsWith<IllegalArgumentException> { PrivacySalt(ByteArray(SALT_SIZE - 1) { 0x7f }) }
assertEquals("Privacy salt should be at least 32 bytes.", ex.message)
}
}

View File

@ -1,37 +0,0 @@
package net.corda.deterministic.contracts
import net.corda.core.contracts.UniqueIdentifier
import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert.*
import org.junit.Test
import java.util.*
import kotlin.reflect.full.primaryConstructor
import kotlin.test.assertFailsWith
class UniqueIdentifierTest {
private companion object {
private const val NAME = "MyName"
private val TEST_UUID: UUID = UUID.fromString("00000000-1111-2222-3333-444444444444")
}
@Test(timeout=300_000)
fun testNewInstance() {
val id = UniqueIdentifier(NAME, TEST_UUID)
assertEquals("${NAME}_$TEST_UUID", id.toString())
assertEquals(NAME, id.externalId)
assertEquals(TEST_UUID, id.id)
}
@Test(timeout=300_000)
fun testPrimaryConstructor() {
val primary = UniqueIdentifier::class.primaryConstructor ?: throw AssertionError("primary constructor missing")
assertThat(primary.call(NAME, TEST_UUID)).isEqualTo(UniqueIdentifier(NAME, TEST_UUID))
}
@Test(timeout=300_000)
fun testConstructors() {
assertEquals(1, UniqueIdentifier::class.constructors.size)
val ex = assertFailsWith<IllegalArgumentException> { UniqueIdentifier::class.constructors.first().call() }
assertThat(ex).hasMessage("Callable expects 2 arguments, but 0 were provided.")
}
}

View File

@ -1,68 +0,0 @@
@file:JvmName("CryptoSignUtils")
package net.corda.deterministic.crypto
import net.corda.core.crypto.*
import net.corda.core.crypto.Crypto.findSignatureScheme
import net.corda.core.crypto.Crypto.isSupportedSignatureScheme
import net.corda.core.serialization.serialize
import java.security.*
/**
* This is a slightly modified copy of signing utils from net.corda.core.crypto.Crypto, which are normally removed from DJVM.
* However, we need those for TransactionSignatureTest.
*/
object CryptoSignUtils {
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
return doSign(findSignatureScheme(schemeCodeName), privateKey, clearData)
}
/**
* Generic way to sign [ByteArray] data with a [PrivateKey] and a known [Signature].
* @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto].
* @param privateKey the signer's [PrivateKey].
* @param clearData the data/message to be signed in [ByteArray] form (usually the Merkle root).
* @return the digital signature (in [ByteArray]) on the input message.
* @throws IllegalArgumentException if the signature scheme is not supported for this private key.
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
require(isSupportedSignatureScheme(signatureScheme)) {
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
}
require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" }
val signature = Signature.getInstance(signatureScheme.signatureName, signatureScheme.providerName)
signature.initSign(privateKey)
signature.update(clearData)
return signature.sign()
}
/**
* Generic way to sign [SignableData] objects with a [PrivateKey].
* [SignableData] is a wrapper over the transaction's id (Merkle root) in order to attach extra information, such as
* a timestamp or partial and blind signature indicators.
* @param keyPair the signer's [KeyPair].
* @param signableData a [SignableData] object that adds extra information to a transaction.
* @return a [TransactionSignature] object than contains the output of a successful signing, signer's public key and
* the signature metadata.
* @throws IllegalArgumentException if the signature scheme is not supported for this private key.
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature {
val sigKey: SignatureScheme = findSignatureScheme(keyPair.private)
val sigMetaData: SignatureScheme = findSignatureScheme(keyPair.public)
require(sigKey == sigMetaData) {
"Metadata schemeCodeName: ${sigMetaData.schemeCodeName} is not aligned with the key type: ${sigKey.schemeCodeName}."
}
val signatureBytes = doSign(sigKey.schemeCodeName, keyPair.private, signableData.serialize().bytes)
return TransactionSignature(signatureBytes, keyPair.public, signableData.signatureMetadata)
}
}

View File

@ -1,50 +0,0 @@
package net.corda.deterministic.crypto
import net.corda.core.crypto.DigestService
import net.corda.core.crypto.MerkleTree
import net.corda.core.crypto.SecureHash
import org.junit.Assert.assertEquals
import org.junit.Test
class MerkleTreeTest {
private fun leafs(algorithm : String) : List<SecureHash> =
listOf(SecureHash.allOnesHashFor(algorithm), SecureHash.zeroHashFor(algorithm))
@Test(timeout=300_000)
fun testCreate() {
val merkle = MerkleTree.getMerkleTree(leafs(SecureHash.SHA2_256), DigestService.sha2_256)
assertEquals(SecureHash.create("A5DE9B714ACCD8AFAAABF1CBD6E1014C9D07FF95C2AE154D91EC68485B31E7B5"), merkle.hash)
}
@Test(timeout=300_000)
fun `test create SHA2-384`() {
val merkle = MerkleTree.getMerkleTree(leafs(SecureHash.SHA2_384), DigestService.sha2_384)
assertEquals(SecureHash.create("SHA-384:2B83D37859E3665D7C239964D769CF950EE6478C13E4CA2D6643C23B6C4EAE035C88F654D22E0D65E7CA40BAE4F3718F"), merkle.hash)
}
@Test(timeout=300_000)
fun `test create SHA2-256 to SHA2-384`() {
val merkle = MerkleTree.getMerkleTree(leafs(SecureHash.SHA2_256), DigestService.sha2_384)
assertEquals(SecureHash.create("SHA-384:02A4E8EA5AA4BBAFE80C0E7127B15994B84030BE8616EA2A0127D85203CF34221403635C08084A6BDDB1DB06333F0A49"), merkle.hash)
}
// @Test(timeout=300_000)
// fun testCreateSHA3256() {
// val merkle = MerkleTree.getMerkleTree(listOf(SecureHash.allOnesHashFor(SecureHash.SHA3_256),
// SecureHash.zeroHashFor(SecureHash.SHA3_256)), DigestService.sha3_256)
// assertEquals(SecureHash.create("SHA3-256:80673DBEEC8F6761ACBB121E7E45F61D4279CCD8B8E2231741ECD0716F4C9EDC"), merkle.hash)
// }
//
// @Test(timeout=300_000)
// fun testCreateSHA2256toSHA3256() {
// val merkle = MerkleTree.getMerkleTree(listOf(SecureHash.allOnesHash, SecureHash.zeroHash), DigestService.sha3_256)
// assertEquals(SecureHash.create("SHA3-256:80673DBEEC8F6761ACBB121E7E45F61D4279CCD8B8E2231741ECD0716F4C9EDC"), merkle.hash)
// }
//
// @Test(timeout=300_000)
// fun testCreateSHA3256toSHA2256() {
// val merkle = MerkleTree.getMerkleTree(listOf(SecureHash.allOnesHashFor(SecureHash.SHA3_256),
// SecureHash.zeroHashFor(SecureHash.SHA3_256)), DigestService.sha2_256)
// assertEquals(SecureHash.create("A5DE9B714ACCD8AFAAABF1CBD6E1014C9D07FF95C2AE154D91EC68485B31E7B5"), merkle.hash)
// }
}

View File

@ -1,42 +0,0 @@
package net.corda.deterministic.crypto
import net.corda.core.crypto.SecureHash
import org.bouncycastle.util.encoders.Hex
import org.junit.Assert.*
import org.junit.Test
import java.security.MessageDigest
class SecureHashTest {
@Test(timeout=300_000)
fun testSHA256() {
val hash = SecureHash.sha256(byteArrayOf(0x64, -0x13, 0x42, 0x3a))
assertEquals(SecureHash.create("6D1687C143DF792A011A1E80670A4E4E0C25D0D87A39514409B1ABFC2043581F"), hash)
assertEquals("6D1687C143DF792A011A1E80670A4E4E0C25D0D87A39514409B1ABFC2043581F", hash.toString())
}
@Test(timeout=300_000)
fun testPrefix() {
val data = byteArrayOf(0x7d, 0x03, -0x21, 0x32, 0x56, 0x47)
val digest = data.digestFor("SHA-256")
val prefix = SecureHash.sha256(data).prefixChars(8)
assertEquals(Hex.toHexString(digest).substring(0, 8).toUpperCase(), prefix)
}
@Test(timeout=300_000)
fun testConcat() {
val hash1 = SecureHash.sha256(byteArrayOf(0x7d, 0x03, -0x21, 0x32, 0x56, 0x47))
val hash2 = SecureHash.sha256(byteArrayOf(0x63, 0x01, 0x7f, -0x29, 0x1e, 0x3c))
val combined = hash1.hashConcat(hash2)
assertArrayEquals((hash1.bytes + hash2.bytes).digestFor("SHA-256"), combined.bytes)
}
@Test(timeout=300_000)
fun testConstants() {
assertArrayEquals(SecureHash.zeroHash.bytes, ByteArray(32))
assertArrayEquals(SecureHash.allOnesHash.bytes, ByteArray(32) { 0xFF.toByte() })
}
}
private fun ByteArray.digestFor(algorithm: String): ByteArray {
return MessageDigest.getInstance(algorithm).digest(this)
}

View File

@ -1,22 +0,0 @@
package net.corda.deterministic.crypto
import net.corda.core.crypto.CordaSecurityProvider
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import kotlin.test.assertFailsWith
class SecureRandomTest {
private companion object {
init {
CordaSecurityProvider()
}
}
@Test(timeout=300_000)
fun testNoCordaPRNG() {
val error = assertFailsWith<NoSuchAlgorithmException> { SecureRandom.getInstance("CordaPRNG") }
assertThat(error).hasMessage("CordaPRNG SecureRandom not available")
}
}

View File

@ -1,143 +0,0 @@
package net.corda.deterministic.crypto
import net.corda.core.crypto.*
import net.corda.deterministic.KeyStoreProvider
import net.corda.deterministic.CheatingSecurityProvider
import net.corda.deterministic.verifier.LocalSerializationRule
import org.junit.*
import org.junit.rules.RuleChain
import java.security.*
import kotlin.test.*
class TransactionSignatureTest {
companion object {
private const val KEYSTORE_PASSWORD = "deterministic"
private val testBytes = "12345678901234567890123456789012".toByteArray()
private val keyStoreProvider = KeyStoreProvider("keystore/txsignature.pfx", KEYSTORE_PASSWORD)
private lateinit var keyPair: KeyPair
@ClassRule
@JvmField
val rules: RuleChain = RuleChain.outerRule(LocalSerializationRule(TransactionSignatureTest::class))
.around(keyStoreProvider)
@BeforeClass
@JvmStatic
fun setupClass() {
keyPair = keyStoreProvider.getKeyPair("tx")
}
}
/** Valid sign and verify. */
@Test(timeout=300_000)
fun `Signature metadata full sign and verify`() {
// Create a SignableData object.
val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
// Sign the meta object.
val transactionSignature: TransactionSignature = CheatingSecurityProvider().use {
CryptoSignUtils.doSign(keyPair, signableData)
}
// Check auto-verification.
assertTrue(transactionSignature.verify(testBytes.sha256()))
// Check manual verification.
assertTrue(Crypto.doVerify(testBytes.sha256(), transactionSignature))
}
/** Verification should fail; corrupted metadata - clearData (Merkle root) has changed. */
@Test(expected = SignatureException::class)
fun `Signature metadata full failure clearData has changed`() {
val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
val transactionSignature = CheatingSecurityProvider().use {
CryptoSignUtils.doSign(keyPair, signableData)
}
Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature)
}
@Test(timeout=300_000)
fun `Verify multi-tx signature`() {
// Deterministically create 5 txIds.
val txIds: List<SecureHash> = IntRange(0, 4).map { byteArrayOf(it.toByte()).sha256() }
// Multi-tx signature.
val txSignature = signMultipleTx(txIds, keyPair)
// The hash of all txIds are used as leaves.
val merkleTree = MerkleTree.getMerkleTree(txIds.map { it.sha256() }, DigestService.default)
// We haven't added the partial tree yet.
assertNull(txSignature.partialMerkleTree)
// Because partial tree is still null, but we signed over a block of txs, verifying a single tx will fail.
assertFailsWith<SignatureException> { Crypto.doVerify(txIds[3], txSignature) }
// Create a partial tree for one tx.
val pmt = PartialMerkleTree.build(merkleTree, listOf(txIds[0].sha256()))
// Add the partial Merkle tree to the tx signature.
val txSignatureWithTree = TransactionSignature(txSignature.bytes, txSignature.by, txSignature.signatureMetadata, pmt)
// Verify the corresponding txId with every possible way.
assertTrue(Crypto.doVerify(txIds[0], txSignatureWithTree))
assertTrue(txSignatureWithTree.verify(txIds[0]))
assertTrue(Crypto.isValid(txIds[0], txSignatureWithTree))
assertTrue(txSignatureWithTree.isValid(txIds[0]))
// Verify the rest txs in the block, which are not included in the partial Merkle tree.
txIds.subList(1, txIds.size).forEach {
assertFailsWith<IllegalArgumentException> { Crypto.doVerify(it, txSignatureWithTree) }
}
// Test that the Merkle tree consists of hash(txId), not txId.
assertFailsWith<MerkleTreeException> { PartialMerkleTree.build(merkleTree, listOf(txIds[0])) }
// What if we send the Full tree. This could be used if notaries didn't want to create a per tx partial tree.
// Create a partial tree for all txs, thus all leaves are included.
val pmtFull = PartialMerkleTree.build(merkleTree, txIds.map { it.sha256() })
// Add the partial Merkle tree to the tx.
val txSignatureWithFullTree = TransactionSignature(txSignature.bytes, txSignature.by, txSignature.signatureMetadata, pmtFull)
// All txs can be verified, as they are all included in the provided partial tree.
txIds.forEach {
assertTrue(Crypto.doVerify(it, txSignatureWithFullTree))
}
}
@Test(timeout=300_000)
fun `Verify one-tx signature`() {
val txId = "aTransaction".toByteArray().sha256()
// One-tx signature.
val txSignature = try {
signOneTx(txId, keyPair)
} catch (e: Throwable) {
e.cause?.printStackTrace()
throw e
}
// partialMerkleTree should be null.
assertNull(txSignature.partialMerkleTree)
// Verify the corresponding txId with every possible way.
assertTrue(Crypto.doVerify(txId, txSignature))
assertTrue(txSignature.verify(txId))
assertTrue(Crypto.isValid(txId, txSignature))
assertTrue(txSignature.isValid(txId))
// We signed the txId itself, not its hash (because it was a signature over one tx only and no partial tree has been received).
assertFailsWith<SignatureException> { Crypto.doVerify(txId.sha256(), txSignature) }
}
// Returns a TransactionSignature over the Merkle root, but the partial tree is null.
private fun signMultipleTx(txIds: List<SecureHash>, keyPair: KeyPair): TransactionSignature {
val merkleTreeRoot = MerkleTree.getMerkleTree(txIds.map { it.sha256() }, DigestService.default).hash
return signOneTx(merkleTreeRoot, keyPair)
}
// Returns a TransactionSignature over one SecureHash.
// Note that if one tx is to be signed, we don't create a Merkle tree and we directly sign over the txId.
private fun signOneTx(txId: SecureHash, keyPair: KeyPair): TransactionSignature {
val signableData = SignableData(txId, SignatureMetadata(3, Crypto.findSignatureScheme(keyPair.public).schemeNumberID))
return CheatingSecurityProvider().use {
CryptoSignUtils.doSign(keyPair, signableData)
}
}
}

View File

@ -1,30 +0,0 @@
package net.corda.deterministic.transactions
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.TransactionSignature
import net.corda.core.transactions.TransactionWithSignatures
import org.junit.Test
import java.security.PublicKey
class TransactionWithSignaturesTest {
@Test(timeout=300_000)
fun txWithSigs() {
val tx = object : TransactionWithSignatures {
override val id: SecureHash
get() = SecureHash.zeroHash
override val requiredSigningKeys: Set<PublicKey>
get() = emptySet()
override val sigs: List<TransactionSignature>
get() = emptyList()
override fun getKeyDescriptions(keys: Set<PublicKey>): List<String> {
return emptyList()
}
}
tx.verifyRequiredSignatures()
tx.checkSignaturesAreValid()
tx.getMissingSigners()
tx.verifySignaturesExcept()
tx.verifySignaturesExcept(emptySet())
}
}

View File

@ -1,29 +0,0 @@
package net.corda.deterministic.txverify
import net.corda.deterministic.bytesOfResource
import net.corda.deterministic.verifier.LocalSerializationRule
import net.corda.deterministic.verifier.verifyTransaction
import net.corda.finance.contracts.asset.Cash.Commands.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import kotlin.test.assertFailsWith
class VerifyTransactionTest {
companion object {
@ClassRule
@JvmField
val serialization = LocalSerializationRule(VerifyTransactionTest::class)
}
@Test(timeout=300_000)
fun success() {
verifyTransaction(bytesOfResource("txverify/tx-success.bin"))
}
@Test(timeout=300_000)
fun failure() {
val e = assertFailsWith<Exception> { verifyTransaction(bytesOfResource("txverify/tx-failure.bin")) }
assertThat(e).hasMessageContaining("Required ${Move::class.java.canonicalName} command")
}
}

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Appenders>
<Console name="Console-Appender" target="SYSTEM_OUT">
<PatternLayout pattern="%date %highlight{%level %c{1}.%method - %msg%n}{INFO=white,WARN=red,FATAL=bright red}"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console-Appender"/>
</Root>
</Loggers>
</Configuration>

View File

@ -1,56 +0,0 @@
plugins {
id 'java-library'
id 'net.corda.plugins.publish-utils'
id 'com.jfrog.artifactory'
id 'idea'
}
apply from: "${rootProject.projectDir}/deterministic.gradle"
description 'Test utilities for deterministic contract verification'
configurations {
deterministicArtifacts {
canBeResolved = false
}
// Compile against the deterministic artifacts to ensure that we use only the deterministic API subset.
compileOnly.extendsFrom deterministicArtifacts
runtimeArtifacts.extendsFrom api
}
dependencies {
deterministicArtifacts project(path: ':serialization-deterministic', configuration: 'deterministicArtifacts')
deterministicArtifacts project(path: ':core-deterministic', configuration: 'deterministicArtifacts')
runtimeArtifacts project(':serialization')
runtimeArtifacts project(':core')
api "junit:junit:$junit_version"
runtimeOnly "org.junit.vintage:junit-vintage-engine:$junit_vintage_version"
}
jar {
archiveBaseName = 'corda-deterministic-verifier'
}
artifacts {
deterministicArtifacts jar
runtimeArtifacts jar
publish jar
}
publish {
// Our published POM will contain dependencies on the non-deterministic Corda artifacts.
dependenciesFrom(configurations.runtimeArtifacts) {
defaultScope = 'compile'
}
name jar.archiveBaseName.get()
}
idea {
module {
if (project.hasProperty("deterministic_idea_sdk")) {
jdkName project.property("deterministic_idea_sdk") as String
}
}
}

View File

@ -1,82 +0,0 @@
package net.corda.deterministic.verifier
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationContext.UseCase.P2P
import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.internal.SerializationEnvironment
import net.corda.core.serialization.internal._driverSerializationEnv
import net.corda.serialization.internal.*
import net.corda.serialization.internal.amqp.*
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import kotlin.reflect.KClass
import kotlin.reflect.jvm.jvmName
class LocalSerializationRule(private val label: String) : TestRule {
constructor(klass: KClass<*>) : this(klass.jvmName)
private companion object {
private val AMQP_P2P_CONTEXT = SerializationContextImpl(
amqpMagic,
LocalSerializationRule::class.java.classLoader,
GlobalTransientClassWhiteList(BuiltInExceptionsWhitelist()),
emptyMap(),
true,
P2P,
null
)
}
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
init()
try {
base.evaluate()
} finally {
clear()
}
}
}
}
fun reset() {
clear()
init()
}
private fun init() {
_driverSerializationEnv.set(createTestSerializationEnv())
}
private fun clear() {
_driverSerializationEnv.set(null)
}
private fun createTestSerializationEnv(): SerializationEnvironment {
val factory = SerializationFactoryImpl(mutableMapOf()).apply {
registerScheme(AMQPSerializationScheme(emptySet(), emptySet(), AccessOrderLinkedHashMap(128)))
}
return SerializationEnvironment.with(factory, AMQP_P2P_CONTEXT)
}
private class AMQPSerializationScheme(
cordappCustomSerializers: Set<SerializationCustomSerializer<*, *>>,
cordappSerializationWhitelists: Set<SerializationWhitelist>,
serializerFactoriesForContexts: AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>
) : AbstractAMQPSerializationScheme(cordappCustomSerializers, cordappSerializationWhitelists, serializerFactoriesForContexts) {
override fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory {
throw UnsupportedOperationException()
}
override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory {
throw UnsupportedOperationException()
}
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean {
return canDeserializeVersion(magic) && target == P2P
}
}
}

View File

@ -1,19 +0,0 @@
package net.corda.deterministic.verifier
import net.corda.core.contracts.ContractClassName
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.Party
import net.corda.core.internal.AbstractAttachment
import net.corda.core.serialization.CordaSerializable
import java.security.PublicKey
// A valid zip file with 1 entry.
val simpleZip = byteArrayOf(80, 75, 3, 4, 20, 0, 8, 8, 8, 0, 15, 113, 79, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 47, 97, -2, -54, 0, 0, 75, 4, 0, 80, 75, 7, 8, 67, -66, -73, -24, 3, 0, 0, 0, 1, 0, 0, 0, 80, 75, 1, 2, 20, 0, 20, 0, 8, 8, 8, 0, 15, 113, 79, 78, 67, -66, -73, -24, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 97, -2, -54, 0, 0, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0, 1, 0, 52, 0, 0, 0, 55, 0, 0, 0, 0, 0)
@CordaSerializable
class MockContractAttachment(
override val id: SecureHash = SecureHash.zeroHash,
val contract: ContractClassName,
override val signerKeys: List<PublicKey> = emptyList(),
override val signers: List<Party> = emptyList()
) : AbstractAttachment({ simpleZip }, "app")

View File

@ -1,6 +0,0 @@
@file:JvmName("SampleData")
package net.corda.deterministic.verifier
import net.corda.core.contracts.TypeOnlyCommandData
object SampleCommandData : TypeOnlyCommandData()

View File

@ -1,35 +0,0 @@
package net.corda.deterministic.verifier
import net.corda.core.contracts.Attachment
import net.corda.core.contracts.ContractAttachment
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
import net.corda.core.internal.toLtxDjvmInternal
import net.corda.core.node.NetworkParameters
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.WireTransaction
@Suppress("MemberVisibilityCanBePrivate")
//TODO the use of deprecated toLedgerTransaction need to be revisited as resolveContractAttachment requires attachments of the transactions which created input states...
//TODO ...to check contract version non downgrade rule, currently dummy Attachment if not fund is used which sets contract version to '1'
@CordaSerializable
class TransactionVerificationRequest(val wtxToVerify: SerializedBytes<WireTransaction>,
val dependencies: Array<SerializedBytes<WireTransaction>>,
val attachments: Array<ByteArray>,
val networkParameters: SerializedBytes<NetworkParameters>) {
fun toLedgerTransaction(): LedgerTransaction {
val deps = dependencies.map { it.deserialize() }.associateBy(WireTransaction::id)
val attachments = attachments.map { it.deserialize<Attachment>() }
val attachmentMap = attachments
.mapNotNull { it as? MockContractAttachment }
.associateBy(Attachment::id) { ContractAttachment(it, it.contract, uploader = DEPLOYED_CORDAPP_UPLOADER) }
@Suppress("DEPRECATION")
return wtxToVerify.deserialize().toLtxDjvmInternal(
resolveAttachment = { attachmentMap[it] },
resolveStateRef = { deps[it.txhash]?.outputs?.get(it.index) },
resolveParameters = { networkParameters.deserialize() }
)
}
}

View File

@ -1,21 +0,0 @@
@file:JvmName("Verifier")
package net.corda.deterministic.verifier
import net.corda.core.serialization.deserialize
import net.corda.core.transactions.LedgerTransaction
/**
* We assume the signatures were already checked outside the sandbox: the purpose of this code
* is simply to check the sensitive, app-specific parts of a transaction.
*
* TODO: Transaction data is meant to be encrypted under an enclave-private key.
*/
@Throws(Exception::class)
fun verifyTransaction(reqBytes: ByteArray) {
deserialize(reqBytes).verify()
}
private fun deserialize(reqBytes: ByteArray): LedgerTransaction {
return reqBytes.deserialize<TransactionVerificationRequest>()
.toLedgerTransaction()
}

View File

@ -93,6 +93,8 @@ dependencies {
smokeTestCompile project(':smoke-test-utils')
smokeTestCompile "org.assertj:assertj-core:${assertj_version}"
// used by FinalityFlowTests
testCompile project(':testing:cordapps:cashobservers')
}
configurations {

View File

@ -22,6 +22,7 @@ import net.corda.core.crypto.SecureHash.Companion.allOnesHash
import net.corda.core.crypto.SecureHash.Companion.zeroHash
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.sign
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.canBeTransitionedFrom
@ -61,6 +62,7 @@ class ConstraintsPropagationTests {
val testSerialization = SerializationEnvironmentRule()
private companion object {
val DUMMY_NOTARY_IDENTITY = TestIdentity(DUMMY_NOTARY_NAME, 20)
val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party
val ALICE = TestIdentity(CordaX500Name("ALICE", "London", "GB"))
val ALICE_PARTY get() = ALICE.party
@ -389,7 +391,8 @@ class ConstraintsPropagationTests {
requireSupportedHashType(wireTransaction)
val nodeKey = ALICE_PUBKEY
val sigs = listOf(keyManagementService.sign(
SignableData(wireTransaction.id, SignatureMetadata(4, Crypto.findSignatureScheme(nodeKey).schemeNumberID)), nodeKey))
SignableData(wireTransaction.id, SignatureMetadata(4, Crypto.findSignatureScheme(nodeKey).schemeNumberID)), nodeKey),
DUMMY_NOTARY_IDENTITY.keyPair.sign(SignableData(wireTransaction.id, SignatureMetadata(4, Crypto.findSignatureScheme(DUMMY_NOTARY_IDENTITY.publicKey).schemeNumberID))))
recordTransactions(SignedTransaction(wireTransaction, sigs))
}

View File

@ -30,7 +30,7 @@ import java.util.*
class ContractUpgradeFlowTest : WithContracts, WithFinality {
companion object {
private val classMockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()))
private val classMockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP, DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()))
@JvmStatic
@AfterClass

View File

@ -1,32 +1,95 @@
package net.corda.coretests.flows
import co.paralleluniverse.fibers.Suspendable
import com.natpryce.hamkrest.and
import com.natpryce.hamkrest.assertion.assertThat
import net.corda.core.contracts.Amount
import net.corda.core.contracts.PartyAndReference
import net.corda.core.contracts.StateAndContract
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.TransactionVerificationException
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.TransactionSignature
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowException
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.NotaryError
import net.corda.core.flows.NotaryException
import net.corda.core.flows.NotarySigCheck
import net.corda.core.flows.ReceiveFinalityFlow
import net.corda.core.flows.ReceiveTransactionFlow
import net.corda.core.flows.ReceiverDistributionRecord
import net.corda.core.flows.SendTransactionFlow
import net.corda.core.flows.SenderDistributionRecord
import net.corda.core.flows.StartableByRPC
import net.corda.core.flows.UnexpectedFlowEndException
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.FetchDataFlow
import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.internal.PlatformVersionSwitches
import net.corda.core.internal.ServiceHubCoreInternal
import net.corda.core.node.StatesToRecord
import net.corda.core.node.services.TransactionStatus
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.coretests.flows.WithFinality.FinalityInvoker
import net.corda.finance.POUNDS
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.issuedBy
import net.corda.testing.core.*
import net.corda.core.utilities.unwrap
import net.corda.coretesting.internal.matchers.flow.willReturn
import net.corda.coretesting.internal.matchers.flow.willThrow
import net.corda.testing.node.internal.*
import net.corda.coretests.flows.WithFinality.FinalityInvoker
import net.corda.coretests.flows.WithFinality.OldFinalityInvoker
import net.corda.finance.GBP
import net.corda.finance.POUNDS
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.finance.issuedBy
import net.corda.finance.test.flows.CashIssueWithObserversFlow
import net.corda.finance.test.flows.CashPaymentWithObserversFlow
import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery.DBReceiverDistributionRecord
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord
import net.corda.node.services.persistence.HashedDistributionList
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.CHARLIE_NAME
import net.corda.testing.core.TestIdentity
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.MOCK_VERSION_INFO
import net.corda.testing.node.internal.TestCordappInternal
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappWithPackages
import net.corda.testing.node.internal.enclosedCordapp
import net.corda.testing.node.internal.findCordapp
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Assert.assertNotNull
import org.junit.Test
import java.sql.SQLException
import java.util.Random
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.fail
class FinalityFlowTests : WithFinality {
companion object {
private val CHARLIE = TestIdentity(CHARLIE_NAME, 90).party
}
override val mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, enclosedCordapp(),
CustomCordapp(targetPlatformVersion = 3, classes = setOf(FinalityFlow::class.java))))
override val mockNet = InternalMockNetwork(cordappsForAllNodes = setOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP, DUMMY_CONTRACTS_CORDAPP, enclosedCordapp(),
findCordapp("net.corda.finance.test.flows")))
private val aliceNode = makeNode(ALICE_NAME)
private val notary = mockNet.defaultNotaryIdentity
@ -60,9 +123,8 @@ class FinalityFlowTests : WithFinality {
fun `allow use of the old API if the CorDapp target version is 3`() {
val oldBob = createBob(cordapps = listOf(tokenOldCordapp()))
val stx = aliceNode.issuesCashTo(oldBob)
@Suppress("DEPRECATION")
aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture.getOrThrow()
assertThat(oldBob.services.validatedTransactions.getTransaction(stx.id)).isNotNull()
aliceNode.startFlowAndRunNetwork(OldFinalityInvoker(stx)).resultFuture.getOrThrow()
assertThat(oldBob.services.validatedTransactions.getTransaction(stx.id)).isNotNull
}
@Test(timeout=300_000)
@ -76,12 +138,498 @@ class FinalityFlowTests : WithFinality {
oldRecipients = setOf(oldBob.info.singleIdentity())
)).resultFuture
resultFuture.getOrThrow()
assertThat(newCharlie.services.validatedTransactions.getTransaction(stx.id)).isNotNull()
assertThat(oldBob.services.validatedTransactions.getTransaction(stx.id)).isNotNull()
assertThat(newCharlie.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(oldBob.services.validatedTransactions.getTransaction(stx.id)).isNotNull
}
private fun createBob(cordapps: List<TestCordappInternal> = emptyList()): TestStartedNode {
return mockNet.createNode(InternalMockNodeParameters(legalName = BOB_NAME, additionalCordapps = cordapps))
@Test(timeout=300_000)
fun `two phase finality flow transaction`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val stx = aliceNode.startFlow(CashIssueFlow(Amount(1000L, GBP), OpaqueBytes.of(1), notary)).resultFuture.getOrThrow().stx
aliceNode.startFlowAndRunNetwork(CashPaymentFlow(Amount(100, GBP), bobNode.info.singleIdentity())).resultFuture.getOrThrow()
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
}
@Test(timeout=300_000)
fun `two phase finality flow initiator to pre-2PF peer`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY - 1)
val stx = aliceNode.startFlow(CashIssueFlow(Amount(1000L, GBP), OpaqueBytes.of(1), notary)).resultFuture.getOrThrow().stx
aliceNode.startFlowAndRunNetwork(CashPaymentFlow(Amount(100, GBP), bobNode.info.singleIdentity())).resultFuture.getOrThrow()
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
}
@Test(timeout=300_000)
fun `pre-2PF initiator to two phase finality flow peer`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY - 1)
val stx = bobNode.startFlow(CashIssueFlow(Amount(1000L, GBP), OpaqueBytes.of(1), notary)).resultFuture.getOrThrow().stx
bobNode.startFlowAndRunNetwork(CashPaymentFlow(Amount(100, GBP), aliceNode.info.singleIdentity())).resultFuture.getOrThrow()
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
}
@Test(timeout=300_000)
fun `two phase finality flow double spend transaction`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val ref = aliceNode.startFlowAndRunNetwork(IssueFlow(notary)).resultFuture.getOrThrow()
val stx = aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
val (_, txnStatusAlice) = aliceNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusAlice)
val (_, txnStatusBob) = bobNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusBob)
try {
aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
}
catch (e: NotaryException) {
val stxId = (e.error as NotaryError.Conflict).txId
assertNull(aliceNode.services.validatedTransactions.getTransactionWithStatus(stxId))
// Note: double spend error not propagated to peers by default (corDapp PV = 3)
// Un-notarised txn clean-up occurs in ReceiveFinalityFlow upon receipt of UnexpectedFlowEndException
assertNull(aliceNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(aliceNode, stxId)
}
}
@Test(timeout=300_000)
fun `two phase finality flow double spend transaction with double spend handling`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val ref = aliceNode.startFlowAndRunNetwork(IssueFlow(notary)).resultFuture.getOrThrow()
val stx = aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
val (_, txnStatusAlice) = aliceNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusAlice)
val (_, txnStatusBob) = bobNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusBob)
try {
aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity(), handlePropagatedNotaryError = true)).resultFuture.getOrThrow()
}
catch (e: NotaryException) {
val stxId = (e.error as NotaryError.Conflict).txId
assertNull(aliceNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(aliceNode, stxId)
assertNull(bobNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(bobNode, stxId)
}
try {
aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity(), handlePropagatedNotaryError = false)).resultFuture.getOrThrow()
}
catch (e: NotaryException) {
val stxId = (e.error as NotaryError.Conflict).txId
assertNull(aliceNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(aliceNode, stxId)
val (_, txnStatus) = bobNode.services.validatedTransactions.getTransactionWithStatus(stxId) ?: fail()
assertEquals(TransactionStatus.IN_FLIGHT, txnStatus)
}
}
private fun assertTxnRemovedFromDatabase(node: TestStartedNode, stxId: SecureHash) {
val fromDb = node.database.transaction {
session.createQuery(
"from ${DBTransactionStorage.DBTransaction::class.java.name} where tx_id = :transactionId",
DBTransactionStorage.DBTransaction::class.java
).setParameter("transactionId", stxId.toString()).resultList
}
assertEquals(0, fromDb.size)
}
@Test(timeout=300_000)
fun `two phase finality flow double spend transaction from pre-2PF initiator`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY - 1)
val ref = bobNode.startFlowAndRunNetwork(IssueFlow(notary)).resultFuture.getOrThrow()
val stx = bobNode.startFlowAndRunNetwork(SpendFlow(ref, aliceNode.info.singleIdentity())).resultFuture.getOrThrow()
val (_, txnStatusAlice) = aliceNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusAlice)
val (_, txnStatusBob) = bobNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusBob)
try {
bobNode.startFlowAndRunNetwork(SpendFlow(ref, aliceNode.info.singleIdentity())).resultFuture.getOrThrow()
}
catch (e: NotaryException) {
val stxId = (e.error as NotaryError.Conflict).txId
assertNull(bobNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(bobNode, stxId)
assertNull(aliceNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(aliceNode, stxId)
}
}
@Test(timeout=300_000)
fun `two phase finality flow double spend transaction to pre-2PF peer`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY - 1)
val ref = aliceNode.startFlowAndRunNetwork(IssueFlow(notary)).resultFuture.getOrThrow()
val stx = aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
val (_, txnStatusAlice) = aliceNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusAlice)
val (_, txnStatusBob) = bobNode.services.validatedTransactions.getTransactionWithStatus(stx.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusBob)
try {
aliceNode.startFlowAndRunNetwork(SpendFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
}
catch (e: NotaryException) {
val stxId = (e.error as NotaryError.Conflict).txId
assertNull(aliceNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(aliceNode, stxId)
assertNull(bobNode.services.validatedTransactions.getTransactionWithStatus(stxId))
assertTxnRemovedFromDatabase(bobNode, stxId)
}
}
@Test(timeout=300_000)
fun `two phase finality flow speedy spender`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val ref = aliceNode.startFlowAndRunNetwork(IssueFlow(notary)).resultFuture.getOrThrow()
val notarisedStxn1 = aliceNode.startFlowAndRunNetwork(SpeedySpendFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
val (_, txnStatusAlice) = aliceNode.services.validatedTransactions.getTransactionWithStatus(notarisedStxn1.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusAlice)
val (_, txnStatusBob) = bobNode.services.validatedTransactions.getTransactionWithStatus(notarisedStxn1.id) ?: fail()
assertEquals(TransactionStatus.IN_FLIGHT, txnStatusBob)
// now lets attempt a new spend with the new output of the previous transaction
val newStateRef = notarisedStxn1.coreTransaction.outRef<DummyContract.SingleOwnerState>(1)
val notarisedStxn2 = aliceNode.startFlowAndRunNetwork(SpeedySpendFlow(newStateRef, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
// the original transaction is now finalised at Bob (despite the original flow not completing) because Bob resolved the
// original transaction from Alice in the second transaction (and Alice had already notarised and finalised the original transaction)
val (_, txnStatusBobAgain) = bobNode.services.validatedTransactions.getTransactionWithStatus(notarisedStxn1.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusBobAgain)
val (_, txnStatusAlice2) = aliceNode.services.validatedTransactions.getTransactionWithStatus(notarisedStxn2.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusAlice2)
val (_, txnStatusBob2) = bobNode.services.validatedTransactions.getTransactionWithStatus(notarisedStxn2.id) ?: fail()
assertEquals(TransactionStatus.IN_FLIGHT, txnStatusBob2)
// Validate attempt at flow finalisation by Bob has no effect on outcome.
val finaliseStxn1 = bobNode.startFlowAndRunNetwork(FinaliseSpeedySpendFlow(notarisedStxn1.id, notarisedStxn1.sigs)).resultFuture.getOrThrow()
val (_, txnStatusBobYetAgain) = bobNode.services.validatedTransactions.getTransactionWithStatus(finaliseStxn1.id) ?: fail()
assertEquals(TransactionStatus.VERIFIED, txnStatusBobYetAgain)
}
@Test(timeout=300_000)
fun `two phase finality flow keeps un-notarised transaction where initiator fails to send notary signature`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val ref = aliceNode.startFlowAndRunNetwork(IssueFlow(notary)).resultFuture.getOrThrow()
try {
aliceNode.startFlowAndRunNetwork(MimicFinalityFailureFlow(ref, bobNode.info.singleIdentity())).resultFuture.getOrThrow()
}
catch (e: UnexpectedFlowEndException) {
val stxId = SecureHash.parse(e.message)
val (_, txnStatusBob) = bobNode.services.validatedTransactions.getTransactionWithStatus(stxId) ?: fail()
assertEquals(TransactionStatus.IN_FLIGHT, txnStatusBob)
}
}
@Test(timeout=300_000)
fun `two phase finality flow issuance transaction with observers`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val stx = aliceNode.startFlowAndRunNetwork(CashIssueWithObserversFlow(
Amount(1000L, GBP), OpaqueBytes.of(1), notary,
observers = setOf(bobNode.info.singleIdentity()))).resultFuture.getOrThrow().stx
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
val sdrs = getSenderRecoveryData(stx.id, aliceNode.database).apply {
assertEquals(1, this.size)
assertEquals(StatesToRecord.ONLY_RELEVANT, this[0].senderStatesToRecord)
assertEquals(StatesToRecord.ALL_VISIBLE, this[0].receiverStatesToRecord)
assertEquals(SecureHash.sha256(BOB_NAME.toString()), this[0].peerPartyId)
}
val rdr = getReceiverRecoveryData(stx.id, bobNode).apply {
assertNotNull(this)
val hashedDL = HashedDistributionList.decrypt(this!!.encryptedDistributionList.bytes, aliceNode.internals.encryptionService)
assertEquals(StatesToRecord.ONLY_RELEVANT, hashedDL.senderStatesToRecord)
assertEquals(SecureHash.sha256(aliceNode.info.singleIdentity().name.toString()), this.peerPartyId)
assertEquals(mapOf<SecureHash, StatesToRecord>(SecureHash.sha256(BOB_NAME.toString()) to StatesToRecord.ALL_VISIBLE), hashedDL.peerHashToStatesToRecord)
}
validateSenderAndReceiverTimestamps(sdrs, rdr!!)
}
@Test(timeout=300_000)
fun `two phase finality flow payment transaction with observers`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
val charlieNode = createNode(CHARLIE_NAME, platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
// issue some cash
aliceNode.startFlow(CashIssueFlow(Amount(1000L, GBP), OpaqueBytes.of(1), notary)).resultFuture.getOrThrow().stx
// standard issuance with observers passed in as FinalityFlow sessions
val stx = aliceNode.startFlowAndRunNetwork(CashPaymentWithObserversFlow(
amount = Amount(100L, GBP),
recipient = bobNode.info.singleIdentity(),
observers = setOf(charlieNode.info.singleIdentity()))).resultFuture.getOrThrow()
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(charlieNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
val sdrs = getSenderRecoveryData(stx.id, aliceNode.database).apply {
assertEquals(2, this.size)
assertEquals(StatesToRecord.ONLY_RELEVANT, this[0].senderStatesToRecord)
assertEquals(SecureHash.sha256(BOB_NAME.toString()), this[0].peerPartyId)
assertEquals(StatesToRecord.ALL_VISIBLE, this[1].receiverStatesToRecord)
assertEquals(SecureHash.sha256(CHARLIE_NAME.toString()), this[1].peerPartyId)
}
val rdr = getReceiverRecoveryData(stx.id, bobNode).apply {
assertNotNull(this)
val hashedDL = HashedDistributionList.decrypt(this!!.encryptedDistributionList.bytes, aliceNode.internals.encryptionService)
assertEquals(StatesToRecord.ONLY_RELEVANT, hashedDL.senderStatesToRecord)
assertEquals(SecureHash.sha256(aliceNode.info.singleIdentity().name.toString()), this.peerPartyId)
// note: Charlie assertion here is using the hinted StatesToRecord value passed to it from Alice
assertEquals(mapOf<SecureHash, StatesToRecord>(
SecureHash.sha256(BOB_NAME.toString()) to StatesToRecord.ONLY_RELEVANT,
SecureHash.sha256(CHARLIE_NAME.toString()) to StatesToRecord.ALL_VISIBLE
), hashedDL.peerHashToStatesToRecord)
}
validateSenderAndReceiverTimestamps(sdrs, rdr!!)
// exercise the new FinalityFlow observerSessions constructor parameter
val stx3 = aliceNode.startFlowAndRunNetwork(CashPaymentWithObserversFlow(
amount = Amount(100L, GBP),
recipient = bobNode.info.singleIdentity(),
observers = setOf(charlieNode.info.singleIdentity()),
useObserverSessions = true)).resultFuture.getOrThrow()
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx3.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx3.id)).isNotNull
assertThat(charlieNode.services.validatedTransactions.getTransaction(stx3.id)).isNotNull
val senderDistributionRecords = getSenderRecoveryData(stx3.id, aliceNode.database).apply {
assertEquals(2, this.size)
assertEquals(this[0].timestamp, this[1].timestamp)
}
getReceiverRecoveryData(stx3.id, bobNode).apply {
assertThat(this).isNotNull
assertEquals(senderDistributionRecords[0].timestamp, this!!.timestamp)
}
getReceiverRecoveryData(stx3.id, charlieNode).apply {
assertThat(this).isNotNull
assertEquals(senderDistributionRecords[0].timestamp, this!!.timestamp)
}
}
private fun validateSenderAndReceiverTimestamps(sdrs: List<SenderDistributionRecord>, rdr: ReceiverDistributionRecord) {
sdrs.map {
assertEquals(it.timestamp, rdr.timestamp)
}
}
@Test(timeout=300_000)
fun `two phase finality flow payment transaction using confidential identities`() {
val bobNode = createBob(platformVersion = PlatformVersionSwitches.TWO_PHASE_FINALITY)
aliceNode.startFlow(CashIssueFlow(Amount(1000L, GBP), OpaqueBytes.of(1), notary)).resultFuture.getOrThrow().stx
val stx = aliceNode.startFlowAndRunNetwork(CashPaymentFlow(
amount = Amount(100L, GBP),
recipient = bobNode.info.singleIdentity(),
anonymous = true)).resultFuture.getOrThrow().stx
assertThat(aliceNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
assertThat(bobNode.services.validatedTransactions.getTransaction(stx.id)).isNotNull
val sdr = getSenderRecoveryData(stx.id, aliceNode.database).apply {
assertEquals(1, this.size)
assertEquals(StatesToRecord.ONLY_RELEVANT, this[0].senderStatesToRecord)
assertEquals(SecureHash.sha256(BOB_NAME.toString()), this[0].peerPartyId)
}
val rdr = getReceiverRecoveryData(stx.id, bobNode).apply {
assertNotNull(this)
val hashedDL = HashedDistributionList.decrypt(this!!.encryptedDistributionList.bytes, aliceNode.internals.encryptionService)
assertEquals(StatesToRecord.ONLY_RELEVANT, hashedDL.senderStatesToRecord)
assertEquals(SecureHash.sha256(aliceNode.info.singleIdentity().name.toString()), this.peerPartyId)
assertEquals(mapOf<SecureHash, StatesToRecord>(SecureHash.sha256(BOB_NAME.toString()) to StatesToRecord.ONLY_RELEVANT), hashedDL.peerHashToStatesToRecord)
}
validateSenderAndReceiverTimestamps(sdr, rdr!!)
}
private fun getSenderRecoveryData(id: SecureHash, database: CordaPersistence): List<SenderDistributionRecord> {
val fromDb = database.transaction {
session.createQuery(
"from ${DBSenderDistributionRecord::class.java.name} where transaction_id = :transactionId",
DBSenderDistributionRecord::class.java
).setParameter("transactionId", id.toString()).resultList
}
return fromDb.map { it.toSenderDistributionRecord() }
}
private fun getReceiverRecoveryData(txId: SecureHash, receiver: TestStartedNode): ReceiverDistributionRecord? {
return receiver.database.transaction {
session.createQuery(
"from ${DBReceiverDistributionRecord::class.java.name} where transaction_id = :transactionId",
DBReceiverDistributionRecord::class.java
).setParameter("transactionId", txId.toString()).resultList
}.singleOrNull()?.toReceiverDistributionRecord()
}
@StartableByRPC
class IssueFlow(val notary: Party) : FlowLogic<StateAndRef<DummyContract.SingleOwnerState>>() {
@Suspendable
override fun call(): StateAndRef<DummyContract.SingleOwnerState> {
val partyAndReference = PartyAndReference(ourIdentity, OpaqueBytes.of(1))
val txBuilder = DummyContract.generateInitial(Random().nextInt(), notary, partyAndReference)
val signedTransaction = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey)
val notarised = subFlow(FinalityFlow(signedTransaction, emptySet<FlowSession>()))
return notarised.coreTransaction.outRef(0)
}
}
@StartableByRPC
@InitiatingFlow
class SpendFlow(private val stateAndRef: StateAndRef<DummyContract.SingleOwnerState>, private val newOwner: Party,
private val handlePropagatedNotaryError: Boolean = false) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val txBuilder = DummyContract.move(stateAndRef, newOwner)
val signedTransaction = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey)
val sessionWithCounterParty = initiateFlow(newOwner)
sessionWithCounterParty.send(handlePropagatedNotaryError)
return subFlow(FinalityFlow(signedTransaction, setOf(sessionWithCounterParty)))
}
}
@Suppress("unused")
@InitiatedBy(SpendFlow::class)
class AcceptSpendFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
val handleNotaryError = otherSide.receive<Boolean>().unwrap { it }
val stx = subFlow(ReceiveFinalityFlow(otherSide, handlePropagatedNotaryError = handleNotaryError))
stx.verify(serviceHub)
}
}
/**
* This flow allows an Initiator to race ahead of a Receiver when using Two Phase Finality.
* The initiator transaction will be finalised, so output states can be used in a follow-up transaction.
* The receiver transaction will not be finalised, causing ledger inconsistency.
*/
@StartableByRPC
@InitiatingFlow
class SpeedySpendFlow(private val stateAndRef: StateAndRef<DummyContract.SingleOwnerState>, private val newOwner: Party) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val newState = StateAndContract(DummyContract.SingleOwnerState(99999, ourIdentity), DummyContract.PROGRAM_ID)
val txBuilder = DummyContract.move(stateAndRef, newOwner).withItems(newState)
val signedTransaction = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey)
val sessionWithCounterParty = initiateFlow(newOwner)
try {
subFlow(FinalityFlow(signedTransaction, setOf(sessionWithCounterParty)))
}
catch (e: FinalisationFailedException) {
// expected (transaction has been notarised by Initiator)
return e.notarisedTxn
}
return signedTransaction
}
}
@Suppress("unused")
@InitiatedBy(SpeedySpendFlow::class)
class AcceptSpeedySpendFlow(private val otherSideSession: FlowSession) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
// Mimic ReceiveFinalityFlow but fail to finalise
try {
val stx = subFlow(ReceiveTransactionFlow(otherSideSession, false, StatesToRecord.ONLY_RELEVANT, true))
require(NotarySigCheck.needsNotarySignature(stx))
logger.info("Peer recording transaction without notary signature.")
(serviceHub as ServiceHubCoreInternal).recordUnnotarisedTransaction(stx)
otherSideSession.send(FetchDataFlow.Request.End) // Finish fetching data (overrideAutoAck)
logger.info("Peer recorded transaction without notary signature.")
val notarySignatures = otherSideSession.receive<List<TransactionSignature>>()
.unwrap { it }
logger.info("Peer received notarised signature.")
(serviceHub as ServiceHubCoreInternal).finalizeTransactionWithExtraSignatures(stx + notarySignatures, notarySignatures, StatesToRecord.ONLY_RELEVANT)
throw FinalisationFailedException(stx + notarySignatures)
}
catch (e: SQLException) {
logger.error("Peer failure upon recording or finalising transaction: $e")
otherSideSession.send(FetchDataFlow.Request.End) // Finish fetching data (overrideAutoAck)
throw UnexpectedFlowEndException("Peer failure upon recording or finalising transaction.", e.cause)
}
catch (uae: TransactionVerificationException.UntrustedAttachmentsException) {
logger.error("Peer failure upon receiving transaction: $uae")
otherSideSession.send(FetchDataFlow.Request.End) // Finish fetching data (overrideAutoAck)
throw uae
}
}
}
class FinaliseSpeedySpendFlow(val id: SecureHash, private val sigs: List<TransactionSignature>) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
// Mimic ReceiveFinalityFlow finalisation
val stx = serviceHub.validatedTransactions.getTransaction(id) ?: throw FlowException("Missing transaction: $id")
(serviceHub as ServiceHubCoreInternal).finalizeTransactionWithExtraSignatures(stx + sigs, sigs, StatesToRecord.ONLY_RELEVANT)
logger.info("Peer finalised transaction with notary signature.")
return stx + sigs
}
}
@InitiatingFlow
class MimicFinalityFailureFlow(private val stateAndRef: StateAndRef<DummyContract.SingleOwnerState>, private val newOwner: Party) : FlowLogic<SignedTransaction>() {
// Mimic FinalityFlow but trigger UnexpectedFlowEndException in ReceiveFinality whilst awaiting receipt of notary signature
@Suspendable
override fun call(): SignedTransaction {
val txBuilder = DummyContract.move(stateAndRef, newOwner)
val stxn = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey)
val sessionWithCounterParty = initiateFlow(newOwner)
subFlow(object : SendTransactionFlow(stxn, setOf(sessionWithCounterParty), emptySet(), StatesToRecord.ONLY_RELEVANT, true) {
override fun isFinality(): Boolean = true
})
throw UnexpectedFlowEndException("${stxn.id}")
}
}
@Suppress("unused")
@InitiatedBy(MimicFinalityFailureFlow::class)
class TriggerReceiveFinalityFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
subFlow(ReceiveFinalityFlow(otherSide))
}
}
class FinalisationFailedException(val notarisedTxn: SignedTransaction) : FlowException("Failed to finalise transaction with notary signature.")
private fun createBob(cordapps: List<TestCordappInternal> = emptyList(), platformVersion: Int = PLATFORM_VERSION): TestStartedNode {
return mockNet.createNode(InternalMockNodeParameters(legalName = BOB_NAME, additionalCordapps = cordapps,
version = MOCK_VERSION_INFO.copy(platformVersion = platformVersion)))
}
private fun createNode(legalName: CordaX500Name, cordapps: List<TestCordappInternal> = emptyList(), platformVersion: Int = PLATFORM_VERSION): TestStartedNode {
return mockNet.createNode(InternalMockNodeParameters(legalName = legalName, additionalCordapps = cordapps,
version = MOCK_VERSION_INFO.copy(platformVersion = platformVersion)))
}
private fun TestStartedNode.issuesCashTo(recipient: TestStartedNode): SignedTransaction {

View File

@ -15,7 +15,7 @@ class TestNoSecurityDataVendingFlow(otherSideSession: FlowSession) : DataVending
// Hack to not send the first message.
otherSideSession.receive()
} else {
super.sendPayloadAndReceiveDataRequest(this.otherSideSession, payload)
super.sendPayloadAndReceiveDataRequest(this.otherSessions.first(), payload)
}
}
}

View File

@ -4,7 +4,13 @@ import co.paralleluniverse.fibers.Suspendable
import com.natpryce.hamkrest.MatchResult
import com.natpryce.hamkrest.Matcher
import com.natpryce.hamkrest.equalTo
import net.corda.core.flows.*
import net.corda.core.flows.FinalityFlow
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.ReceiveFinalityFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.core.internal.FlowStateMachineHandle
import net.corda.core.messaging.CordaRPCOps
@ -58,4 +64,13 @@ interface WithFinality : WithMockNet {
subFlow(ReceiveFinalityFlow(otherSide))
}
}
@StartableByRPC
class OldFinalityInvoker(private val transaction: SignedTransaction) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
@Suppress("DEPRECATION")
return subFlow(FinalityFlow(transaction))
}
}
}

View File

@ -99,12 +99,17 @@ class ResolveTransactionsFlowTest {
// DOCEND 1
@Test(timeout=300_000)
fun `dependency with an error`() {
val stx = makeTransactions(signFirstTX = false).second
val p = TestFlow(setOf(stx.id), megaCorp)
val future = miniCorpNode.startFlow(p)
mockNet.runNetwork()
assertFailsWith(SignedTransaction.SignaturesMissingException::class) { future.getOrThrow() }
fun `dependency with an error fails fast upon prior attempt to record transaction with missing signature`() {
val exception = assertFailsWith(IllegalStateException::class) {
val stx = makeTransactions(signFirstTX = false).second
// fails fast in above operation
// prior to platform version 13, same failure would occur upon transaction resolution
val p = TestFlow(setOf(stx.id), megaCorp)
val future = miniCorpNode.startFlow(p)
mockNet.runNetwork()
future.getOrThrow()
}
assertTrue(exception.cause.toString().contains("SignaturesMissingException"))
}
@Test(timeout=300_000)

View File

@ -30,6 +30,8 @@ import java.time.Duration
import java.time.Instant
import kotlin.test.assertEquals
import kotlin.test.assertFails
import kotlin.test.assertNotEquals
import kotlin.test.assertNull
class NetworkParametersTest {
private val mockNet = InternalMockNetwork(
@ -93,6 +95,32 @@ class NetworkParametersTest {
assertEquals(twoDays, nm2.eventHorizon)
}
@Test(timeout=300_000)
fun `that transactionRecoveryPeriod and confidentialIdentityPreGenerationPeriod aren't required`() {
// this is defensive tests in response to CORDA-2769
val aliceNotaryParty = TestIdentity(ALICE_NAME).party
val aliceNotaryInfo = NotaryInfo(aliceNotaryParty, false)
val nm1 = NetworkParameters(
minimumPlatformVersion = 1,
notaries = listOf(aliceNotaryInfo),
maxMessageSize = Int.MAX_VALUE,
maxTransactionSize = Int.MAX_VALUE,
modifiedTime = Instant.now(),
epoch = 1,
whitelistedContractImplementations = mapOf("MyClass" to listOf(AttachmentId.allOnesHash)),
eventHorizon = Duration.ofDays(1)
)
assertNull(nm1.recoveryMaximumBackupInterval)
assertNull(nm1.confidentialIdentityMinimumBackupInterval)
val nm2 = nm1.copy(recoveryMaximumBackupInterval = 10.days, confidentialIdentityMinimumBackupInterval = 10.days)
assertNotEquals(nm1.recoveryMaximumBackupInterval, nm2.recoveryMaximumBackupInterval)
assertNotEquals(nm1.confidentialIdentityMinimumBackupInterval, nm2.confidentialIdentityMinimumBackupInterval)
}
// Notaries tests
@Test(timeout=300_000)
fun `choosing notary not specified in network parameters will fail`() {

View File

@ -80,7 +80,7 @@ class LedgerTransactionQueryTests {
.addOutputState(dummyState, DummyContract.PROGRAM_ID)
.addCommand(dummyCommand())
)
services.recordTransactions(fakeIssueTx)
services.recordTransactions(fakeIssueTx, disableSignatureVerification = true)
val dummyStateRef = StateRef(fakeIssueTx.id, 0)
return StateAndRef(TransactionState(dummyState, DummyContract.PROGRAM_ID, DUMMY_NOTARY, constraint = AlwaysAcceptAttachmentConstraint), dummyStateRef)
}

View File

@ -9,7 +9,6 @@ apply plugin: 'com.jfrog.artifactory'
description 'Corda core'
// required by DJVM and Avian JVM (for running inside the SGX enclave) which only supports Java 8.
targetCompatibility = VERSION_1_8
sourceSets {

View File

@ -1,7 +1,5 @@
package net.corda.core.crypto;
import net.corda.core.KeepForDJVM;
import java.math.BigInteger;
import java.util.Arrays;
@ -29,7 +27,6 @@ import java.util.Arrays;
* NB: This class originally comes from the Apache licensed bitcoinj library. The original author of this code is the
* same as the original author of the R3 repository.
*/
@KeepForDJVM
public class Base58 {
private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
private static final char ENCODED_ZERO = ALPHABET[0];

View File

@ -1,14 +1,11 @@
package net.corda.core.flows;
import net.corda.core.KeepForDJVM;
import javax.annotation.Nullable;
/**
* An exception that may be identified with an ID. If an exception originates in a counter-flow this ID will be
* propagated. This allows correlation of error conditions across different flows.
*/
@KeepForDJVM
public interface IdentifiableException {
/**
* @return the ID of the error, or null if the error doesn't have it set (yet).

View File

@ -6,6 +6,5 @@ import net.corda.core.serialization.CordaSerializable
* Allows an implementing [Throwable] to be propagated to clients.
*/
@CordaSerializable
@KeepForDJVM
@Deprecated("This is no longer used as the exception obfuscation feature is no longer available.")
interface ClientRelevantError

View File

@ -4,7 +4,6 @@ import net.corda.core.serialization.CordaSerializable
import java.util.*
@CordaSerializable
@KeepForDJVM
interface CordaThrowable {
var originalExceptionClassName: String?
val originalMessage: String?
@ -13,7 +12,6 @@ interface CordaThrowable {
fun addSuppressed(suppressed: Array<Throwable>)
}
@KeepForDJVM
open class CordaException internal constructor(override var originalExceptionClassName: String? = null,
private var _message: String? = null,
private var _cause: Throwable? = null) : Exception(null, null, true, true), CordaThrowable {
@ -61,7 +59,6 @@ open class CordaException internal constructor(override var originalExceptionCla
}
}
@KeepForDJVM
open class CordaRuntimeException(override var originalExceptionClassName: String?,
private var _message: String?,
private var _cause: Throwable?) : RuntimeException(null, null, true, true), CordaThrowable {

View File

@ -6,7 +6,6 @@ import net.corda.core.crypto.internal.AliasPrivateKey
* OIDs used for the Corda platform. All entries MUST be defined in this file only and they MUST NOT be removed.
* If an OID is incorrectly assigned, it should be marked deprecated and NEVER be reused again.
*/
@KeepForDJVM
object CordaOID {
/** Assigned to R3, see http://www.oid-info.com/cgi-bin/display?oid=1.3.6.1.4.1.50530&action=display */
const val R3_ROOT = "1.3.6.1.4.1.50530"

View File

@ -1,24 +0,0 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
/**
* Declare the annotated element to unsuitable for the deterministic version of Corda.
*/
// DOCSTART 01
@Target(
FILE,
CLASS,
CONSTRUCTOR,
FUNCTION,
PROPERTY_GETTER,
PROPERTY_SETTER,
PROPERTY,
FIELD,
TYPEALIAS
)
@Retention(BINARY)
@CordaInternal
annotation class DeleteForDJVM
// DOCEND 01

View File

@ -1,18 +0,0 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FILE
/**
* This annotates a class or file that we want to include into the deterministic version of Corda Core.
* We don't expect everything within that class/file to be deterministic; those non-deterministic
* elements need to be annotated with either [DeleteForDJVM] or [StubOutForDJVM] so that they
* can be deleted.
*/
// DOCSTART 01
@Target(FILE, CLASS)
@Retention(BINARY)
@CordaInternal
annotation class KeepForDJVM
// DOCEND 01

View File

@ -1,22 +0,0 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
/**
* We expect that almost every non-deterministic element can have its bytecode
* deleted entirely from the deterministic version of Corda. This annotation is
* for those (hopefully!) few occasions where the non-deterministic function
* cannot be deleted. In these cases, the function will be stubbed out instead.
*/
// DOCSTART 01
@Target(
CONSTRUCTOR,
FUNCTION,
PROPERTY_GETTER,
PROPERTY_SETTER
)
@Retention(BINARY)
@CordaInternal
annotation class StubOutForDJVM
// DOCEND 01

View File

@ -1,7 +1,5 @@
package net.corda.core.context
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.contracts.ScheduledStateRef
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.telemetry.SerializedTelemetry
@ -52,7 +50,6 @@ data class InvocationContext(
/**
* Creates an [InvocationContext] with a [Trace] that defaults to a [java.util.UUID] as value and [java.time.Instant.now] timestamp.
*/
@DeleteForDJVM
@JvmStatic
@JvmOverloads
@Suppress("LongParameterList")
@ -70,7 +67,6 @@ data class InvocationContext(
/**
* Creates an [InvocationContext] with [InvocationOrigin.RPC] origin.
*/
@DeleteForDJVM
@JvmStatic
@JvmOverloads
@Suppress("LongParameterList")
@ -86,28 +82,24 @@ data class InvocationContext(
/**
* Creates an [InvocationContext] with [InvocationOrigin.Peer] origin.
*/
@DeleteForDJVM
@JvmStatic
fun peer(party: CordaX500Name, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null, impersonatedActor: Actor? = null): InvocationContext = newInstance(InvocationOrigin.Peer(party), trace, null, externalTrace, impersonatedActor)
/**
* Creates an [InvocationContext] with [InvocationOrigin.Service] origin.
*/
@DeleteForDJVM
@JvmStatic
fun service(serviceClassName: String, owningLegalIdentity: CordaX500Name, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = newInstance(InvocationOrigin.Service(serviceClassName, owningLegalIdentity), trace, null, externalTrace)
/**
* Creates an [InvocationContext] with [InvocationOrigin.Scheduled] origin.
*/
@DeleteForDJVM
@JvmStatic
fun scheduled(scheduledState: ScheduledStateRef, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = newInstance(InvocationOrigin.Scheduled(scheduledState), trace, null, externalTrace)
/**
* Creates an [InvocationContext] with [InvocationOrigin.Shell] origin.
*/
@DeleteForDJVM
@JvmStatic
fun shell(trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = InvocationContext(InvocationOrigin.Shell, trace, null, externalTrace)
}
@ -161,7 +153,6 @@ data class InvocationContext(
/**
* Models an initiator in Corda, can be a user, a service, etc.
*/
@KeepForDJVM
@CordaSerializable
data class Actor(val id: Id, val serviceId: AuthServiceId, val owningLegalIdentity: CordaX500Name) {
@ -173,7 +164,6 @@ data class Actor(val id: Id, val serviceId: AuthServiceId, val owningLegalIdenti
/**
* Actor id.
*/
@KeepForDJVM
@CordaSerializable
data class Id(val value: String)
}
@ -181,7 +171,6 @@ data class Actor(val id: Id, val serviceId: AuthServiceId, val owningLegalIdenti
/**
* Represents the source of an action such as a flow start, an RPC, a shell command etc.
*/
@DeleteForDJVM
@CordaSerializable
sealed class InvocationOrigin {
/**
@ -230,6 +219,5 @@ sealed class InvocationOrigin {
/**
* Authentication / Authorisation Service ID.
*/
@KeepForDJVM
@CordaSerializable
data class AuthServiceId(val value: String)

View File

@ -1,6 +1,5 @@
package net.corda.core.context
import net.corda.core.DeleteForDJVM
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.Id
import net.corda.core.utilities.UuidGenerator
@ -17,7 +16,6 @@ data class Trace(val invocationId: InvocationId, val sessionId: SessionId) {
/**
* Creates a trace using a [InvocationId.newInstance] with default arguments and a [SessionId] matching the value and timestamp from the invocation id..
*/
@DeleteForDJVM
@JvmStatic
fun newInstance(invocationId: InvocationId = InvocationId.newInstance(), sessionId: SessionId = SessionId(invocationId.value, invocationId.timestamp)) = Trace(invocationId, sessionId)
}
@ -34,7 +32,6 @@ data class Trace(val invocationId: InvocationId, val sessionId: SessionId) {
/**
* Creates an invocation id using a [java.util.UUID] as value and [Instant.now] as timestamp.
*/
@DeleteForDJVM
@JvmStatic
fun newInstance(value: String = UuidGenerator.next().toString(), timestamp: Instant = Instant.now()) = InvocationId(value, timestamp)
}
@ -52,7 +49,6 @@ data class Trace(val invocationId: InvocationId, val sessionId: SessionId) {
/**
* Creates a session id using a [java.util.UUID] as value and [Instant.now] as timestamp.
*/
@DeleteForDJVM
@JvmStatic
fun newInstance(value: String = UuidGenerator.next().toString(), timestamp: Instant = Instant.now()) = SessionId(value, timestamp)
}

View File

@ -1,6 +1,5 @@
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.crypto.CompositeKey
import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable
@ -37,7 +36,6 @@ interface TokenizableAssetInfo {
* @property token the type of token this is an amount of. This is usually a singleton.
* @param T the type of the token, for example [Currency]. T should implement [TokenizableAssetInfo] if automatic conversion to/from a display format is required.
*/
@KeepForDJVM
@CordaSerializable
data class Amount<T : Any>(val quantity: Long, val displayTokenSize: BigDecimal, val token: T) : Comparable<Amount<T>> {
// TODO Proper lookup of currencies in a locale and context sensitive fashion is not supported and is left to the application.

View File

@ -1,7 +1,6 @@
package net.corda.core.contracts
import net.corda.core.DoNotImplement
import net.corda.core.KeepForDJVM
import net.corda.core.identity.Party
import net.corda.core.internal.extractFile
import net.corda.core.serialization.CordaSerializable
@ -31,7 +30,6 @@ import java.util.jar.JarInputStream
* Finally, using ZIPs ensures files have a timestamp associated with them, and enables informational attachments
* to be password protected (although in current releases password protected ZIPs are likely to fail to work).
*/
@KeepForDJVM
@CordaSerializable
@DoNotImplement
interface Attachment : NamedByHash {

View File

@ -2,7 +2,6 @@ package net.corda.core.contracts
import net.corda.core.CordaInternal
import net.corda.core.DoNotImplement
import net.corda.core.KeepForDJVM
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint.isSatisfiedBy
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.isFulfilledBy
@ -38,7 +37,6 @@ interface AttachmentConstraint {
}
/** An [AttachmentConstraint] where [isSatisfiedBy] always returns true. */
@KeepForDJVM
object AlwaysAcceptAttachmentConstraint : AttachmentConstraint {
override fun isSatisfiedBy(attachment: Attachment) = true
}
@ -48,7 +46,6 @@ object AlwaysAcceptAttachmentConstraint : AttachmentConstraint {
* The state protected by this constraint can only be used in a transaction created with that version of the jar.
* And a receiving node will only accept it if a cordapp with that hash has (is) been deployed on the node.
*/
@KeepForDJVM
data class HashAttachmentConstraint(val attachmentId: SecureHash) : AttachmentConstraint {
companion object {
val disableHashConstraints = System.getProperty("net.corda.node.disableHashConstraints")?.toBoolean() ?: false
@ -69,7 +66,6 @@ data class HashAttachmentConstraint(val attachmentId: SecureHash) : AttachmentCo
* See: [net.corda.core.node.NetworkParameters.whitelistedContractImplementations]
* It allows for centralized control over the cordapps that can be used.
*/
@KeepForDJVM
object WhitelistedByZoneAttachmentConstraint : AttachmentConstraint {
override fun isSatisfiedBy(attachment: Attachment): Boolean {
return if (attachment is AttachmentWithContext) {
@ -83,7 +79,6 @@ object WhitelistedByZoneAttachmentConstraint : AttachmentConstraint {
}
}
@KeepForDJVM
@Deprecated(
"The name is no longer valid as multiple constraints were added.",
replaceWith = ReplaceWith("AutomaticPlaceholderConstraint"),
@ -102,7 +97,6 @@ object AutomaticHashConstraint : AttachmentConstraint {
* The resolution occurs in [TransactionBuilder.toWireTransaction] and is based on the input states and the attachments.
* If the [Contract] was not annotated with [NoConstraintPropagation], then the platform will ensure the correct constraint propagation.
*/
@KeepForDJVM
object AutomaticPlaceholderConstraint : AttachmentConstraint {
override fun isSatisfiedBy(attachment: Attachment): Boolean {
throw UnsupportedOperationException("Contracts cannot be satisfied by an AutomaticPlaceholderConstraint placeholder.")
@ -115,7 +109,6 @@ object AutomaticPlaceholderConstraint : AttachmentConstraint {
*
* @property key A [PublicKey] that must be fulfilled by the owning keys of the attachment's signing parties.
*/
@KeepForDJVM
data class SignatureAttachmentConstraint(val key: PublicKey) : AttachmentConstraint {
override fun isSatisfiedBy(attachment: Attachment): Boolean {
log.debug("Checking signature constraints: verifying $key in contract attachment signer keys: ${attachment.signerKeys}")

View File

@ -1,7 +1,6 @@
package net.corda.core.contracts
import net.corda.core.CordaInternal
import net.corda.core.KeepForDJVM
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
import java.security.PublicKey
@ -12,7 +11,6 @@ import java.security.PublicKey
* @property contract The contract name contained within the JAR. A Contract attachment has to contain at least 1 contract.
* @property additionalContracts Additional contract names contained within the JAR.
*/
@KeepForDJVM
class ContractAttachment private constructor(
val attachment: Attachment,
val contract: ContractClassName,

View File

@ -1,6 +1,5 @@
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.identity.AbstractParty
import net.corda.core.serialization.CordaSerializable
@ -12,7 +11,6 @@ import net.corda.core.serialization.CordaSerializable
* notary is responsible for ensuring there is no "double spending" by only signing a transaction if the input states
* are all free.
*/
@KeepForDJVM
@CordaSerializable
interface ContractState {
/**

View File

@ -1,8 +1,6 @@
@file:JvmName("ContractsDSL")
@file:KeepForDJVM
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import net.corda.core.internal.uncheckedCast
@ -18,7 +16,6 @@ import java.util.*
//// Requirements /////////////////////////////////////////////////////////////////////////////////////////////////////
@KeepForDJVM
object Requirements {
/** Throws [IllegalArgumentException] if the given expression evaluates to false. */
@Suppress("NOTHING_TO_INLINE") // Inlining this takes it out of our committed ABI.

View File

@ -1,6 +1,5 @@
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.flows.FlowException
import net.corda.core.identity.AbstractParty
import net.corda.core.serialization.SerializableCalculatedProperty
@ -27,7 +26,6 @@ class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException
* @param T a type that represents the asset in question. This should describe the basic type of the asset
* (GBP, USD, oil, shares in company <X>, etc.) and any additional metadata (issuer, grade, class, etc.).
*/
@KeepForDJVM
interface FungibleAsset<T : Any> : FungibleState<Issued<T>>, OwnableState {
/**
* Amount represents a positive quantity of some issued product which can be cash, tokens, assets, or generally

View File

@ -1,7 +1,5 @@
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
/**
* Interface to represent things which are fungible, this means that there is an expectation that these things can
* be split and merged. That's the only assumption made by this interface.
@ -25,7 +23,6 @@ import net.corda.core.KeepForDJVM
* [TokenizableAssetInfo].
*/
// DOCSTART 1
@KeepForDJVM
interface FungibleState<T : Any> : ContractState {
/**
* Amount represents a positive quantity of some token which can be cash, tokens, stock, agreements, or generally

View File

@ -1,8 +1,6 @@
package net.corda.core.contracts
import net.corda.core.DeleteForDJVM
import net.corda.core.DoNotImplement
import net.corda.core.KeepForDJVM
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.Vault
import net.corda.core.node.services.queryBy
@ -18,7 +16,6 @@ import net.corda.core.transactions.LedgerTransaction
* [StaticPointer]s are for use with any type of [ContractState].
*/
@CordaSerializable
@KeepForDJVM
@DoNotImplement
sealed class StatePointer<T : ContractState> {
@ -70,7 +67,6 @@ sealed class StatePointer<T : ContractState> {
*
* @param services a [ServiceHub] implementation is required to resolve the pointer.
*/
@DeleteForDJVM
abstract fun resolve(services: ServiceHub): StateAndRef<T>
/**
@ -89,7 +85,6 @@ sealed class StatePointer<T : ContractState> {
* - The [ContractState] may not be known by the node performing the look-up in which case the [resolve] method will
* throw a [TransactionResolutionException]
*/
@KeepForDJVM
class StaticPointer<T : ContractState>(
override val pointer: StateRef,
override val type: Class<T>,
@ -110,7 +105,6 @@ class StaticPointer<T : ContractState>(
*/
@Throws(TransactionResolutionException::class)
@Suppress("UNCHECKED_CAST")
@DeleteForDJVM
override fun resolve(services: ServiceHub): StateAndRef<T> {
val transactionState = services.loadState(pointer) as TransactionState<T>
val castState: T = type.cast(transactionState.data)
@ -148,7 +142,6 @@ class StaticPointer<T : ContractState>(
* then the transaction with such a reference state cannot be committed to the ledger until the most up-to-date version
* of the [LinearState] is available. See reference states documentation on docs.corda.net for more info.
*/
@KeepForDJVM
class LinearPointer<T : LinearState>(
override val pointer: UniqueIdentifier,
override val type: Class<T>,
@ -171,7 +164,6 @@ class LinearPointer<T : LinearState>(
* @param services a [ServiceHub] implementation is required to perform a vault query.
*/
@Suppress("UNCHECKED_CAST")
@DeleteForDJVM
override fun resolve(services: ServiceHub): StateAndRef<T> {
// Return the latest version of the linear state.
// This query will only ever return one or zero states.

View File

@ -1,9 +1,6 @@
@file:JvmName("Structures")
@file:KeepForDJVM
package net.corda.core.contracts
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.secureRandomBytes
import net.corda.core.crypto.toStringShort
@ -45,7 +42,6 @@ interface NamedByHash {
* of product may differentiate different kinds of asset within the same logical class e.g the currency, or
* it may just be a type marker for a single custom asset.
*/
@KeepForDJVM
@CordaSerializable
data class Issued<out P : Any>(val issuer: PartyAndReference, val product: P) {
init {
@ -72,13 +68,11 @@ fun <T : Any> Amount<Issued<T>>.withoutIssuer(): Amount<T> = Amount(quantity, di
/**
* Return structure for [OwnableState.withNewOwner]
*/
@KeepForDJVM
data class CommandAndState(val command: CommandData, val ownableState: OwnableState)
/**
* A contract state that can have a single owner.
*/
@KeepForDJVM
interface OwnableState : ContractState {
/** There must be a MoveCommand signed by this key to claim the amount. */
val owner: AbstractParty
@ -89,7 +83,6 @@ interface OwnableState : ContractState {
// DOCEND 3
/** Something which is scheduled to happen at a point in time. */
@KeepForDJVM
interface Scheduled {
val scheduledAt: Instant
}
@ -102,7 +95,6 @@ interface Scheduled {
* lifecycle processing needs to take place. e.g. a fixing or a late payment etc.
*/
@CordaSerializable
@KeepForDJVM
data class ScheduledStateRef(val ref: StateRef, override val scheduledAt: Instant) : Scheduled
/**
@ -117,7 +109,6 @@ data class ScheduledStateRef(val ref: StateRef, override val scheduledAt: Instan
* for a particular [ContractState] have been processed/fired etc. If the activity is not "on ledger" then the
* scheduled activity shouldn't be either.
*/
@KeepForDJVM
data class ScheduledActivity(val logicRef: FlowLogicRef, override val scheduledAt: Instant) : Scheduled
// DOCSTART 2
@ -126,7 +117,6 @@ data class ScheduledActivity(val logicRef: FlowLogicRef, override val scheduledA
*
* This simplifies the job of tracking the current version of certain types of state in e.g. a vault.
*/
@KeepForDJVM
interface LinearState : ContractState {
/**
* Unique id shared by all LinearState states throughout history within the vaults of all parties.
@ -136,7 +126,6 @@ interface LinearState : ContractState {
val linearId: UniqueIdentifier
}
// DOCEND 2
@KeepForDJVM
interface SchedulableState : ContractState {
/**
* Indicate whether there is some activity to be performed at some future point in time with respect to this
@ -160,7 +149,6 @@ fun ContractState.hash(algorithm: String): SecureHash = SecureHash.hashAs(algori
* A stateref is a pointer (reference) to a state, this is an equivalent of an "outpoint" in Bitcoin. It records which
* transaction defined the state and where in that transaction it was.
*/
@KeepForDJVM
@CordaSerializable
// DOCSTART 8
data class StateRef(val txhash: SecureHash, val index: Int) {
@ -169,7 +157,6 @@ data class StateRef(val txhash: SecureHash, val index: Int) {
// DOCEND 8
/** A StateAndRef is simply a (state, ref) pair. For instance, a vault (which holds available assets) contains these. */
@KeepForDJVM
@CordaSerializable
// DOCSTART 7
data class StateAndRef<out T : ContractState>(val state: TransactionState<T>, val ref: StateRef) {
@ -179,7 +166,6 @@ data class StateAndRef<out T : ContractState>(val state: TransactionState<T>, va
// DOCEND 7
/** A wrapper for a [StateAndRef] indicating that it should be added to a transaction as a reference input state. */
@KeepForDJVM
data class ReferencedStateAndRef<out T : ContractState>(val stateAndRef: StateAndRef<T>)
/** Filters a list of [StateAndRef] objects according to the type of the states */
@ -191,7 +177,6 @@ inline fun <reified T : ContractState> Iterable<StateAndRef<ContractState>>.filt
* Reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal
* ledger. The reference is intended to be encrypted so it's meaningless to anyone other than the party.
*/
@KeepForDJVM
@CordaSerializable
data class PartyAndReference(val party: AbstractParty, val reference: OpaqueBytes) {
override fun toString() = "$party$reference"
@ -202,14 +187,12 @@ data class PartyAndReference(val party: AbstractParty, val reference: OpaqueByte
interface CommandData
/** Commands that inherit from this are intended to have no data items: it's only their presence that matters. */
@KeepForDJVM
abstract class TypeOnlyCommandData : CommandData {
override fun equals(other: Any?) = other?.javaClass == javaClass
override fun hashCode() = javaClass.name.hashCode()
}
/** Command data/content plus pubkey pair: the signature is stored at the end of the serialized bytes */
@KeepForDJVM
@CordaSerializable
data class Command<T : CommandData>(val value: T, val signers: List<PublicKey>) {
// TODO Introduce NonEmptyList?
@ -224,7 +207,6 @@ data class Command<T : CommandData>(val value: T, val signers: List<PublicKey>)
}
/** A common move command for contract states which can change owner. */
@KeepForDJVM
interface MoveCommand : CommandData {
/**
* Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in
@ -236,7 +218,6 @@ interface MoveCommand : CommandData {
// DOCSTART 6
/** A [Command] where the signing parties have been looked up if they have a well known/recognised institutional key. */
@KeepForDJVM
@CordaSerializable
data class CommandWithParties<out T : CommandData>(
val signers: List<PublicKey>,
@ -256,7 +237,6 @@ data class CommandWithParties<out T : CommandData>(
*
* TODO: Contract serialization is likely to change, so the annotation is likely temporary.
*/
@KeepForDJVM
@CordaSerializable
interface Contract {
/**
@ -288,7 +268,6 @@ annotation class LegalProseReference(val uri: String)
* more than one state).
* @param NewState the upgraded contract state.
*/
@KeepForDJVM
interface UpgradedContract<in OldState : ContractState, out NewState : ContractState> : Contract {
/**
* Name of the contract this is an upgraded version of, used as part of verification of upgrade transactions.
@ -307,7 +286,6 @@ interface UpgradedContract<in OldState : ContractState, out NewState : ContractS
* This interface allows specifying a custom legacy contract constraint for upgraded contracts. The default for [UpgradedContract]
* is [WhitelistedByZoneAttachmentConstraint].
*/
@KeepForDJVM
interface UpgradedContractWithLegacyConstraint<in OldState : ContractState, out NewState : ContractState> : UpgradedContract<OldState, NewState> {
/**
* A validator for the legacy (pre-upgrade) contract attachments on the transaction.
@ -325,14 +303,11 @@ interface UpgradedContractWithLegacyConstraint<in OldState : ContractState, out
* but it is highlighted that one should always ensure it has sufficient entropy.
*/
@CordaSerializable
@KeepForDJVM
class PrivacySalt(bytes: ByteArray) : OpaqueBytes(bytes) {
/** Constructs a salt with a randomly-generated saltLength byte value. */
@DeleteForDJVM
constructor(saltLength: Int) : this(secureRandomBytes(saltLength))
/** Constructs a salt with a randomly-generated 32 byte value. */
@DeleteForDJVM
constructor() : this(MINIMUM_SIZE)
init {
@ -343,7 +318,6 @@ class PrivacySalt(bytes: ByteArray) : OpaqueBytes(bytes) {
companion object {
private const val MINIMUM_SIZE = 32
@DeleteForDJVM
@JvmStatic
fun createFor(algorithm: String): PrivacySalt {
return PrivacySalt(SecureHash.digestLengthFor(algorithm))
@ -357,5 +331,4 @@ class PrivacySalt(bytes: ByteArray) : OpaqueBytes(bytes) {
* @property state A state
* @property contract The contract that should verify the state
*/
@KeepForDJVM
data class StateAndContract(val state: ContractState, val contract: ContractClassName)

View File

@ -1,6 +1,5 @@
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.internal.div
import net.corda.core.internal.until
import net.corda.core.serialization.CordaSerializable
@ -79,7 +78,6 @@ abstract class TimeWindow {
/** Returns true iff the given [instant] is within the time interval of this [TimeWindow]. */
abstract operator fun contains(instant: Instant): Boolean
@KeepForDJVM
private data class From(override val fromTime: Instant) : TimeWindow() {
override val untilTime: Instant? get() = null
override val midpoint: Instant? get() = null
@ -87,7 +85,6 @@ abstract class TimeWindow {
override fun toString(): String = "[$fromTime, ∞)"
}
@KeepForDJVM
private data class Until(override val untilTime: Instant) : TimeWindow() {
override val fromTime: Instant? get() = null
override val midpoint: Instant? get() = null
@ -95,7 +92,6 @@ abstract class TimeWindow {
override fun toString(): String = "(∞, $untilTime)"
}
@KeepForDJVM
private data class Between(override val fromTime: Instant, override val untilTime: Instant) : TimeWindow() {
init {
require(fromTime < untilTime) { "fromTime must be earlier than untilTime" }

View File

@ -1,7 +1,5 @@
@file:KeepForDJVM
package net.corda.core.contracts
import net.corda.core.KeepForDJVM
import net.corda.core.identity.Party
import net.corda.core.internal.requiredContractClassName
import net.corda.core.serialization.CordaSerializable

View File

@ -1,8 +1,6 @@
package net.corda.core.contracts
import net.corda.core.CordaException
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException
import net.corda.core.identity.Party
@ -18,7 +16,6 @@ import java.security.PublicKey
*
* @property hash Merkle root of the transaction being resolved, see [net.corda.core.transactions.WireTransaction.id]
*/
@KeepForDJVM
open class TransactionResolutionException @JvmOverloads constructor(val hash: SecureHash, message: String = "Transaction resolution failure for $hash") : FlowException(message) {
/**
* Thrown if a transaction specifies a set of parameters that aren't stored locally yet verification is requested.
@ -35,7 +32,6 @@ open class TransactionResolutionException @JvmOverloads constructor(val hash: Se
*
* @property hash Hash of the bytes of the attachment, see [Attachment.id]
*/
@KeepForDJVM
class AttachmentResolutionException(val hash: AttachmentId) : FlowException("Attachment resolution failure for $hash")
/**
@ -43,7 +39,6 @@ class AttachmentResolutionException(val hash: AttachmentId) : FlowException("Att
* for this error is provided via the [message] and [cause].
* @property attachmentId
*/
@KeepForDJVM
class BrokenAttachmentException(val attachmentId: AttachmentId, message: String?, cause: Throwable?)
: FlowException("Attachment $attachmentId has error (${message ?: "no message"})", cause)
@ -64,7 +59,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
*
* @property contractClass The fully qualified class name of the failing contract.
*/
@KeepForDJVM
class ContractRejection internal constructor(txId: SecureHash, val contractClass: String, cause: Throwable?, message: String) : TransactionVerificationException(txId, "Contract verification failed: $message, contract: $contractClass", cause) {
internal constructor(txId: SecureHash, contract: Contract, cause: Throwable) : this(txId, contract.javaClass.name, cause, cause.message ?: "")
}
@ -78,7 +72,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* @property inputConstraint The constraint of the input state.
* @property outputConstraint The constraint of the outputs state.
*/
@KeepForDJVM
class ConstraintPropagationRejection(txId: SecureHash, message: String) : TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash,
contractClass: String,
@ -97,7 +90,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
*
* @property contractClass The fully qualified class name of the failing contract.
*/
@KeepForDJVM
class ContractConstraintRejection(txId: SecureHash, val contractClass: String)
: TransactionVerificationException(txId, "Contract constraints failed for $contractClass", null)
@ -107,7 +99,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* @property contractClass The fully qualified class name of the failing contract.
* @property reason a message containing the reason the constraint is invalid included in thrown the exception.
*/
@KeepForDJVM
class InvalidConstraintRejection(txId: SecureHash, val contractClass: String, val reason: String)
: TransactionVerificationException(txId, "Contract constraints failed for $contractClass. $reason", null)
@ -117,7 +108,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
*
* @property contractClass The fully qualified class name of the failing contract.
*/
@KeepForDJVM
class MissingAttachmentRejection(txId: SecureHash, val contractClass: String)
: TransactionVerificationException(txId, "Contract constraints failed, could not find attachment for: $contractClass", null)
@ -130,14 +120,12 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
*
* @property contractClass The fully qualified class name of the failing contract.
*/
@KeepForDJVM
class ConflictingAttachmentsRejection(txId: SecureHash, val contractClass: String)
: TransactionVerificationException(txId, "Contract constraints failed for: $contractClass, because multiple attachments providing this contract were attached.", null)
/**
* Indicates that the same attachment has been added multiple times to a transaction.
*/
@KeepForDJVM
class DuplicateAttachmentsRejection(txId: SecureHash, val attachmentId: Attachment)
: TransactionVerificationException(txId, "The attachment: $attachmentId was added multiple times.", null)
@ -147,7 +135,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
*
* @property contractClass The fully qualified class name of the failing contract.
*/
@KeepForDJVM
class ContractCreationError internal constructor(txId: SecureHash, val contractClass: String, cause: Throwable?, message: String)
: TransactionVerificationException(txId, "Contract verification failed: $message, could not create contract class: $contractClass", cause) {
internal constructor(txId: SecureHash, contractClass: String, cause: Throwable) : this(txId, contractClass, cause, cause.message ?: "")
@ -159,7 +146,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* @property txNotary the [Party] specified by the transaction header.
* @property outputNotary the [Party] specified by the errant state.
*/
@KeepForDJVM
class NotaryChangeInWrongTransactionType(txId: SecureHash, val txNotary: Party, val outputNotary: Party)
: TransactionVerificationException(txId, "Found unexpected notary change in transaction. Tx notary: $txNotary, found: $outputNotary", null)
@ -172,7 +158,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* @property missing the index of the state missing the encumbrance.
* @property inOut whether the issue exists in the input list or output list.
*/
@KeepForDJVM
class TransactionMissingEncumbranceException(txId: SecureHash, val missing: Int, val inOut: Direction)
: TransactionVerificationException(txId, "Missing required encumbrance $missing in $inOut", null)
@ -180,7 +165,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* If two or more states refer to another state (as their encumbrance), then the bi-directionality property cannot
* be satisfied.
*/
@KeepForDJVM
class TransactionDuplicateEncumbranceException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash, index: Int) : this(txId, "The bi-directionality property of encumbered output states " +
@ -191,7 +175,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* An encumbered state should also be referenced as the encumbrance of another state in order to satisfy the
* bi-directionality property (a full cycle should be present).
*/
@KeepForDJVM
class TransactionNonMatchingEncumbranceException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash, nonMatching: Collection<Int>) : this(txId,
@ -205,7 +188,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* transactions are not supported and thus two encumbered states with different notaries cannot be consumed
* in the same transaction.
*/
@KeepForDJVM
class TransactionNotaryMismatchEncumbranceException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash, encumberedIndex: Int, encumbranceIndex: Int, encumberedNotary: Party, encumbranceNotary: Party) :
@ -222,7 +204,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* @param state The [TransactionState] whose bundled state and contract are in conflict.
* @param requiredContractClassName The class name of the contract to which the state belongs.
*/
@KeepForDJVM
class TransactionContractConflictException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash, state: TransactionState<ContractState>, requiredContractClassName: String): this(txId,
@ -233,7 +214,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
}
// TODO: add reference to documentation
@KeepForDJVM
class TransactionRequiredContractUnspecifiedException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash, state: TransactionState<ContractState>) : this(txId,
@ -247,7 +227,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
/**
* If the network parameters associated with an input or reference state in a transaction are more recent than the network parameters of the new transaction itself.
*/
@KeepForDJVM
class TransactionNetworkParameterOrderingException(txId: SecureHash, message: String) :
TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash,
@ -265,7 +244,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
* @param txId Id of the transaction that has missing parameters hash in the resolution chain
* @param missingNetworkParametersHash Missing hash of the network parameters associated to this transaction
*/
@KeepForDJVM
class MissingNetworkParametersException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null) {
constructor(txId: SecureHash, missingNetworkParametersHash: SecureHash) :
@ -275,13 +253,11 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
/**
* @param txId Id of the transaction that Corda is no longer able to verify.
*/
@KeepForDJVM
class BrokenTransactionException(txId: SecureHash, message: String)
: TransactionVerificationException(txId, message, null)
/** Whether the inputs or outputs list contains an encumbrance issue, see [TransactionMissingEncumbranceException]. */
@CordaSerializable
@KeepForDJVM
enum class Direction {
/** Issue in the inputs list. */
INPUT,
@ -294,30 +270,25 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
// as a cause.
/** @suppress This class is not used: duplicate inputs throw a [IllegalStateException] instead. */
@Deprecated("This class is not used: duplicate inputs throw a [IllegalStateException] instead.")
@DeleteForDJVM
class DuplicateInputStates(txId: SecureHash, val duplicates: NonEmptySet<StateRef>)
: TransactionVerificationException(txId, "Duplicate inputs: ${duplicates.joinToString()}", null)
/** @suppress This class is obsolete and nothing has ever used it. */
@Deprecated("This class is obsolete and nothing has ever used it.")
@DeleteForDJVM
class MoreThanOneNotary(txId: SecureHash) : TransactionVerificationException(txId, "More than one notary", null)
/** @suppress This class is obsolete and nothing has ever used it. */
@Deprecated("This class is obsolete and nothing has ever used it.")
@DeleteForDJVM
class SignersMissing(txId: SecureHash, val missing: List<PublicKey>) : TransactionVerificationException(txId, "Signers missing: ${missing.joinToString()}", null)
/** @suppress This class is obsolete and nothing has ever used it. */
@Deprecated("This class is obsolete and nothing has ever used it.")
@DeleteForDJVM
class InvalidNotaryChange(txId: SecureHash)
: TransactionVerificationException(txId, "Detected a notary change. Outputs must use the same notary as inputs", null)
/**
* Thrown when multiple attachments provide the same file when building the AttachmentsClassloader for a transaction.
*/
@KeepForDJVM
class OverlappingAttachmentsException(txId: SecureHash, val path: String) : TransactionVerificationException(txId, "Multiple attachments define a file at $path.", null)
/**
@ -336,16 +307,12 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
// TODO: Make this descend from TransactionVerificationException so that untrusted attachments cause flows to be hospitalized.
/** Thrown during classloading upon encountering an untrusted attachment (eg. not in the [TRUSTED_UPLOADERS] list) */
@KeepForDJVM
class UntrustedAttachmentsException(val txId: SecureHash, val ids: List<SecureHash>) :
CordaException("Attempting to load untrusted transaction attachments: $ids. " +
"At this time these are not loadable because the DJVM sandbox has not yet been integrated. " +
"You will need to manually install the CorDapp to whitelist it for use.")
@KeepForDJVM
class UnsupportedHashTypeException(txId: SecureHash) : TransactionVerificationException(txId, "The transaction Id is defined by an unsupported hash type", null)
@KeepForDJVM
class AttachmentTooBigException(txId: SecureHash) : TransactionVerificationException(
txId, "The transaction attachments are too large and exceed both max transaction size and the maximum allowed compression ratio", null)

View File

@ -1,7 +1,5 @@
package net.corda.core.contracts
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.internal.VisibleForTesting
import net.corda.core.serialization.CordaSerializable
import java.util.*
@ -19,8 +17,7 @@ import java.util.*
* Subsequent copies and evolutions of a state should just copy the [externalId] and [id] fields unmodified.
*/
@CordaSerializable
@KeepForDJVM
data class UniqueIdentifier @JvmOverloads @DeleteForDJVM constructor(val externalId: String? = null, val id: UUID = UUID.randomUUID()) : Comparable<UniqueIdentifier> {
data class UniqueIdentifier @JvmOverloads constructor(val externalId: String? = null, val id: UUID = UUID.randomUUID()) : Comparable<UniqueIdentifier> {
override fun toString(): String = if (externalId != null) "${externalId}_$id" else id.toString()
companion object {

View File

@ -1,6 +1,5 @@
package net.corda.core.cordapp
import net.corda.core.DeleteForDJVM
import net.corda.core.DoNotImplement
import net.corda.core.cordapp.Cordapp.Info.*
import net.corda.core.crypto.SecureHash
@ -41,7 +40,6 @@ import java.net.URL
* @property targetPlatformVersion The target platform version this CorDapp was designed and tested on.
*/
@DoNotImplement
@DeleteForDJVM
interface Cordapp {
val name: String
val contractClassNames: List<String>

View File

@ -1,7 +1,6 @@
package net.corda.core.cordapp
import net.corda.core.CordaInternal
import net.corda.core.DeleteForDJVM
import net.corda.core.crypto.SecureHash
import java.lang.UnsupportedOperationException
@ -18,7 +17,6 @@ import java.lang.UnsupportedOperationException
* @property classLoader the classloader used to load this cordapp's classes
* @property config Configuration for this CorDapp
*/
@DeleteForDJVM
class CordappContext private constructor(
val cordapp: Cordapp,
val attachmentId: SecureHash?,

View File

@ -1,6 +1,5 @@
package net.corda.core.cordapp
import net.corda.core.DeleteForDJVM
import net.corda.core.DoNotImplement
import net.corda.core.contracts.ContractClassName
import net.corda.core.node.services.AttachmentId
@ -9,7 +8,6 @@ import net.corda.core.node.services.AttachmentId
* Provides access to what the node knows about loaded applications.
*/
@DoNotImplement
@DeleteForDJVM
interface CordappProvider {
/**
* Exposes the current CorDapp context which will contain information and configuration of the CorDapp that

View File

@ -1,10 +1,16 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.exactAdd
import net.corda.core.utilities.sequence
import org.bouncycastle.asn1.*
import org.bouncycastle.asn1.ASN1EncodableVector
import org.bouncycastle.asn1.ASN1Encoding
import org.bouncycastle.asn1.ASN1Integer
import org.bouncycastle.asn1.ASN1Object
import org.bouncycastle.asn1.ASN1Primitive
import org.bouncycastle.asn1.ASN1Sequence
import org.bouncycastle.asn1.DERBitString
import org.bouncycastle.asn1.DERSequence
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import java.security.PublicKey
@ -27,7 +33,6 @@ import java.util.*
* @property threshold specifies the minimum total weight required (in the simple case the minimum number of child
* signatures required) to satisfy the sub-tree rooted at this node.
*/
@KeepForDJVM
class CompositeKey private constructor(val threshold: Int, children: List<NodeAndWeight>) : PublicKey {
companion object {
const val KEY_ALGORITHM = "COMPOSITE"
@ -144,7 +149,6 @@ class CompositeKey private constructor(val threshold: Int, children: List<NodeAn
* Holds node - weight pairs for a CompositeKey. Ordered first by weight, then by node's hashCode.
* Each node should be assigned with a positive weight to avoid certain types of weight underflow attacks.
*/
@KeepForDJVM
@CordaSerializable
data class NodeAndWeight(val node: PublicKey, val weight: Int) : Comparable<NodeAndWeight>, ASN1Object() {
init {
@ -162,7 +166,7 @@ class CompositeKey private constructor(val threshold: Int, children: List<NodeAn
override fun toASN1Primitive(): ASN1Primitive {
val vector = ASN1EncodableVector()
vector.add(DERBitString(node.encoded))
vector.add(DERBitString(Crypto.encodePublicKey(node)))
vector.add(ASN1Integer(weight.toLong()))
return DERSequence(vector)
}
@ -243,7 +247,6 @@ class CompositeKey private constructor(val threshold: Int, children: List<NodeAn
override fun toString() = "(${children.joinToString()})"
/** A helper class for building a [CompositeKey]. */
@KeepForDJVM
class Builder {
private val children: MutableList<NodeAndWeight> = mutableListOf()

View File

@ -1,6 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import java.security.*
import java.security.spec.InvalidKeySpecException
import java.security.spec.KeySpec
@ -9,7 +8,6 @@ import java.security.spec.X509EncodedKeySpec
/**
* Factory for generating composite keys from ASN.1 format key specifications. This is used by [CordaSecurityProvider].
*/
@KeepForDJVM
class CompositeKeyFactory : KeyFactorySpi() {
@Throws(InvalidKeySpecException::class)

View File

@ -1,6 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.deserialize
import java.io.ByteArrayOutputStream
import java.security.InvalidAlgorithmParameterException
@ -15,7 +14,6 @@ import java.security.spec.AlgorithmParameterSpec
/**
* Dedicated class for storing a set of signatures that comprise [CompositeKey].
*/
@KeepForDJVM
class CompositeSignature : Signature(SIGNATURE_ALGORITHM) {
companion object {
const val SIGNATURE_ALGORITHM = "COMPOSITESIG"

View File

@ -1,6 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.CordaSerializable
/**
@ -8,7 +7,6 @@ import net.corda.core.serialization.CordaSerializable
* serialization format.
*/
@CordaSerializable
@KeepForDJVM
data class CompositeSignaturesWithKeys(val sigs: List<TransactionSignature>) {
companion object {
val EMPTY = CompositeSignaturesWithKeys(emptyList())

View File

@ -1,7 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.StubOutForDJVM
import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_KEY
import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_SIGNATURE
import net.corda.core.crypto.internal.PlatformSecureRandomService
@ -10,13 +8,14 @@ import java.security.Provider
import java.util.*
import java.util.concurrent.ConcurrentHashMap
@KeepForDJVM
@Suppress("DEPRECATION") // JDK11: should replace with Provider(String name, double version, String info) (since 9)
class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME security provider wrapper") {
companion object {
const val PROVIDER_NAME = "Corda"
}
private val services = ConcurrentHashMap<Pair<String, String>, Optional<Service>>()
init {
put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", CompositeKeyFactory::class.java.name)
put("Alg.Alias.KeyFactory.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM)
@ -27,47 +26,19 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur
putPlatformSecureRandomService()
}
@StubOutForDJVM
private fun putPlatformSecureRandomService() {
putService(PlatformSecureRandomService(this))
}
override fun getService(type: String, algorithm: String): Service? = serviceFactory(type, algorithm)
// Used to work around banning of ConcurrentHashMap in DJVM
@Suppress("TooGenericExceptionCaught")
private val serviceFactory: (String, String) -> Service? = try {
// Will throw UnsupportedOperationException in DJVM
makeCachingFactory()
} catch (e: Exception) {
makeFactory()
override fun getService(type: String, algorithm: String): Service? {
return services.getOrPut(Pair(type, algorithm)) {
Optional.ofNullable(superGetService(type, algorithm))
}.orElse(null)
}
private fun superGetService(type: String, algorithm: String): Service? = super.getService(type, algorithm)
@StubOutForDJVM
private fun makeCachingFactory(): Function2<String, String, Service?> {
return object : Function2<String, String, Service?> {
private val services = ConcurrentHashMap<Pair<String, String>, Optional<Service>>()
override fun invoke(type: String, algorithm: String): Service? {
return services.getOrPut(Pair(type, algorithm)) {
Optional.ofNullable(superGetService(type, algorithm))
}.orElse(null)
}
}
}
private fun makeFactory(): Function2<String, String, Service?> {
return object : Function2<String, String, Service?> {
override fun invoke(type: String, algorithm: String): Service? {
return superGetService(type, algorithm)
}
}
}
}
@KeepForDJVM
object CordaObjectIdentifier {
// UUID-based OID
// TODO define and use an official Corda OID in [CordaOID]. We didn't do yet for backwards compatibility purposes,

View File

@ -1,10 +1,9 @@
package net.corda.core.crypto
import net.corda.core.CordaOID
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.crypto.internal.AliasPrivateKey
import net.corda.core.crypto.internal.Instances.withSignature
import net.corda.core.crypto.internal.PublicKeyCache
import net.corda.core.crypto.internal.bouncyCastlePQCProvider
import net.corda.core.crypto.internal.cordaBouncyCastleProvider
import net.corda.core.crypto.internal.cordaSecurityProvider
@ -12,6 +11,7 @@ import net.corda.core.crypto.internal.`id-Curve25519ph`
import net.corda.core.crypto.internal.providerMap
import net.corda.core.internal.utilities.PrivateInterner
import net.corda.core.serialization.serialize
import net.corda.core.utilities.ByteSequence
import net.i2p.crypto.eddsa.EdDSAEngine
import net.i2p.crypto.eddsa.EdDSAPrivateKey
import net.i2p.crypto.eddsa.EdDSAPublicKey
@ -81,7 +81,6 @@ import javax.crypto.spec.SecretKeySpec
* <li>SPHINCS256_SHA512 (SPHINCS-256 hash-based signature scheme using SHA512 as hash algorithm).
* </ul>
*/
@KeepForDJVM
object Crypto {
/**
* RSA PKCS#1 signature scheme using SHA256 for message hashing.
@ -227,7 +226,6 @@ object Crypto {
@JvmStatic
fun supportedSignatureSchemes(): List<SignatureScheme> = ArrayList(signatureSchemeMap.values)
@DeleteForDJVM
@JvmStatic
fun findProvider(name: String): Provider {
return providerMap[name] ?: throw IllegalArgumentException("Unrecognised provider: $name")
@ -281,7 +279,7 @@ object Crypto {
*/
@JvmStatic
fun findSignatureScheme(key: PublicKey): SignatureScheme {
val keyInfo = SubjectPublicKeyInfo.getInstance(key.encoded)
val keyInfo = SubjectPublicKeyInfo.getInstance(encodePublicKey(key))
return findSignatureScheme(keyInfo.algorithm)
}
@ -306,7 +304,6 @@ object Crypto {
* @throws IllegalArgumentException on not supported scheme or if the given key specification
* is inappropriate for this key factory to produce a private key.
*/
@DeleteForDJVM
@JvmStatic
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
@ -318,7 +315,6 @@ object Crypto {
return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)))
}
@DeleteForDJVM
private fun decodeAliasPrivateKey(keyInfo: PrivateKeyInfo): PrivateKey {
val encodable = keyInfo.parsePrivateKey() as DLSequence
val derutF8String = encodable.getObjectAt(0)
@ -334,7 +330,6 @@ object Crypto {
* @throws IllegalArgumentException on not supported scheme or if the given key specification
* is inappropriate for this key factory to produce a private key.
*/
@DeleteForDJVM
@JvmStatic
@Throws(InvalidKeySpecException::class)
fun decodePrivateKey(schemeCodeName: String, encodedKey: ByteArray): PrivateKey {
@ -373,10 +368,17 @@ object Crypto {
*/
@JvmStatic
fun decodePublicKey(encodedKey: ByteArray): PublicKey {
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey)
val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm)
val keyFactory = keyFactory(signatureScheme)
return convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
return PublicKeyCache.publicKeyForCachedBytes(ByteSequence.of(encodedKey)) ?: {
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey)
val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm)
val keyFactory = keyFactory(signatureScheme)
convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
}()
}
@JvmStatic
fun encodePublicKey(key: PublicKey): ByteArray {
return PublicKeyCache.bytesForCachedPublicKey(key)?.bytes ?: key.encoded
}
/**
@ -429,7 +431,6 @@ object Crypto {
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(privateKey: PrivateKey, clearData: ByteArray): ByteArray = doSign(findSignatureScheme(privateKey), privateKey, clearData)
@ -444,7 +445,6 @@ object Crypto {
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
@ -461,7 +461,6 @@ object Crypto {
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray {
@ -501,7 +500,6 @@ object Crypto {
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@JvmStatic
@Throws(InvalidKeyException::class, SignatureException::class)
fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature {
@ -688,7 +686,6 @@ object Crypto {
* @return a KeyPair for the requested signature scheme code name.
* @throws IllegalArgumentException if the requested signature scheme is not supported.
*/
@DeleteForDJVM
@JvmStatic
fun generateKeyPair(schemeCodeName: String): KeyPair = generateKeyPair(findSignatureScheme(schemeCodeName))
@ -699,7 +696,6 @@ object Crypto {
* @return a new [KeyPair] for the requested [SignatureScheme].
* @throws IllegalArgumentException if the requested signature scheme is not supported.
*/
@DeleteForDJVM
@JvmOverloads
@JvmStatic
fun generateKeyPair(signatureScheme: SignatureScheme = DEFAULT_SIGNATURE_SCHEME): KeyPair {
@ -993,7 +989,8 @@ object Crypto {
}
private val interner = PrivateInterner<PublicKey>()
private fun internPublicKey(key: PublicKey): PublicKey = interner.intern(key)
private fun internPublicKey(key: PublicKey): PublicKey = PublicKeyCache.cachePublicKey(interner.intern(key))
private fun convertIfBCEdDSAPublicKey(key: PublicKey): PublicKey {
return internPublicKey(when (key) {
@ -1049,7 +1046,6 @@ object Crypto {
* @throws IllegalArgumentException on not supported scheme or if the given key specification
* is inappropriate for a supported key factory to produce a private key.
*/
@DeleteForDJVM
@JvmStatic
fun toSupportedPrivateKey(key: PrivateKey): PrivateKey {
return when (key) {
@ -1086,7 +1082,6 @@ object Crypto {
* CRL & CSR checks etc.).
*/
// TODO: perform all cryptographic operations via Crypto.
@DeleteForDJVM
@JvmStatic
fun registerProviders() {
providerMap
@ -1097,7 +1092,6 @@ object Crypto {
setBouncyCastleRNG()
}
@DeleteForDJVM
private fun setBouncyCastleRNG() {
CryptoServicesRegistrar.setSecureRandom(newSecureRandom())
}

View File

@ -1,11 +1,7 @@
@file:Suppress("MatchingDeclarationName")
@file:KeepForDJVM
@file:JvmName("CryptoUtils")
package net.corda.core.crypto
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.contracts.PrivacySalt
import net.corda.core.crypto.internal.platformSecureRandomFactory
import net.corda.core.serialization.SerializationDefaults
@ -32,7 +28,6 @@ import java.security.SignatureException
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@Throws(InvalidKeyException::class, SignatureException::class)
fun PrivateKey.sign(bytesToSign: ByteArray): DigitalSignature = DigitalSignature(Crypto.doSign(this, bytesToSign))
@ -45,7 +40,6 @@ fun PrivateKey.sign(bytesToSign: ByteArray): DigitalSignature = DigitalSignature
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@Throws(InvalidKeyException::class, SignatureException::class)
fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
return DigitalSignature.WithKey(publicKey, this.sign(bytesToSign).bytes)
@ -59,12 +53,10 @@ fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey): DigitalSignat
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@Throws(InvalidKeyException::class, SignatureException::class)
fun KeyPair.sign(bytesToSign: ByteArray): DigitalSignature.WithKey = private.sign(bytesToSign, public)
/** Helper function to sign the bytes of [bytesToSign] with a key pair. */
@DeleteForDJVM
@Throws(InvalidKeyException::class, SignatureException::class)
fun KeyPair.sign(bytesToSign: OpaqueBytes): DigitalSignature.WithKey = sign(bytesToSign.bytes)
@ -76,7 +68,6 @@ fun KeyPair.sign(bytesToSign: OpaqueBytes): DigitalSignature.WithKey = sign(byte
* @throws InvalidKeyException if the private key is invalid.
* @throws SignatureException if signing is not possible due to malformed data or private key.
*/
@DeleteForDJVM
@Throws(InvalidKeyException::class, SignatureException::class)
fun KeyPair.sign(signableData: SignableData): TransactionSignature = Crypto.doSign(this, signableData)
@ -151,7 +142,6 @@ operator fun KeyPair.component1(): PrivateKey = this.private
operator fun KeyPair.component2(): PublicKey = this.public
/** A simple wrapper that will make it easier to swap out the signature algorithm we use in future. */
@DeleteForDJVM
fun generateKeyPair(): KeyPair = Crypto.generateKeyPair()
/**
@ -196,7 +186,6 @@ fun KeyPair.verify(signatureData: ByteArray, clearData: ByteArray): Boolean = Cr
* or if no strong [SecureRandom] implementations are available or if Security.getProperty("securerandom.strongAlgorithms") is null or empty,
* which should never happen and suggests an unusual JVM or non-standard Java library.
*/
@DeleteForDJVM
@Throws(NoSuchAlgorithmException::class)
fun secureRandomBytes(numOfBytes: Int): ByteArray = ByteArray(numOfBytes).apply { newSecureRandom().nextBytes(this) }
@ -241,7 +230,6 @@ object DummySecureRandom : SecureRandom(DummySecureRandomSpi(), null)
* or if no strong SecureRandom implementations are available or if Security.getProperty("securerandom.strongAlgorithms") is null or empty,
* which should never happen and suggests an unusual JVM or non-standard Java library.
*/
@DeleteForDJVM
@Throws(NoSuchAlgorithmException::class)
fun newSecureRandom(): SecureRandom = platformSecureRandomFactory()
@ -249,7 +237,6 @@ fun newSecureRandom(): SecureRandom = platformSecureRandomFactory()
* Returns a random positive non-zero long generated using a secure RNG. This function sacrifies a bit of entropy in order
* to avoid potential bugs where the value is used in a context where negative numbers or zero are not expected.
*/
@DeleteForDJVM
fun random63BitValue(): Long {
while (true) {
val candidate = Math.abs(newSecureRandom().nextLong())

View File

@ -1,11 +1,8 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
/**
* Interface for injecting custom digest implementation bypassing JCA.
*/
@KeepForDJVM
interface DigestAlgorithm {
/**
* Algorithm identifier.

View File

@ -1,7 +1,5 @@
package net.corda.core.crypto
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.contracts.PrivacySalt
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationDefaults
@ -24,13 +22,11 @@ import java.security.MessageDigest
* @param hashAlgorithm the name of the hash algorithm to be used for the instance
*/
@CordaSerializable
@KeepForDJVM
data class DigestService(val hashAlgorithm: String) {
init {
require(hashAlgorithm.isNotEmpty()) { "Hash algorithm name unavailable or not specified" }
}
@KeepForDJVM
companion object {
private const val NONCE_SIZE = 8
/**
@ -114,5 +110,4 @@ data class DigestService(val hashAlgorithm: String) {
}
}
@DeleteForDJVM
fun DigestService.randomHash(): SecureHash = SecureHash.random(this.hashAlgorithm)

View File

@ -1,6 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.OpaqueBytes
import java.security.InvalidKeyException
@ -9,10 +8,8 @@ import java.security.SignatureException
/** A wrapper around a digital signature. */
@CordaSerializable
@KeepForDJVM
open class DigitalSignature(bytes: ByteArray) : OpaqueBytes(bytes) {
/** A digital signature that identifies who the public key is owned by. */
@KeepForDJVM
open class WithKey(val by: PublicKey, bytes: ByteArray) : DigitalSignature(bytes) {
/**
* Utility to simplify the act of verifying a signature.

View File

@ -1,6 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import java.util.*
/**
@ -15,8 +14,9 @@ import java.util.*
sealed class MerkleTree {
abstract val hash: SecureHash
@KeepForDJVM data class Leaf(override val hash: SecureHash) : MerkleTree()
@KeepForDJVM data class Node(override val hash: SecureHash, val left: MerkleTree, val right: MerkleTree) : MerkleTree()
data class Leaf(override val hash: SecureHash) : MerkleTree()
data class Node(override val hash: SecureHash, val left: MerkleTree, val right: MerkleTree) : MerkleTree()
companion object {
private fun isPow2(num: Int): Boolean = num and (num - 1) == 0

View File

@ -1,10 +1,8 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.identity.AnonymousParty
import java.security.PublicKey
@KeepForDJVM
object NullKeys {
object NullPublicKey : PublicKey, Comparable<PublicKey> {
override fun getAlgorithm() = "NULL"

View File

@ -2,12 +2,10 @@ package net.corda.core.crypto
import net.corda.core.CordaException
import net.corda.core.CordaInternal
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.DeprecatedConstructorForDeserialization
import java.util.*
@KeepForDJVM
@CordaSerializable
class MerkleTreeException(val reason: String) : CordaException("Partial Merkle Tree exception. Reason: $reason")
@ -45,7 +43,6 @@ class MerkleTreeException(val reason: String) : CordaException("Partial Merkle T
* (there can be a difference in obtained leaves ordering - that's why it's a set comparison not hashing leaves into a tree).
* If both equalities hold, we can assume that l3 and l5 belong to the transaction with root h15.
*/
@KeepForDJVM
@CordaSerializable
class PartialMerkleTree(val root: PartialTree) {
/**
@ -57,9 +54,9 @@ class PartialMerkleTree(val root: PartialTree) {
*/
@CordaSerializable
sealed class PartialTree {
@KeepForDJVM data class IncludedLeaf(val hash: SecureHash) : PartialTree()
@KeepForDJVM data class Leaf(val hash: SecureHash) : PartialTree()
@KeepForDJVM data class Node(val left: PartialTree, val right: PartialTree, val hashAlgorithm: String? = SecureHash.SHA2_256) : PartialTree(){
data class IncludedLeaf(val hash: SecureHash) : PartialTree()
data class Leaf(val hash: SecureHash) : PartialTree()
data class Node(val left: PartialTree, val right: PartialTree, val hashAlgorithm: String? = SecureHash.SHA2_256) : PartialTree() {
/**
* Old version of [PartialTree.Node] constructor for ABI compatibility.
*/

View File

@ -1,11 +1,8 @@
@file:Suppress("TooManyFunctions", "MagicNumber")
@file:KeepForDJVM
package net.corda.core.crypto
import io.netty.util.concurrent.FastThreadLocal
import net.corda.core.CordaInternal
import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM
import net.corda.core.crypto.internal.DigestAlgorithmFactory
import net.corda.core.internal.utilities.Internable
import net.corda.core.internal.utilities.PrivateInterner
@ -13,7 +10,6 @@ import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.parseAsHex
import net.corda.core.utilities.toHexString
import java.nio.ByteBuffer
import java.security.MessageDigest
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
@ -23,7 +19,6 @@ import java.util.function.Supplier
* Container for a cryptographically secure hash value.
* Provides utilities for generating a cryptographic hash using different algorithms (currently only SHA-256 supported).
*/
@KeepForDJVM
@CordaSerializable
sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
/** SHA-256 is part of the SHA-2 hash function family. Generated hash is fixed size, 256-bits (32-bytes). */
@ -39,9 +34,10 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
return true
}
// This is an efficient hashCode, because there is no point in performing a hash calculation on a cryptographic hash.
// It just takes the first 4 bytes and transforms them into an Int.
override fun hashCode() = ByteBuffer.wrap(bytes).int
override fun hashCode(): Int {
// Hash code not overridden on purpose (super class impl will do), but don't delete or have to deal with detekt and API checker.
return super.hashCode()
}
/**
* Convert the hash value to an uppercase hexadecimal [String].
@ -62,7 +58,10 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
}
}
override fun hashCode() = ByteBuffer.wrap(bytes).int
override fun hashCode(): Int {
// Hash code not overridden on purpose (super class impl will do), but don't delete or have to deal with detekt and API checker.
return super.hashCode()
}
override fun toString(): String {
return "$algorithm$DELIMITER${toHexString()}"
@ -288,14 +287,12 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
/**
* Generates a random SHA-256 value.
*/
@DeleteForDJVM
@JvmStatic
fun randomSHA256() = sha256(secureRandomBytes(32))
/**
* Generates a random hash value.
*/
@DeleteForDJVM
@JvmStatic
fun random(algorithm: String): SecureHash {
return if (algorithm == SHA2_256) {

View File

@ -1,6 +1,5 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.serialization.CordaSerializable
/**
@ -13,5 +12,4 @@ import net.corda.core.serialization.CordaSerializable
* @param signatureMetadata meta data required.
*/
@CordaSerializable
@KeepForDJVM
data class SignableData(val txId: SecureHash, val signatureMetadata: SignatureMetadata)

Some files were not shown because too many files have changed in this diff Show More