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-jdk15on:$bouncycastle_version" deterministicLibraries "org.bouncycastle:bcpkix-jdk15on:$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/internal/utilities/PrivateInterner*.class' exclude 'net/corda/core/internal/ContractStateClassCache*.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 ; }' } 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 ; }' } 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 } } }