mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
ENT-11056: Compile the external verifier using Kotlin 1.2 (#7622)
This requires Kotlin 1.2 versions of core and serialization (core-1.2 and serialization-1.2 respectively), which are just "shell" modules and which compile the existing source code with Kotlin 1.2. The 1.2 plugin does not work with the current version of Gradle and so the 1.2 compiler has to be called directly. Now with two versions of Kotlin in the code base, each module needs to have its version manually specified to ensure a clean separation. Otherwise, the default Kotlin version can override 1.2 when needed. Some of the code was tidied-up or improved to enable it to be cross-compiled. For post-1.2 APIs being used, they have been copied into core-1.2 with the same method signatures. OpenTelemetryComponent was moved to node-api, along with the dependency, to avoid also having a 1.2 version for the opentelemetry module.
This commit is contained in:
parent
4791f0d84f
commit
406f7ff292
46
build.gradle
46
build.gradle
@ -245,7 +245,7 @@ logger.lifecycle("Building Corda version: {}", corda_release_version)
|
||||
logger.lifecycle("User home: {}", System.getProperty('user.home'))
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'kotlin-allopen'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'org.owasp.dependencycheck'
|
||||
@ -437,10 +437,12 @@ allprojects {
|
||||
}
|
||||
|
||||
configurations {
|
||||
all {
|
||||
configureEach {
|
||||
resolutionStrategy {
|
||||
// Force dependencies to use the same version of Kotlin as Corda.
|
||||
force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
if (pluginManager.hasPlugin("org.jetbrains.kotlin.jvm")) {
|
||||
// Force dependencies to use the same version of Kotlin as Corda.
|
||||
force "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
}
|
||||
|
||||
// Force dependencies to use the same version of Guava as Corda.
|
||||
force "com.google.guava:guava:$guava_version"
|
||||
@ -487,24 +489,26 @@ allprojects {
|
||||
// Effectively delete this unused and unwanted transitive dependency of Artemis.
|
||||
substitute module('org.jgroups:jgroups') with module("org.apache.activemq:artemis-commons:$artemis_version")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select all of the compileClasspath and runtimeClasspath etc configurations,
|
||||
// but NOT the "classpath" configuration, as that is used by the Gradle plugins.
|
||||
matching { it.name.endsWith("Classpath") }.configureEach { cfg ->
|
||||
cfg.resolutionStrategy {
|
||||
dependencySubstitution {
|
||||
// Force dependencies to use the same version of Kotlin as Corda.
|
||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib-common') with module("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version")
|
||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib') with module("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
|
||||
substitute module('org.jetbrains.kotlin:kotlin-reflect') with module("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
|
||||
}
|
||||
|
||||
// FORCE Gradle to use latest SNAPSHOT dependencies.
|
||||
cacheChangingModulesFor 0, 'seconds'
|
||||
}
|
||||
}
|
||||
|
||||
if (pluginManager.hasPlugin("org.jetbrains.kotlin.jvm")) {
|
||||
// Select all of the compileClasspath and runtimeClasspath etc configurations,
|
||||
// but NOT the "classpath" configuration, as that is used by the Gradle plugins.
|
||||
matching { it.name.endsWith("Classpath") }.configureEach { cfg ->
|
||||
cfg.resolutionStrategy {
|
||||
dependencySubstitution {
|
||||
// Force dependencies to use the same version of Kotlin as Corda.
|
||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib-common') with module("org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version")
|
||||
substitute module('org.jetbrains.kotlin:kotlin-stdlib') with module("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
|
||||
substitute module('org.jetbrains.kotlin:kotlin-reflect') with module("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,9 +561,9 @@ tasks.register('jacocoRootReport', JacocoReport) {
|
||||
// classDirectories = files(subprojects.sourceSets.main.output)
|
||||
// executionData = files(subprojects.jacocoTestReport.executionData)
|
||||
reports {
|
||||
html.enabled = true
|
||||
xml.enabled = true
|
||||
csv.enabled = false
|
||||
html.required = true
|
||||
xml.required = true
|
||||
csv.required = false
|
||||
}
|
||||
onlyIf = {
|
||||
true
|
||||
@ -595,7 +599,7 @@ tasks.register('detektBaseline', JavaExec) {
|
||||
}
|
||||
|
||||
tasks.withType(Test).configureEach {
|
||||
reports.html.destination = file("${reporting.baseDir}/${name}")
|
||||
reports.html.outputLocation.set(file("${reporting.baseDir}/${name}"))
|
||||
}
|
||||
|
||||
tasks.register('testReport', TestReport) {
|
||||
|
@ -46,8 +46,9 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation group: 'com.github.docker-java', name: 'docker-java', version: constants.dockerJavaVersion
|
||||
implementation group: 'com.github.docker-java', name: 'docker-java-transport-httpclient5', version: constants.dockerJavaVersion
|
||||
implementation "com.github.docker-java:docker-java:$constants.dockerJavaVersion"
|
||||
implementation "com.github.docker-java:docker-java-transport-httpclient5:$constants.dockerJavaVersion"
|
||||
implementation "org.jooq:joor:$constants.joorVersion"
|
||||
|
||||
if (System.getenv('CORDA_ARTIFACTORY_USERNAME') != null || project.hasProperty('cordaArtifactoryUsername')) {
|
||||
implementation "com.r3.internal.gradle.plugins:publish:$internalPublishVersion"
|
||||
|
91
buildSrc/src/main/groovy/corda.kotlin-1.2.gradle
Normal file
91
buildSrc/src/main/groovy/corda.kotlin-1.2.gradle
Normal file
@ -0,0 +1,91 @@
|
||||
import org.gradle.api.internal.file.DefaultSourceDirectorySet
|
||||
|
||||
import static org.joor.Reflect.onClass
|
||||
|
||||
pluginManager.apply(Kotlin12Plugin.class)
|
||||
|
||||
// We cannot use the 1.2 Kotlin plugin as it only works with a very old version of Gradle, which itself will only work on Java 8. So we need
|
||||
// our own plugin which calls the 1.2 compiler directly.
|
||||
class Kotlin12Plugin implements Plugin<Project> {
|
||||
private static final KOTLIN_VERSION = "1.2.71"
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
project.pluginManager.apply(JavaPlugin.class)
|
||||
|
||||
project.extensions.add("kotlin_1_2_version", KOTLIN_VERSION)
|
||||
project.dependencies.add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$KOTLIN_VERSION")
|
||||
|
||||
def kotlinCompilerConfiguration = project.configurations.create("kotlinCompiler")
|
||||
project.dependencies.add("kotlinCompiler", "org.jetbrains.kotlin:kotlin-compiler:$KOTLIN_VERSION")
|
||||
|
||||
project.extensions.getByType(JavaPluginExtension.class).sourceSets.configureEach { sourceSet ->
|
||||
// Create the "src/*/kotlin" SourceDirectorySet, alongside the "java" one
|
||||
def kotlinSourceDirectorySet = new DefaultSourceDirectorySet(project.objects.sourceDirectorySet("kotlin", "${sourceSet.displayName} Kotlin source"))
|
||||
sourceSet.extensions.add(SourceDirectorySet.class, "kotlin", kotlinSourceDirectorySet)
|
||||
kotlinSourceDirectorySet.filter.include("**/*.java", "**/*.kt")
|
||||
kotlinSourceDirectorySet.srcDir(project.file("src/${sourceSet.name}/kotlin"))
|
||||
|
||||
def allKotlin = project.objects.sourceDirectorySet("allkotlin", "${sourceSet.displayName} Kotlin source")
|
||||
allKotlin.filter.include("**/*.kt")
|
||||
allKotlin.source(kotlinSourceDirectorySet)
|
||||
|
||||
sourceSet.allJava.source(kotlinSourceDirectorySet)
|
||||
sourceSet.allSource.source(kotlinSourceDirectorySet)
|
||||
|
||||
def kotlinBuildDir = project.layout.buildDirectory.dir("classes/kotlin/${sourceSet.name}")
|
||||
sourceSet.output.dir(kotlinBuildDir)
|
||||
|
||||
def taskSourceSetName = isMain(sourceSet) ? "" : sourceSet.name.capitalize()
|
||||
|
||||
def compileKotlin = project.tasks.register("compile${taskSourceSetName}Kotlin", KotlinCompile.class) { task ->
|
||||
// The 1.2 compiler needs to be laoded in a separate class loader, as the build classpath already contains its own version
|
||||
// of Kotlin.
|
||||
task.compilerClasspath.from(kotlinCompilerConfiguration)
|
||||
task.source(allKotlin)
|
||||
// Paradoxically, the Java sources are also required by the Kotlin compiler. This is actually so that it can correctly
|
||||
// resolve any references the Kotlin code makes to Java code.
|
||||
task.source(sourceSet.allJava)
|
||||
task.classpath = sourceSet.compileClasspath
|
||||
task.destinationDirectory = kotlinBuildDir
|
||||
}
|
||||
|
||||
// Compiling the Java code needs the compiled Kotlin code first
|
||||
project.tasks.named("compile${taskSourceSetName}Java", JavaCompile.class) { task ->
|
||||
task.classpath += project.files(compileKotlin.map { it.destinationDirectory })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KotlinCompile extends AbstractCompile {
|
||||
@Classpath
|
||||
abstract ConfigurableFileCollection getCompilerClasspath()
|
||||
|
||||
@TaskAction
|
||||
void compile() {
|
||||
def args = [
|
||||
"-jvm-target", "1.8",
|
||||
"-language-version", "1.2",
|
||||
"-api-version", "1.2",
|
||||
"-java-parameters",
|
||||
"-Xjvm-default=compatibility",
|
||||
"-no-stdlib",
|
||||
"-Xallow-kotlin-package", // We may have copies of stdlib APIs (see `core-1.2`)
|
||||
"-cp", classpath.asPath,
|
||||
"-d", destinationDirectory.get().asFile.absolutePath
|
||||
]
|
||||
args.addAll(source.collect { it.absolutePath })
|
||||
|
||||
logger.info("args: {}", args)
|
||||
|
||||
def compilerClassLoader = new URLClassLoader(compilerClasspath.collect { it.toURI().toURL() } as URL[])
|
||||
def exitCode = onClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler", compilerClassLoader)
|
||||
.create()
|
||||
.call("exec", System.err, args as String[])
|
||||
.get()
|
||||
if (exitCode.toString() != "OK") {
|
||||
throw new GradleException("Compilation error. See log for more details")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'net.corda.plugins.api-scanner'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
@ -1,14 +1,15 @@
|
||||
package net.corda.client.rpc.internal
|
||||
|
||||
import net.corda.core.internal.telemetry.OpenTelemetryComponent
|
||||
import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent
|
||||
import net.corda.core.internal.telemetry.TelemetryServiceImpl
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.nodeapi.internal.telemetry.OpenTelemetryComponent
|
||||
|
||||
class RPCClientTelemetry(val serviceName: String, val openTelemetryEnabled: Boolean,
|
||||
val simpleLogTelemetryEnabled: Boolean, val spanStartEndEventsEnabled: Boolean,
|
||||
class RPCClientTelemetry(serviceName: String,
|
||||
val openTelemetryEnabled: Boolean,
|
||||
val simpleLogTelemetryEnabled: Boolean,
|
||||
val spanStartEndEventsEnabled: Boolean,
|
||||
val copyBaggageToTags: Boolean) {
|
||||
|
||||
companion object {
|
||||
private val log = contextLogger()
|
||||
}
|
||||
@ -39,4 +40,4 @@ class RPCClientTelemetry(val serviceName: String, val openTelemetryEnabled: Bool
|
||||
fun <T> getTelemetryHandle(telemetryClass: Class<T>): T? {
|
||||
return telemetryService.getTelemetryHandle(telemetryClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// This contains the SwapIdentitiesFlow which can be used for exchanging confidential identities as part of a flow.
|
||||
// TODO: Merge this into core: the original plan was to develop it independently but in practice it's too widely used to break compatibility now, as finance uses it.
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||
apply plugin: 'net.corda.plugins.cordapp'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
@ -100,3 +100,4 @@ controlsfxVersion=8.40.15
|
||||
fontawesomefxCommonsVersion=11.0
|
||||
fontawesomefxFontawesomeVersion=4.7.0-11
|
||||
javaassistVersion=3.29.2-GA
|
||||
joorVersion=0.9.15
|
||||
|
4
core-1.2/README.md
Normal file
4
core-1.2/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
This is a Kotlin 1.2 version of the `core` module, which is consumed by the `verifier` module, for verifying contracts written in Kotlin
|
||||
1.2. This is just a "shell" module which uses the existing the code in `core` and compiles it with the 1.2 compiler.
|
||||
|
||||
To allow `core` to benefit from new APIs introduced since 1.2, those APIs much be copied into this module with the same `kotlin` package.
|
34
core-1.2/build.gradle
Normal file
34
core-1.2/build.gradle
Normal file
@ -0,0 +1,34 @@
|
||||
apply plugin: "corda.kotlin-1.2"
|
||||
apply plugin: "corda.common-publishing"
|
||||
|
||||
description 'Corda core built with Kotlin 1.2'
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDir("../core/src/main/java")
|
||||
kotlin.srcDir("../core/src/main/kotlin")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Use the same dependencies as core (minus Kotlin)
|
||||
implementation(project(path: ":core", configuration: "resolvableImplementation")) {
|
||||
exclude(group: "org.jetbrains.kotlin")
|
||||
}
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_1_2_version"
|
||||
implementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'corda-core-1.2'
|
||||
}
|
||||
|
||||
// TODO Don't publish publicly as it's only needed by the `verifier` module which consumes this into a fat jar.
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
artifactId 'corda-core-1.2'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||
@file:Suppress("unused", "MagicNumber", "INVISIBLE_MEMBER")
|
||||
|
||||
package kotlin.collections
|
||||
|
||||
inline fun <K, V> Iterable<K>.associateWith(valueSelector: (K) -> V): Map<K, V> {
|
||||
val result = LinkedHashMap<K, V>(mapCapacity(if (this is Collection<*>) size else 10).coerceAtLeast(16))
|
||||
return associateWithTo(result, valueSelector)
|
||||
}
|
||||
|
||||
inline fun <K, V, M : MutableMap<in K, in V>> Iterable<K>.associateWithTo(destination: M, valueSelector: (K) -> V): M {
|
||||
for (element in this) {
|
||||
destination.put(element, valueSelector(element))
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
inline fun <T> Iterable<T>.sumOf(selector: (T) -> Int): Int {
|
||||
var sum = 0
|
||||
for (element in this) {
|
||||
sum += selector(element)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
inline fun <T, R : Comparable<R>> Iterable<T>.maxOf(selector: (T) -> R): R {
|
||||
val iterator = iterator()
|
||||
if (!iterator.hasNext()) throw NoSuchElementException()
|
||||
var maxValue = selector(iterator.next())
|
||||
while (iterator.hasNext()) {
|
||||
val v = selector(iterator.next())
|
||||
if (maxValue < v) {
|
||||
maxValue = v
|
||||
}
|
||||
}
|
||||
return maxValue
|
||||
}
|
37
core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt
Normal file
37
core-1.2/src/main/kotlin/kotlin/io/path/KotlinIoPath1.2.kt
Normal file
@ -0,0 +1,37 @@
|
||||
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||
@file:Suppress("unused", "SpreadOperator", "NOTHING_TO_INLINE")
|
||||
|
||||
package kotlin.io.path
|
||||
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.LinkOption
|
||||
import java.nio.file.OpenOption
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.attribute.FileAttribute
|
||||
|
||||
inline operator fun Path.div(other: String): Path = this.resolve(other)
|
||||
|
||||
fun Path.listDirectoryEntries(glob: String = "*"): List<Path> = Files.newDirectoryStream(this, glob).use { it.toList() }
|
||||
|
||||
inline fun Path.createDirectories(vararg attributes: FileAttribute<*>): Path = Files.createDirectories(this, *attributes)
|
||||
|
||||
inline fun Path.deleteIfExists(): Boolean = Files.deleteIfExists(this)
|
||||
|
||||
inline fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options)
|
||||
|
||||
inline fun Path.inputStream(vararg options: OpenOption): InputStream = Files.newInputStream(this, *options)
|
||||
|
||||
inline fun Path.outputStream(vararg options: OpenOption): OutputStream = Files.newOutputStream(this, *options)
|
||||
|
||||
inline fun Path.isDirectory(vararg options: LinkOption): Boolean = Files.isDirectory(this, *options)
|
||||
|
||||
inline fun Path.isSymbolicLink(): Boolean = Files.isSymbolicLink(this)
|
||||
|
||||
inline fun Path.readSymbolicLink(): Path = Files.readSymbolicLink(this)
|
||||
|
||||
val Path.name: String
|
||||
get() = fileName?.toString().orEmpty()
|
||||
|
||||
inline fun Path.readBytes(): ByteArray = Files.readAllBytes(this)
|
10
core-1.2/src/main/kotlin/kotlin/text/KotlinText1.2.kt
Normal file
10
core-1.2/src/main/kotlin/kotlin/text/KotlinText1.2.kt
Normal file
@ -0,0 +1,10 @@
|
||||
// Implement the new post-1.2 APIs which are used by core and serialization
|
||||
@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE", "unused")
|
||||
|
||||
package kotlin.text
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
inline fun String.lowercase(): String = (this as java.lang.String).toLowerCase(Locale.ROOT)
|
||||
|
||||
inline fun String.lowercase(locale: Locale): String = (this as java.lang.String).toLowerCase(locale)
|
@ -11,68 +11,51 @@ sourceSets {
|
||||
}
|
||||
|
||||
configurations {
|
||||
resolvableImplementation.extendsFrom implementation
|
||||
|
||||
integrationTestImplementation.extendsFrom testImplementation
|
||||
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
|
||||
|
||||
smokeTestCompile.extendsFrom compile
|
||||
smokeTestRuntimeOnly.extendsFrom runtimeOnly
|
||||
|
||||
testArtifacts.extendsFrom(testRuntimeClasspath)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.opentelemetry:opentelemetry-api:${open_telemetry_version}"
|
||||
compileOnly project(':opentelemetry')
|
||||
|
||||
testImplementation sourceSets.obfuscator.output
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||
|
||||
testImplementation "commons-fileupload:commons-fileupload:$fileupload_version"
|
||||
|
||||
// Guava: Google test library (collections test suite)
|
||||
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
|
||||
// Hamkrest, for fluent, composable matchers
|
||||
testImplementation "com.natpryce:hamkrest:$hamkrest_version"
|
||||
|
||||
// SLF4J: commons-logging bindings for a SLF4J back end
|
||||
implementation "org.slf4j:jcl-over-slf4j:$slf4j_version"
|
||||
implementation "org.slf4j:slf4j-api:$slf4j_version"
|
||||
|
||||
// AssertJ: for fluent assertions for testing
|
||||
testImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||
|
||||
// Guava: Google utilities library.
|
||||
implementation "com.google.guava:guava:$guava_version"
|
||||
|
||||
// For caches rather than guava
|
||||
implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||
|
||||
// RxJava: observable streams of events.
|
||||
implementation "io.reactivex:rxjava:$rxjava_version"
|
||||
|
||||
implementation "org.apache.commons:commons-lang3:$commons_lang3_version"
|
||||
|
||||
// Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
|
||||
implementation "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
|
||||
// Bouncy castle support needed for X509 certificate manipulation
|
||||
implementation "org.bouncycastle:bcprov-jdk18on:${bouncycastle_version}"
|
||||
testImplementation "org.bouncycastle:bcpkix-jdk18on:${bouncycastle_version}"
|
||||
|
||||
// required to use @Type annotation
|
||||
implementation "org.hibernate:hibernate-core:$hibernate_version"
|
||||
|
||||
// FastThreadLocal
|
||||
implementation "io.netty:netty-common:$netty_version"
|
||||
implementation "io.github.classgraph:classgraph:$class_graph_version"
|
||||
|
||||
implementation group: "io.github.classgraph", name: "classgraph", version: class_graph_version
|
||||
|
||||
testImplementation sourceSets.obfuscator.output
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
testImplementation "commons-fileupload:commons-fileupload:$fileupload_version"
|
||||
// Guava: Google test library (collections test suite)
|
||||
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
// Hamkrest, for fluent, composable matchers
|
||||
testImplementation "com.natpryce:hamkrest:$hamkrest_version"
|
||||
// AssertJ: for fluent assertions for testing
|
||||
testImplementation "org.assertj:assertj-core:$assertj_version"
|
||||
testImplementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastle_version"
|
||||
testImplementation "org.ow2.asm:asm:$asm_version"
|
||||
|
||||
// JDK11: required by Quasar at run-time
|
||||
@ -103,10 +86,6 @@ jar {
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
testArtifacts.extendsFrom testRuntimeClasspath
|
||||
}
|
||||
|
||||
processTestResources {
|
||||
inputs.files(jar)
|
||||
into("zip") {
|
||||
|
@ -1,3 +1,5 @@
|
||||
@file:Suppress("MagicNumber")
|
||||
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
@ -34,6 +36,7 @@ import java.nio.ByteBuffer
|
||||
import java.nio.file.CopyOption
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.security.KeyPair
|
||||
import java.security.MessageDigest
|
||||
import java.security.PrivateKey
|
||||
@ -60,6 +63,8 @@ import java.util.Spliterator.SUBSIZED
|
||||
import java.util.Spliterators
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarInputStream
|
||||
import java.util.stream.Collectors
|
||||
import java.util.stream.Collectors.toCollection
|
||||
import java.util.stream.IntStream
|
||||
@ -68,7 +73,6 @@ import java.util.stream.StreamSupport
|
||||
import java.util.zip.Deflater
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlin.io.path.toPath
|
||||
import kotlin.math.roundToLong
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.createInstance
|
||||
@ -132,14 +136,17 @@ fun <T> List<T>.indexOfOrThrow(item: T): Int {
|
||||
/**
|
||||
* Similar to [Iterable.map] except it maps to a [Set] which preserves the iteration order.
|
||||
*/
|
||||
@Suppress("INVISIBLE_MEMBER", "RemoveExplicitTypeArguments") // Because the external verifier uses Kotlin 1.2
|
||||
inline fun <T, R> Iterable<T>.mapToSet(transform: (T) -> R): Set<R> {
|
||||
if (this is Collection) {
|
||||
return if (this is Collection) {
|
||||
when (size) {
|
||||
0 -> return emptySet()
|
||||
1 -> return setOf(transform(first()))
|
||||
else -> mapTo(LinkedHashSet<R>(mapCapacity(size)), transform)
|
||||
}
|
||||
} else {
|
||||
mapTo(LinkedHashSet<R>(), transform)
|
||||
}
|
||||
return mapTo(LinkedHashSet(), transform)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,6 +183,8 @@ fun InputStream.hash(): SecureHash {
|
||||
|
||||
inline fun <reified T : Any> InputStream.readObject(): T = readFully().deserialize()
|
||||
|
||||
fun JarInputStream.entries(): Sequence<JarEntry> = generateSequence(nextJarEntry) { nextJarEntry }
|
||||
|
||||
fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else "${take(maxWidth - 1)}…"
|
||||
|
||||
/**
|
||||
@ -370,17 +379,10 @@ class DeclaredField<T>(clazz: Class<*>, name: String, private val receiver: Any?
|
||||
val name: String = javaField.name
|
||||
|
||||
private fun <RESULT> Field.accessible(action: Field.() -> RESULT): RESULT {
|
||||
@Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9)
|
||||
val accessible = isAccessible
|
||||
isAccessible = true
|
||||
try {
|
||||
return action(this)
|
||||
} finally {
|
||||
isAccessible = accessible
|
||||
}
|
||||
return action(this)
|
||||
}
|
||||
|
||||
@Throws(NoSuchFieldException::class)
|
||||
private fun findField(fieldName: String, clazz: Class<*>?): Field {
|
||||
if (clazz == null) {
|
||||
throw NoSuchFieldException(fieldName)
|
||||
@ -436,7 +438,7 @@ inline val Member.isStatic: Boolean get() = Modifier.isStatic(modifiers)
|
||||
|
||||
inline val Member.isFinal: Boolean get() = Modifier.isFinal(modifiers)
|
||||
|
||||
fun URL.toPath(): Path = toURI().toPath()
|
||||
fun URL.toPath(): Path = Paths.get(toURI())
|
||||
|
||||
val DEFAULT_HTTP_CONNECT_TIMEOUT = 30.seconds.toMillis()
|
||||
val DEFAULT_HTTP_READ_TIMEOUT = 30.seconds.toMillis()
|
||||
|
@ -57,8 +57,8 @@ object JarSignatureCollector {
|
||||
return firstSignerSet
|
||||
}
|
||||
|
||||
private val JarInputStream.fileSignerSets: List<Pair<String, Set<CodeSigner>>> get() =
|
||||
entries.thatAreSignable.shreddedFrom(this).toFileSignerSet().toList()
|
||||
private val JarInputStream.fileSignerSets: List<Pair<String, Set<CodeSigner>>>
|
||||
get() = entries().thatAreSignable.shreddedFrom(this).toFileSignerSet().toList()
|
||||
|
||||
private val Sequence<JarEntry>.thatAreSignable: Sequence<JarEntry> get() = filterNot { isNotSignable(it) }
|
||||
|
||||
@ -85,8 +85,6 @@ object JarSignatureCollector {
|
||||
private fun Set<CodeSigner>.toCertificates(): List<X509Certificate> = map {
|
||||
it.signerCertPath.certificates[0] as X509Certificate
|
||||
}.sortedBy { it.toString() } // Sorted for determinism.
|
||||
|
||||
private val JarInputStream.entries get(): Sequence<JarEntry> = generateSequence(nextJarEntry) { nextJarEntry }
|
||||
}
|
||||
|
||||
class InvalidJarSignersException(msg: String) : Exception(msg)
|
@ -56,7 +56,7 @@ class AttachmentFixups {
|
||||
private fun parseIds(ids: String): Set<AttachmentId> {
|
||||
return ids.splitToSequence(",")
|
||||
.map(String::trim)
|
||||
.filterNot(String::isEmpty)
|
||||
.filter { it.isNotEmpty() }
|
||||
.mapTo(LinkedHashSet(), SecureHash.Companion::create)
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.AttachmentTrustCalculator
|
||||
import net.corda.core.internal.SerializedTransactionState
|
||||
import net.corda.core.internal.TRUSTED_UPLOADERS
|
||||
import net.corda.core.internal.entries
|
||||
import net.corda.core.internal.getRequiredTransaction
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
@ -31,7 +32,6 @@ import net.corda.core.transactions.NotaryChangeLedgerTransaction
|
||||
import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import java.security.PublicKey
|
||||
import java.util.jar.JarInputStream
|
||||
|
||||
/**
|
||||
* Implements [VerificationSupport] in terms of node-based services.
|
||||
@ -135,19 +135,12 @@ interface VerificationService : VerificationSupport {
|
||||
// TODO - add caching if performance is affected.
|
||||
for (attId in allTrusted) {
|
||||
val attch = attachmentStorage.openAttachment(attId)!!
|
||||
if (attch.openAsJAR().use { hasFile(it, "$className.class") }) return attch
|
||||
if (attch.hasFile("$className.class")) return attch
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun hasFile(jarStream: JarInputStream, className: String): Boolean {
|
||||
while (true) {
|
||||
val e = jarStream.nextJarEntry ?: return false
|
||||
if (e.name == className) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun Attachment.hasFile(className: String): Boolean = openAsJAR().use { it.entries().any { entry -> entry.name == className } }
|
||||
|
||||
override fun isAttachmentTrusted(attachment: Attachment): Boolean = attachmentTrustCalculator.calculate(attachment)
|
||||
|
||||
|
@ -39,7 +39,8 @@ interface VerifyingServiceHub : ServiceHub, VerificationService {
|
||||
|
||||
private fun loadContractAttachment(stateRef: StateRef, forContractClassName: String?): Attachment {
|
||||
val stx = getRequiredTransaction(stateRef.txhash)
|
||||
return when (val ctx = stx.coreTransaction) {
|
||||
val ctx = stx.coreTransaction
|
||||
return when (ctx) {
|
||||
is WireTransaction -> {
|
||||
val contractClassName = forContractClassName ?: ctx.outRef<ContractState>(stateRef.index).state.contract
|
||||
ctx.attachments
|
||||
|
@ -75,9 +75,10 @@ open class MappedSchema(schemaFamily: Class<*>,
|
||||
* A super class for all mapped states exported to a schema that ensures the [StateRef] appears on the database row. The
|
||||
* [StateRef] will be set to the correct value by the framework (there's no need to set during mapping generation by the state itself).
|
||||
*/
|
||||
@Suppress("RedundantModalityModifier") // Because the external verifier uses Kotlin 1.2
|
||||
@MappedSuperclass
|
||||
@CordaSerializable
|
||||
class PersistentState(@EmbeddedId override var stateRef: PersistentStateRef? = null) : DirectStatePersistable
|
||||
open class PersistentState(@EmbeddedId override var stateRef: PersistentStateRef? = null) : DirectStatePersistable
|
||||
|
||||
/**
|
||||
* Embedded [StateRef] representation used in state mapping.
|
||||
|
@ -17,6 +17,7 @@ import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.cordapp.targetPlatformVersion
|
||||
import net.corda.core.internal.createInstancesOfClassesImplementing
|
||||
import net.corda.core.internal.createSimpleCache
|
||||
import net.corda.core.internal.entries
|
||||
import net.corda.core.internal.toSynchronised
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.serialization.AMQP_ENVELOPE_CACHE_INITIAL_CAPACITY
|
||||
@ -48,7 +49,6 @@ import java.util.ServiceLoader
|
||||
import java.util.WeakHashMap
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.function.Function
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
import kotlin.collections.set
|
||||
@ -170,13 +170,7 @@ class AttachmentsClassLoader(attachments: List<Attachment>,
|
||||
}
|
||||
|
||||
private fun containsClasses(attachment: Attachment): Boolean {
|
||||
attachment.openAsJAR().use { jar ->
|
||||
while (true) {
|
||||
val entry = jar.nextJarEntry ?: return false
|
||||
if (entry.name.endsWith(".class", ignoreCase = true)) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return attachment.openAsJAR().use { it.entries().any { entry -> entry.name.endsWith(".class", ignoreCase = true) } }
|
||||
}
|
||||
|
||||
// This function attempts to strike a balance between security and usability when it comes to the no-overlap rule.
|
||||
@ -412,7 +406,7 @@ object AttachmentURLStreamHandlerFactory : URLStreamHandlerFactory {
|
||||
|
||||
@Synchronized
|
||||
fun toUrl(attachment: Attachment): URL {
|
||||
val uniqueURL = URL(attachmentScheme, "", -1, attachment.id.toString()+ "?" + uniqueness.getAndIncrement(), AttachmentURLStreamHandler)
|
||||
val uniqueURL = URL(attachmentScheme, "", -1, "${attachment.id}?${uniqueness.getAndIncrement()}", AttachmentURLStreamHandler)
|
||||
loadedAttachments[uniqueURL] = attachment
|
||||
return uniqueURL
|
||||
}
|
||||
@ -429,12 +423,12 @@ object AttachmentURLStreamHandlerFactory : URLStreamHandlerFactory {
|
||||
|
||||
override fun equals(attachmentUrl: URL, otherURL: URL?): Boolean {
|
||||
if (attachmentUrl.protocol != otherURL?.protocol) return false
|
||||
if (attachmentUrl.protocol != attachmentScheme) throw IllegalArgumentException("Cannot handle protocol: ${attachmentUrl.protocol}")
|
||||
require(attachmentUrl.protocol == attachmentScheme) { "Cannot handle protocol: ${attachmentUrl.protocol}" }
|
||||
return attachmentUrl.file == otherURL?.file
|
||||
}
|
||||
|
||||
override fun hashCode(url: URL): Int {
|
||||
if (url.protocol != attachmentScheme) throw IllegalArgumentException("Cannot handle protocol: ${url.protocol}")
|
||||
require(url.protocol == attachmentScheme) { "Cannot handle protocol: ${url.protocol}" }
|
||||
return url.file.hashCode()
|
||||
}
|
||||
}
|
||||
@ -466,7 +460,10 @@ private class AttachmentsHolderImpl : AttachmentsHolder {
|
||||
}
|
||||
|
||||
interface AttachmentsClassLoaderCache {
|
||||
fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function<in AttachmentsClassLoaderKey, out SerializationContext>): SerializationContext
|
||||
fun computeIfAbsent(
|
||||
key: AttachmentsClassLoaderKey,
|
||||
mappingFunction: (AttachmentsClassLoaderKey) -> SerializationContext
|
||||
): SerializationContext
|
||||
}
|
||||
|
||||
class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : SingletonSerializeAsToken(), AttachmentsClassLoaderCache {
|
||||
@ -514,18 +511,23 @@ class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : Singlet
|
||||
}, "AttachmentsClassLoader_cache"
|
||||
)
|
||||
|
||||
override fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function<in AttachmentsClassLoaderKey, out SerializationContext>): SerializationContext {
|
||||
override fun computeIfAbsent(
|
||||
key: AttachmentsClassLoaderKey,
|
||||
mappingFunction: (AttachmentsClassLoaderKey) -> SerializationContext
|
||||
): SerializationContext {
|
||||
purgeExpiryQueue()
|
||||
return cache.get(key, mappingFunction) ?: throw NullPointerException("null returned from cache mapping function")
|
||||
}
|
||||
}
|
||||
|
||||
class AttachmentsClassLoaderSimpleCacheImpl(cacheSize: Int) : AttachmentsClassLoaderCache {
|
||||
|
||||
private val cache: MutableMap<AttachmentsClassLoaderKey, SerializationContext>
|
||||
= createSimpleCache<AttachmentsClassLoaderKey, SerializationContext>(cacheSize).toSynchronised()
|
||||
|
||||
override fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function<in AttachmentsClassLoaderKey, out SerializationContext>): SerializationContext {
|
||||
override fun computeIfAbsent(
|
||||
key: AttachmentsClassLoaderKey,
|
||||
mappingFunction: (AttachmentsClassLoaderKey) -> SerializationContext
|
||||
): SerializationContext {
|
||||
return cache.computeIfAbsent(key, mappingFunction)
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ import java.util.function.Supplier
|
||||
*
|
||||
* [LedgerTransaction]s should never be instantiated directly from client code, but rather via WireTransaction.toLedgerTransaction
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@Suppress("LongParameterList", "RedundantSamConstructor") // Because the external verifier uses Kotlin 1.2
|
||||
class LedgerTransaction
|
||||
private constructor(
|
||||
// DOCSTART 1
|
||||
@ -465,7 +465,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> filterInputs(crossinline predicate: (T) -> Boolean): List<T> {
|
||||
return filterInputs(T::class.java) { predicate(it) }
|
||||
return filterInputs(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -481,7 +481,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> filterReferenceInputs(crossinline predicate: (T) -> Boolean): List<T> {
|
||||
return filterReferenceInputs(T::class.java) { predicate(it) }
|
||||
return filterReferenceInputs(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -497,7 +497,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> filterInRefs(crossinline predicate: (T) -> Boolean): List<StateAndRef<T>> {
|
||||
return filterInRefs(T::class.java) { predicate(it) }
|
||||
return filterInRefs(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -513,7 +513,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> filterReferenceInputRefs(crossinline predicate: (T) -> Boolean): List<StateAndRef<T>> {
|
||||
return filterReferenceInputRefs(T::class.java) { predicate(it) }
|
||||
return filterReferenceInputRefs(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -530,7 +530,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> findInput(crossinline predicate: (T) -> Boolean): T {
|
||||
return findInput(T::class.java) { predicate(it) }
|
||||
return findInput(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -543,11 +543,11 @@ private constructor(
|
||||
* @throws IllegalArgumentException if no item, or multiple items are found matching the requirements.
|
||||
*/
|
||||
fun <T : ContractState> findReference(clazz: Class<T>, predicate: Predicate<T>): T {
|
||||
return referenceInputsOfType(clazz).single(predicate::test)
|
||||
return referenceInputsOfType(clazz).single { predicate.test(it) }
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> findReference(crossinline predicate: (T) -> Boolean): T {
|
||||
return findReference(T::class.java) { predicate(it) }
|
||||
return findReference(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -564,7 +564,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> findInRef(crossinline predicate: (T) -> Boolean): StateAndRef<T> {
|
||||
return findInRef(T::class.java) { predicate(it) }
|
||||
return findInRef(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -581,7 +581,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : ContractState> findReferenceInputRef(crossinline predicate: (T) -> Boolean): StateAndRef<T> {
|
||||
return findReferenceInputRef(T::class.java) { predicate(it) }
|
||||
return findReferenceInputRef(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -616,7 +616,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : CommandData> filterCommands(crossinline predicate: (T) -> Boolean): List<Command<T>> {
|
||||
return filterCommands(T::class.java) { predicate(it) }
|
||||
return filterCommands(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -633,7 +633,7 @@ private constructor(
|
||||
}
|
||||
|
||||
inline fun <reified T : CommandData> findCommand(crossinline predicate: (T) -> Boolean): Command<T> {
|
||||
return findCommand(T::class.java) { predicate(it) }
|
||||
return findCommand(T::class.java, Predicate { predicate(it) })
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -489,7 +489,8 @@ open class TransactionBuilder(
|
||||
}
|
||||
|
||||
if (explicitContractAttachment != null && hashAttachments.singleOrNull() != null) {
|
||||
require(explicitContractAttachment == hashAttachments.single().attachment.id) {
|
||||
@Suppress("USELESS_CAST") // Because the external verifier uses Kotlin 1.2
|
||||
require(explicitContractAttachment == (hashAttachments.single() as ContractAttachment).attachment.id) {
|
||||
"An attachment has been explicitly set for contract $contractClassName in the transaction builder which conflicts with the HashConstraint of a state."
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import rx.Subscription
|
||||
import rx.functions.Action1
|
||||
import rx.subjects.ReplaySubject
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A progress tracker helps surface information about the progress of an operation to a user interface or API of some
|
||||
@ -34,12 +33,12 @@ import java.util.*
|
||||
*/
|
||||
@CordaSerializable
|
||||
class ProgressTracker(vararg inputSteps: Step) {
|
||||
|
||||
private companion object {
|
||||
private val log = contextLogger()
|
||||
}
|
||||
|
||||
private fun interface SerializableAction<T>: Action1<T>, Serializable
|
||||
@FunctionalInterface
|
||||
private interface SerializableAction1<T> : Action1<T>, Serializable
|
||||
|
||||
@CordaSerializable
|
||||
sealed class Change(val progressTracker: ProgressTracker) {
|
||||
@ -61,7 +60,11 @@ class ProgressTracker(vararg inputSteps: Step) {
|
||||
*/
|
||||
@CordaSerializable
|
||||
open class Step(open val label: String) {
|
||||
private fun definitionLocation(): String = Exception().stackTrace.first { it.className != ProgressTracker.Step::class.java.name }.let { "${it.className}:${it.lineNumber}" }
|
||||
private fun definitionLocation(): String {
|
||||
return Exception().stackTrace
|
||||
.first { it.className != Step::class.java.name }
|
||||
.let { "${it.className}:${it.lineNumber}" }
|
||||
}
|
||||
|
||||
// Required when Steps with the same name are defined in multiple places.
|
||||
private val discriminator: String = definitionLocation()
|
||||
@ -149,10 +152,17 @@ class ProgressTracker(vararg inputSteps: Step) {
|
||||
stepIndex = index
|
||||
_changes.onNext(Change.Position(this, steps[index]))
|
||||
recalculateStepsTreeIndex()
|
||||
curChangeSubscription = currentStep.changes.subscribe((SerializableAction<Change> {
|
||||
_changes.onNext(it)
|
||||
if (it is Change.Structural || it is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex()
|
||||
}), (SerializableAction { _changes.onError(it) }))
|
||||
curChangeSubscription = currentStep.changes.subscribe(
|
||||
object : SerializableAction1<Change> {
|
||||
override fun call(c: Change) {
|
||||
_changes.onNext(c)
|
||||
if (c is Change.Structural || c is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex()
|
||||
}
|
||||
},
|
||||
object : SerializableAction1<Throwable> {
|
||||
override fun call(t: Throwable) = _changes.onError(t)
|
||||
}
|
||||
)
|
||||
|
||||
if (currentStep == DONE) {
|
||||
_changes.onCompleted()
|
||||
@ -182,9 +192,7 @@ class ProgressTracker(vararg inputSteps: Step) {
|
||||
* The zero-based index of the current step in the [steps] array (i.e. with UNSTARTED and DONE)
|
||||
*/
|
||||
var stepIndex: Int = 0
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
/**
|
||||
* The zero-bases index of the current step in a [allStepsLabels] list
|
||||
@ -206,18 +214,25 @@ class ProgressTracker(vararg inputSteps: Step) {
|
||||
|
||||
fun getChildProgressTracker(step: Step): ProgressTracker? = childProgressTrackers[step]?.tracker
|
||||
|
||||
fun setChildProgressTracker(step: ProgressTracker.Step, childProgressTracker: ProgressTracker) {
|
||||
val subscription = childProgressTracker.changes.subscribe((SerializableAction<Change>{
|
||||
_changes.onNext(it)
|
||||
if (it is Change.Structural || it is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex()
|
||||
}), (SerializableAction { _changes.onError(it) }))
|
||||
fun setChildProgressTracker(step: Step, childProgressTracker: ProgressTracker) {
|
||||
val subscription = childProgressTracker.changes.subscribe(
|
||||
object : SerializableAction1<Change> {
|
||||
override fun call(c: Change) {
|
||||
_changes.onNext(c)
|
||||
if (c is Change.Structural || c is Change.Rendering) rebuildStepsTree() else recalculateStepsTreeIndex()
|
||||
}
|
||||
},
|
||||
object : SerializableAction1<Throwable> {
|
||||
override fun call(t: Throwable) = _changes.onError(t)
|
||||
}
|
||||
)
|
||||
childProgressTrackers[step] = Child(childProgressTracker, subscription)
|
||||
childProgressTracker.parent = this
|
||||
_changes.onNext(Change.Structural(this, step))
|
||||
rebuildStepsTree()
|
||||
}
|
||||
|
||||
private fun removeChildProgressTracker(step: ProgressTracker.Step) {
|
||||
private fun removeChildProgressTracker(step: Step) {
|
||||
childProgressTrackers.remove(step)?.let {
|
||||
it.tracker.parent = null
|
||||
it.subscription?.unsubscribe()
|
||||
|
@ -1,4 +1,3 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
|
||||
description 'NetworkParameters signing tool'
|
||||
@ -24,7 +23,7 @@ jar {
|
||||
exclude "META-INF/*.DSA"
|
||||
exclude "META-INF/*.RSA"
|
||||
}
|
||||
baseName = "netparams"
|
||||
archiveBaseName = "netparams"
|
||||
manifest {
|
||||
attributes(
|
||||
'Main-Class': 'net.corda.netparams.NetParamsKt'
|
||||
|
@ -1,4 +1,3 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
|
||||
description 'NodeInfo signing tool'
|
||||
@ -23,7 +22,7 @@ jar {
|
||||
exclude "META-INF/*.DSA"
|
||||
exclude "META-INF/*.RSA"
|
||||
}
|
||||
baseName = "nodeinfo"
|
||||
archiveBaseName = "nodeinfo"
|
||||
manifest {
|
||||
attributes(
|
||||
'Main-Class': 'net.corda.nodeinfo.NodeInfoKt'
|
||||
|
@ -11,6 +11,9 @@ dependencies {
|
||||
implementation project(':common-logging')
|
||||
implementation project(":common-validation")
|
||||
|
||||
implementation "io.opentelemetry:opentelemetry-api:$open_telemetry_version"
|
||||
compileOnly project(':opentelemetry')
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
|
||||
// TODO: remove the forced update of commons-collections and beanutils when artemis updates them
|
||||
@ -90,7 +93,7 @@ configurations {
|
||||
testArtifacts.extendsFrom testRuntimeOnlyClasspath
|
||||
}
|
||||
|
||||
task testJar(type: Jar) {
|
||||
tasks.register('testJar', Jar) {
|
||||
classifier "tests"
|
||||
from sourceSets.test.output
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.corda.core.internal.telemetry
|
||||
package net.corda.nodeapi.internal.telemetry
|
||||
|
||||
import co.paralleluniverse.fibers.instrument.DontInstrument
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry
|
||||
@ -12,14 +12,23 @@ import io.opentelemetry.api.trace.StatusCode
|
||||
import io.opentelemetry.api.trace.Tracer
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.context.Scope
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import net.corda.opentelemetrydriver.OpenTelemetryDriver
|
||||
import io.opentelemetry.context.propagation.TextMapGetter
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.internal.telemetry.EndSpanEvent
|
||||
import net.corda.core.internal.telemetry.EndSpanForFlowEvent
|
||||
import net.corda.core.internal.telemetry.RecordExceptionEvent
|
||||
import net.corda.core.internal.telemetry.SetStatusEvent
|
||||
import net.corda.core.internal.telemetry.ShutdownTelemetryEvent
|
||||
import net.corda.core.internal.telemetry.StartSpanEvent
|
||||
import net.corda.core.internal.telemetry.StartSpanForFlowEvent
|
||||
import net.corda.core.internal.telemetry.TelemetryComponent
|
||||
import net.corda.core.internal.telemetry.TelemetryDataItem
|
||||
import net.corda.core.internal.telemetry.TelemetryEvent
|
||||
import net.corda.core.internal.telemetry.TelemetryStatusCode
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.opentelemetrydriver.OpenTelemetryDriver
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
|
||||
@CordaSerializable
|
||||
@ -54,12 +63,11 @@ class TracerSetup(serviceName: String) {
|
||||
}
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
class OpenTelemetryComponent(val serviceName: String, val spanStartEndEventsEnabled: Boolean, val copyBaggageToTags: Boolean) : TelemetryComponent {
|
||||
class OpenTelemetryComponent(serviceName: String, val spanStartEndEventsEnabled: Boolean, val copyBaggageToTags: Boolean) : TelemetryComponent {
|
||||
val tracerSetup = TracerSetup(serviceName)
|
||||
val tracer: Tracer = tracerSetup.getTracer()
|
||||
|
||||
companion object {
|
||||
private val log: Logger = LoggerFactory.getLogger(OpenTelemetryComponent::class.java)
|
||||
const val OPENTELEMETRY_COMPONENT_NAME = "OpenTelemetry"
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
// Java Persistence API support: create no-arg constructor
|
||||
// see: http://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell
|
||||
apply plugin: 'org.jetbrains.kotlin.plugin.jpa'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
||||
@ -73,7 +72,7 @@ jib.container {
|
||||
processResources {
|
||||
from file("$rootDir/config/dev/log4j2.xml")
|
||||
from file("$rootDir/config/dev/jolokia-access.xml")
|
||||
from(tasks.findByPath(":verifier:shadowJar")) {
|
||||
from(tasks.getByPath(":verifier:shadowJar")) {
|
||||
into("net/corda/node/verification")
|
||||
rename { "external-verifier.jar" }
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import net.corda.core.contracts.CommandData
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.contracts.TransactionVerificationException.ContractRejection
|
||||
import net.corda.core.contracts.TypeOnlyCommandData
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FinalityFlow
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -16,6 +17,7 @@ import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.NotaryChangeFlow
|
||||
import net.corda.core.flows.ReceiveFinalityFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.flows.UnexpectedFlowEndException
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
@ -32,7 +34,6 @@ import net.corda.finance.DOLLARS
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import net.corda.finance.flows.CashIssueFlow
|
||||
import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.node.verification.ExternalVerificationTest.FailExternallyContract.State
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.BOC_NAME
|
||||
@ -89,6 +90,30 @@ class ExternalVerificationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `external verifier is unable to verify contracts which use new Kotlin APIs`() {
|
||||
check(!IntArray::maxOrNull.isInline)
|
||||
|
||||
internalDriver(
|
||||
systemProperties = mapOf("net.corda.node.verification.external" to "true"),
|
||||
cordappsForAllNodes = listOf(cordappWithPackages("net.corda.node.verification"))
|
||||
) {
|
||||
val (alice, bob) = listOf(
|
||||
startNode(NodeParameters(providedName = ALICE_NAME)),
|
||||
startNode(NodeParameters(providedName = BOB_NAME)),
|
||||
).transpose().getOrThrow()
|
||||
|
||||
assertThatExceptionOfType(UnexpectedFlowEndException::class.java).isThrownBy {
|
||||
alice.rpc.startFlow(::NewKotlinApiFlow, bob.nodeInfo).returnValue.getOrThrow()
|
||||
}
|
||||
|
||||
assertThat(bob.externalVerifierLogs()).contains("""
|
||||
java.lang.NoSuchMethodError: 'java.lang.Integer kotlin.collections.ArraysKt.maxOrNull(int[])'
|
||||
at net.corda.node.verification.ExternalVerificationTest${'$'}NewKotlinApiContract.verify(ExternalVerificationTest.kt:
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `regular transactions can fail verification in external verifier`() {
|
||||
internalDriver(
|
||||
@ -104,7 +129,7 @@ class ExternalVerificationTest {
|
||||
// Create a transaction from Alice to Bob, where Charlie is specified as the contract verification trigger
|
||||
val firstState = alice.rpc.startFlow(::FailExternallyFlow, null, charlie.nodeInfo, bob.nodeInfo).returnValue.getOrThrow()
|
||||
// When the transaction chain tries to moves onto Charlie, it will trigger the failure
|
||||
assertThatExceptionOfType(TransactionVerificationException.ContractRejection::class.java)
|
||||
assertThatExceptionOfType(ContractRejection::class.java)
|
||||
.isThrownBy { bob.rpc.startFlow(::FailExternallyFlow, firstState, charlie.nodeInfo, charlie.nodeInfo).returnValue.getOrThrow() }
|
||||
.withMessageContaining("Fail in external verifier: ${firstState.ref.txhash}")
|
||||
|
||||
@ -149,6 +174,7 @@ class ExternalVerificationTest {
|
||||
return verifierLogs[0].readText()
|
||||
}
|
||||
|
||||
|
||||
class FailExternallyContract : Contract {
|
||||
override fun verify(tx: LedgerTransaction) {
|
||||
val command = tx.commandsOfType<Command>().single()
|
||||
@ -165,40 +191,46 @@ class ExternalVerificationTest {
|
||||
}
|
||||
}
|
||||
|
||||
data class State(val party: Party) : ContractState {
|
||||
override val participants: List<AbstractParty> get() = listOf(party)
|
||||
}
|
||||
|
||||
data class State(override val party: Party) : TestState
|
||||
data class Command(val failForParty: Party) : CommandData
|
||||
}
|
||||
|
||||
|
||||
@StartableByRPC
|
||||
@InitiatingFlow
|
||||
class FailExternallyFlow(private val inputState: StateAndRef<State>?,
|
||||
class FailExternallyFlow(inputState: StateAndRef<FailExternallyContract.State>?,
|
||||
private val failForParty: NodeInfo,
|
||||
private val recipient: NodeInfo) : FlowLogic<StateAndRef<State>>() {
|
||||
@Suspendable
|
||||
override fun call(): StateAndRef<State> {
|
||||
val myParty = serviceHub.myInfo.legalIdentities[0]
|
||||
val txBuilder = TransactionBuilder(serviceHub.networkMapCache.notaryIdentities[0])
|
||||
inputState?.let(txBuilder::addInputState)
|
||||
txBuilder.addOutputState(State(myParty), FailExternallyContract::class.java.name)
|
||||
txBuilder.addCommand(FailExternallyContract.Command(failForParty.legalIdentities[0]), myParty.owningKey)
|
||||
val initialTx = serviceHub.signInitialTransaction(txBuilder)
|
||||
val sessions = arrayListOf(initiateFlow(recipient.legalIdentities[0]))
|
||||
inputState?.let { sessions += initiateFlow(it.state.data.party) }
|
||||
val notarisedTx = subFlow(FinalityFlow(initialTx, sessions))
|
||||
return notarisedTx.toLedgerTransaction(serviceHub).outRef(0)
|
||||
}
|
||||
recipient: NodeInfo) : TestFlow<FailExternallyContract.State>(inputState, recipient) {
|
||||
override fun newOutput() = FailExternallyContract.State(serviceHub.myInfo.legalIdentities[0])
|
||||
override fun newCommand() = FailExternallyContract.Command(failForParty.legalIdentities[0])
|
||||
|
||||
@Suppress("unused")
|
||||
@InitiatedBy(FailExternallyFlow::class)
|
||||
class ReceiverFlow(otherSide: FlowSession) : TestReceiverFlow(otherSide)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@InitiatedBy(FailExternallyFlow::class)
|
||||
class ReceiverFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
subFlow(ReceiveFinalityFlow(otherSide))
|
||||
|
||||
class NewKotlinApiContract : Contract {
|
||||
override fun verify(tx: LedgerTransaction) {
|
||||
check(tx.commandsOfType<Command>().isNotEmpty())
|
||||
// New post-1.2 API which is non-inlined
|
||||
intArrayOf().maxOrNull()
|
||||
}
|
||||
|
||||
data class State(override val party: Party) : TestState
|
||||
object Command : TypeOnlyCommandData()
|
||||
}
|
||||
|
||||
|
||||
@StartableByRPC
|
||||
@InitiatingFlow
|
||||
class NewKotlinApiFlow(recipient: NodeInfo) : TestFlow<NewKotlinApiContract.State>(null, recipient) {
|
||||
override fun newOutput() = NewKotlinApiContract.State(serviceHub.myInfo.legalIdentities[0])
|
||||
override fun newCommand() = NewKotlinApiContract.Command
|
||||
|
||||
@Suppress("unused")
|
||||
@InitiatedBy(NewKotlinApiFlow::class)
|
||||
class ReceiverFlow(otherSide: FlowSession) : TestReceiverFlow(otherSide)
|
||||
}
|
||||
|
||||
|
||||
@ -216,4 +248,39 @@ class ExternalVerificationTest {
|
||||
return notaryChangeTx!!.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class TestFlow<T : TestState>(
|
||||
private val inputState: StateAndRef<T>?,
|
||||
private val recipient: NodeInfo
|
||||
) : FlowLogic<StateAndRef<T>>() {
|
||||
@Suspendable
|
||||
override fun call(): StateAndRef<T> {
|
||||
val myParty = serviceHub.myInfo.legalIdentities[0]
|
||||
val txBuilder = TransactionBuilder(serviceHub.networkMapCache.notaryIdentities[0])
|
||||
inputState?.let(txBuilder::addInputState)
|
||||
txBuilder.addOutputState(newOutput())
|
||||
txBuilder.addCommand(newCommand(), myParty.owningKey)
|
||||
val initialTx = serviceHub.signInitialTransaction(txBuilder)
|
||||
val sessions = arrayListOf(initiateFlow(recipient.legalIdentities[0]))
|
||||
inputState?.let { sessions += initiateFlow(it.state.data.party) }
|
||||
val notarisedTx = subFlow(FinalityFlow(initialTx, sessions))
|
||||
return notarisedTx.toLedgerTransaction(serviceHub).outRef(0)
|
||||
}
|
||||
|
||||
protected abstract fun newOutput(): T
|
||||
protected abstract fun newCommand(): CommandData
|
||||
}
|
||||
|
||||
abstract class TestReceiverFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
subFlow(ReceiveFinalityFlow(otherSide))
|
||||
}
|
||||
}
|
||||
|
||||
interface TestState : ContractState {
|
||||
val party: Party
|
||||
override val participants: List<AbstractParty> get() = listOf(party)
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ import net.corda.core.internal.cordapp.CordappProviderInternal
|
||||
import net.corda.core.internal.messaging.AttachmentTrustInfoRPCOps
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
import net.corda.core.internal.rootMessage
|
||||
import net.corda.core.internal.telemetry.OpenTelemetryComponent
|
||||
import net.corda.core.internal.telemetry.SimpleLogTelemetryComponent
|
||||
import net.corda.core.internal.telemetry.TelemetryComponent
|
||||
import net.corda.core.internal.telemetry.TelemetryServiceImpl
|
||||
@ -167,6 +166,7 @@ import net.corda.nodeapi.internal.persistence.RestrictedEntityManager
|
||||
import net.corda.nodeapi.internal.persistence.SchemaMigration
|
||||
import net.corda.nodeapi.internal.persistence.contextDatabase
|
||||
import net.corda.nodeapi.internal.persistence.withoutDatabaseAccess
|
||||
import net.corda.nodeapi.internal.telemetry.OpenTelemetryComponent
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||
import org.jolokia.jvmagent.JolokiaServer
|
||||
import org.jolokia.jvmagent.JolokiaServerConfig
|
||||
|
@ -276,7 +276,7 @@ open class NodeStartup : NodeStartupLogging {
|
||||
logger.info("Platform Version: ${versionInfo.platformVersion}")
|
||||
logger.info("Revision: ${versionInfo.revision}")
|
||||
val info = ManagementFactory.getRuntimeMXBean()
|
||||
logger.info("PID: ${info.name.split("@").firstOrNull()}") // TODO Java 9 has better support for this
|
||||
logger.info("PID: ${ProcessHandle.current().pid()}")
|
||||
logger.info("Main class: ${NodeConfiguration::class.java.location.toURI().path}")
|
||||
logger.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}")
|
||||
// JDK 11 (bootclasspath no longer supported from JDK 9)
|
||||
|
@ -1,4 +1,5 @@
|
||||
apply plugin: 'java'
|
||||
import net.corda.plugins.Cordform
|
||||
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||
@ -54,10 +55,9 @@ dependencies {
|
||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||
}
|
||||
|
||||
def nodeTask = tasks.getByPath(':node:capsule:assemble')
|
||||
def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble')
|
||||
configurations.cordaCordapp.canBeResolved = true
|
||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) {
|
||||
tasks.register('deployNodes', Cordform) {
|
||||
dependsOn('jar', ':node:capsule:assemble', ':testing:testserver:testcapsule::assemble')
|
||||
nodeDefaults {
|
||||
cordapp project(':finance:workflows')
|
||||
cordapp project(':finance:contracts')
|
||||
@ -65,7 +65,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask,
|
||||
}
|
||||
node {
|
||||
name "O=Notary Node,L=Zurich,C=CH"
|
||||
notary = [validating: true,
|
||||
notary = [validating : true,
|
||||
serviceLegalName: "O=Notary Service,L=Zurich,C=CH"
|
||||
]
|
||||
p2pPort 10002
|
||||
@ -113,9 +113,9 @@ idea {
|
||||
}
|
||||
}
|
||||
|
||||
task runRPCCashIssue(type: JavaExec) {
|
||||
tasks.register('runRPCCashIssue', JavaExec) {
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
main = 'net.corda.bank.IssueCash'
|
||||
mainClass = 'net.corda.bank.IssueCash'
|
||||
|
||||
jvmArgs test_add_opens
|
||||
jvmArgs test_add_exports
|
||||
@ -131,9 +131,9 @@ task runRPCCashIssue(type: JavaExec) {
|
||||
jvmArgs test_add_exports
|
||||
}
|
||||
|
||||
task runWebCashIssue(type: JavaExec) {
|
||||
tasks.register('runWebCashIssue', JavaExec) {
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
main = 'net.corda.bank.IssueCash'
|
||||
mainClass = 'net.corda.bank.IssueCash'
|
||||
|
||||
jvmArgs test_add_opens
|
||||
jvmArgs test_add_exports
|
||||
|
@ -1,10 +1,15 @@
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'net.corda.plugins.cordapp'
|
||||
|
||||
def javaHome = System.getProperty('java.home')
|
||||
def shrinkJar = file("$buildDir/libs/${project.name}-${project.version}-tiny.jar")
|
||||
|
||||
import java.security.NoSuchAlgorithmException
|
||||
|
||||
import net.corda.plugins.SignJar
|
||||
import proguard.gradle.ProGuardTask
|
||||
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
|
||||
static String sha256(File jarFile) throws FileNotFoundException, NoSuchAlgorithmException {
|
||||
InputStream input = new FileInputStream(jarFile)
|
||||
@ -58,10 +63,10 @@ dependencies {
|
||||
implementation "com.opengamma.strata:strata-market:$strata_version"
|
||||
}
|
||||
|
||||
def cordappDependencies = file("${sourceSets['main'].output.resourcesDir}/META-INF/Cordapp-Dependencies")
|
||||
configurations.cordapp.canBeResolved = true
|
||||
task generateDependencies {
|
||||
tasks.register('generateDependencies') {
|
||||
dependsOn project(':finance:contracts').tasks.jar
|
||||
def cordappDependencies = file("${sourceSets.main.output.resourcesDir}/META-INF/Cordapp-Dependencies")
|
||||
inputs.files(configurations.cordapp)
|
||||
outputs.files(cordappDependencies)
|
||||
doLast {
|
||||
@ -75,11 +80,10 @@ task generateDependencies {
|
||||
processResources.finalizedBy generateDependencies
|
||||
|
||||
jar {
|
||||
classifier = 'fat'
|
||||
archiveClassifier = 'fat'
|
||||
}
|
||||
|
||||
import proguard.gradle.ProGuardTask
|
||||
task shrink(type: ProGuardTask) {
|
||||
tasks.register('shrink', ProGuardTask) {
|
||||
injars jar
|
||||
outjars shrinkJar
|
||||
|
||||
@ -103,18 +107,18 @@ task shrink(type: ProGuardTask) {
|
||||
verbose
|
||||
|
||||
// These are our CorDapp classes, so don't change these.
|
||||
keep 'class net.corda.vega.** { *; }', includedescriptorclasses:true
|
||||
keep 'class net.corda.vega.** { *; }', includedescriptorclasses: true
|
||||
|
||||
// Until CorDapps are isolated from each other, we need to ensure that the
|
||||
// versions of the classes that this CorDapp needs are still usable by other
|
||||
// CorDapps. Unfortunately, this means that we cannot shrink them as much as
|
||||
// we'd like to.
|
||||
keepclassmembers 'class com.opengamma.strata.** { *; }', includedescriptorclasses:true
|
||||
keepclassmembers 'class com.google.** { *; }', includedescriptorclasses:true
|
||||
keepclassmembers 'class org.joda.** { *; }', includedescriptorclasses:true
|
||||
keepclassmembers 'class com.opengamma.strata.** { *; }', includedescriptorclasses: true
|
||||
keepclassmembers 'class com.google.** { *; }', includedescriptorclasses: true
|
||||
keepclassmembers 'class org.joda.** { *; }', includedescriptorclasses: true
|
||||
}
|
||||
|
||||
task sign(type: net.corda.plugins.SignJar) {
|
||||
tasks.register('sign', SignJar) {
|
||||
inputJars shrink
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||
apply plugin: 'net.corda.plugins.cordapp'
|
||||
|
||||
|
5
serialization-1.2/README.md
Normal file
5
serialization-1.2/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
This is a Kotlin 1.2 version of the `serialization` module, which is consumed by the `verifier` module, for verifying contracts written in
|
||||
Kotlin 1.2. This is just a "shell" module which uses the existing the code in `serialization` and compiles it with the 1.2 compiler.
|
||||
|
||||
To allow `serialization` to benefit from new APIs introduced since 1.2, those APIs much be copied into the `core-1.2` module with the same
|
||||
`kotlin` package.
|
35
serialization-1.2/build.gradle
Normal file
35
serialization-1.2/build.gradle
Normal file
@ -0,0 +1,35 @@
|
||||
apply plugin: "corda.kotlin-1.2"
|
||||
apply plugin: "corda.common-publishing"
|
||||
|
||||
description 'Corda serialization built with Kotlin 1.2'
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDir("../serialization/src/main/java")
|
||||
kotlin.srcDir("../serialization/src/main/kotlin")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":core-1.2")
|
||||
// Use the same dependencies as serialization (minus Kotlin and core)
|
||||
implementation(project(path: ":serialization", configuration: "resolvableImplementation")) {
|
||||
exclude(module: "core")
|
||||
exclude(group: "org.jetbrains.kotlin")
|
||||
}
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_1_2_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'corda-serialization-1.2'
|
||||
}
|
||||
|
||||
// TODO Don't publish publicly as it's only needed by the `verifier` module which consumes this into a fat jar.
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
artifactId 'corda-serialization-1.2'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
@ -3,28 +3,25 @@ apply plugin: 'corda.common-publishing'
|
||||
|
||||
description 'Corda serialization'
|
||||
|
||||
configurations {
|
||||
resolvableImplementation.extendsFrom implementation
|
||||
|
||||
testArtifacts.extendsFrom testRuntimeClasspath
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":core")
|
||||
|
||||
implementation "io.reactivex:rxjava:$rxjava_version"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
|
||||
implementation "org.apache.activemq:artemis-commons:${artemis_version}"
|
||||
|
||||
implementation "org.ow2.asm:asm:$asm_version"
|
||||
|
||||
implementation "com.google.guava:guava:$guava_version"
|
||||
|
||||
// For AMQP serialisation.
|
||||
implementation "org.apache.qpid:proton-j:$protonj_version"
|
||||
|
||||
// ClassGraph: classpath scanning
|
||||
implementation "io.github.classgraph:classgraph:$class_graph_version"
|
||||
|
||||
// Pure-Java Snappy compression
|
||||
implementation "org.iq80.snappy:snappy:$snappy_version"
|
||||
|
||||
// For caches rather than guava
|
||||
implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||
|
||||
@ -43,16 +40,12 @@ dependencies {
|
||||
testImplementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
|
||||
}
|
||||
|
||||
configurations {
|
||||
testArtifacts.extendsFrom testRuntimeClasspath
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc).configureEach {
|
||||
// We have no public or protected Java classes to document.
|
||||
enabled = false
|
||||
}
|
||||
|
||||
task testJar(type: Jar) {
|
||||
tasks.register('testJar', Jar) {
|
||||
archiveClassifier = 'tests'
|
||||
from sourceSets.test.output
|
||||
}
|
||||
|
@ -21,14 +21,14 @@ import java.security.PublicKey
|
||||
typealias SerializedNetworkParameters = SerializedBytes<NetworkParameters>
|
||||
|
||||
@CordaSerializable
|
||||
sealed interface ExternalVerifierInbound {
|
||||
sealed class ExternalVerifierInbound {
|
||||
data class Initialisation(
|
||||
val customSerializerClassNames: Set<String>,
|
||||
val serializationWhitelistClassNames: Set<String>,
|
||||
val customSerializationSchemeClassName: String?,
|
||||
val serializedCurrentNetworkParameters: SerializedNetworkParameters
|
||||
) : ExternalVerifierInbound {
|
||||
val currentNetworkParameters: NetworkParameters by lazy(serializedCurrentNetworkParameters::deserialize)
|
||||
) : ExternalVerifierInbound() {
|
||||
val currentNetworkParameters: NetworkParameters by lazy { serializedCurrentNetworkParameters.deserialize() }
|
||||
|
||||
override fun toString(): String {
|
||||
return "Initialisation(" +
|
||||
@ -43,31 +43,31 @@ sealed interface ExternalVerifierInbound {
|
||||
val stx: SignedTransaction,
|
||||
val stxInputsAndReferences: Map<StateRef, SerializedTransactionState>,
|
||||
val checkSufficientSignatures: Boolean
|
||||
) : ExternalVerifierInbound
|
||||
) : ExternalVerifierInbound()
|
||||
|
||||
data class PartiesResult(val parties: List<Party?>) : ExternalVerifierInbound
|
||||
data class AttachmentResult(val attachment: AttachmentWithTrust?) : ExternalVerifierInbound
|
||||
data class AttachmentsResult(val attachments: List<AttachmentWithTrust?>) : ExternalVerifierInbound
|
||||
data class NetworkParametersResult(val networkParameters: NetworkParameters?) : ExternalVerifierInbound
|
||||
data class TrustedClassAttachmentResult(val id: SecureHash?) : ExternalVerifierInbound
|
||||
data class PartiesResult(val parties: List<Party?>) : ExternalVerifierInbound()
|
||||
data class AttachmentResult(val attachment: AttachmentWithTrust?) : ExternalVerifierInbound()
|
||||
data class AttachmentsResult(val attachments: List<AttachmentWithTrust?>) : ExternalVerifierInbound()
|
||||
data class NetworkParametersResult(val networkParameters: NetworkParameters?) : ExternalVerifierInbound()
|
||||
data class TrustedClassAttachmentResult(val id: SecureHash?) : ExternalVerifierInbound()
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class AttachmentWithTrust(val attachment: Attachment, val isTrusted: Boolean)
|
||||
|
||||
@CordaSerializable
|
||||
sealed interface ExternalVerifierOutbound {
|
||||
sealed interface VerifierRequest : ExternalVerifierOutbound {
|
||||
data class GetParties(val keys: Set<PublicKey>) : VerifierRequest {
|
||||
sealed class ExternalVerifierOutbound {
|
||||
sealed class VerifierRequest : ExternalVerifierOutbound() {
|
||||
data class GetParties(val keys: Set<PublicKey>) : VerifierRequest() {
|
||||
override fun toString(): String = "GetParty(keys=${keys.map { it.toStringShort() }}})"
|
||||
}
|
||||
data class GetAttachment(val id: SecureHash) : VerifierRequest
|
||||
data class GetAttachments(val ids: Set<SecureHash>) : VerifierRequest
|
||||
data class GetNetworkParameters(val id: SecureHash) : VerifierRequest
|
||||
data class GetTrustedClassAttachment(val className: String) : VerifierRequest
|
||||
data class GetAttachment(val id: SecureHash) : VerifierRequest()
|
||||
data class GetAttachments(val ids: Set<SecureHash>) : VerifierRequest()
|
||||
data class GetNetworkParameters(val id: SecureHash) : VerifierRequest()
|
||||
data class GetTrustedClassAttachment(val className: String) : VerifierRequest()
|
||||
}
|
||||
|
||||
data class VerificationResult(val result: Try<Unit>) : ExternalVerifierOutbound
|
||||
data class VerificationResult(val result: Try<Unit>) : ExternalVerifierOutbound()
|
||||
}
|
||||
|
||||
fun DataOutputStream.writeCordaSerializable(payload: Any) {
|
||||
|
@ -42,6 +42,7 @@ include 'confidential-identities'
|
||||
include 'finance:contracts'
|
||||
include 'finance:workflows'
|
||||
include 'core'
|
||||
include 'core-1.2'
|
||||
include 'core-tests'
|
||||
include 'docs'
|
||||
include 'node-api'
|
||||
@ -103,6 +104,7 @@ include 'samples:cordapp-configuration:workflows'
|
||||
include 'samples:network-verifier:contracts'
|
||||
include 'samples:network-verifier:workflows'
|
||||
include 'serialization'
|
||||
include 'serialization-1.2'
|
||||
include 'serialization-tests'
|
||||
include 'testing:cordapps:dbfailure:dbfcontracts'
|
||||
include 'testing:cordapps:dbfailure:dbfworkflows'
|
||||
|
@ -1,4 +1,3 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
|
||||
dependencies {
|
||||
|
@ -1,3 +1,4 @@
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'net.corda.plugins.api-scanner'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
||||
description 'Corda node web server'
|
||||
@ -78,7 +77,7 @@ dependencies {
|
||||
integrationTestImplementation project(':node-driver')
|
||||
}
|
||||
|
||||
task integrationTest(type: Test) {
|
||||
tasks.register('integrationTest', Test) {
|
||||
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'corda.common-publishing'
|
||||
|
||||
|
@ -27,7 +27,6 @@ ext {
|
||||
pkg_macosxKeyUserName = 'R3CEV'
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'application'
|
||||
|
||||
@ -156,7 +155,8 @@ distributions {
|
||||
* Bundles the application using JavaPackager,
|
||||
* using the ZIP distribution as source.
|
||||
*/
|
||||
task javapackage(dependsOn: distZip) {
|
||||
tasks.register('javapackage') {
|
||||
dependsOn distZip
|
||||
|
||||
doLast {
|
||||
delete([pkg_source, pkg_outDir])
|
||||
@ -190,15 +190,14 @@ task javapackage(dependsOn: distZip) {
|
||||
include '**/*.manifest'
|
||||
}
|
||||
filter { line ->
|
||||
line.replaceAll('@pkg_version@', pkg_version)
|
||||
.replaceAll('@signingKeyUserName@', pkg_macosxKeyUserName)
|
||||
line.replaceAll('@pkg_version@', pkg_version).replaceAll('@signingKeyUserName@', pkg_macosxKeyUserName)
|
||||
}
|
||||
into "$pkg_source/package"
|
||||
}
|
||||
|
||||
ant.taskdef(
|
||||
resource: 'com/sun/javafx/tools/ant/antlib.xml',
|
||||
classpath: "$pkg_source:$java_home/../lib/ant-javafx.jar"
|
||||
resource: 'com/sun/javafx/tools/ant/antlib.xml',
|
||||
classpath: "$pkg_source:$java_home/../lib/ant-javafx.jar"
|
||||
)
|
||||
|
||||
ant.deploy(nativeBundles: packageType, outdir: pkg_outDir, outfile: 'DemoBench', verbose: 'true') {
|
||||
|
@ -21,7 +21,6 @@ ext {
|
||||
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'application'
|
||||
// We need to set mainClassName before applying the shadow plugin.
|
||||
mainClassName = 'net.corda.networkbuilder.Main'
|
||||
|
6
verifier/README.md
Normal file
6
verifier/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
This is the external verifier process, which the node kicks off when it needs to verify transactions which itself can't. This will be mainly
|
||||
due to differences in the Kotlin version used in the transaction contract compared to the Kotlin version used by the node.
|
||||
|
||||
This module is built with Kotlin 1.2 and so is only able to verify transactions which have contracts compiled with Kotlin 1.2. It relies on
|
||||
specially compiled versions of `core` and `serialization` also compiled with Kotlin 1.2 (`core-1.2` and `serialization-1.2` respectively)
|
||||
to ensure compatibility.
|
@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.jvm"
|
||||
id "corda.kotlin-1.2"
|
||||
id "application"
|
||||
id "com.github.johnrengelman.shadow"
|
||||
}
|
||||
@ -9,12 +9,12 @@ application {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":core")
|
||||
implementation project(":serialization")
|
||||
implementation project(":core-1.2")
|
||||
implementation project(":serialization-1.2")
|
||||
implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||
implementation "org.slf4j:jul-to-slf4j:$slf4j_version"
|
||||
|
||||
runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
|
||||
runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
|
@ -135,7 +135,7 @@ class ExternalVerifier(
|
||||
|
||||
private fun verifyTransaction(request: VerificationRequest) {
|
||||
val verificationContext = ExternalVerificationContext(appClassLoader, attachmentsClassLoaderCache, this, request.stxInputsAndReferences)
|
||||
val result = try {
|
||||
val result: Try<Unit> = try {
|
||||
request.stx.verifyInternal(verificationContext, request.checkSufficientSignatures)
|
||||
log.info("${request.stx} verified")
|
||||
Try.Success(Unit)
|
||||
@ -213,7 +213,7 @@ class ExternalVerifier(
|
||||
override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
|
||||
|
||||
companion object {
|
||||
inline fun <reified T> Set<String>?.load(classLoader: ClassLoader?): Set<T> {
|
||||
inline fun <reified T : Any> Set<String>?.load(classLoader: ClassLoader?): Set<T> {
|
||||
return this?.mapToSet { loadClassOfType<T>(it, classLoader = classLoader).kotlin.objectOrNewInstance() } ?: emptySet()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user