diff --git a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt b/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt index 96591c7da3..c36eade065 100644 --- a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt +++ b/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt @@ -352,6 +352,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla /** * Placeholder function so that the [Verifier] can release any resources. */ + @Throws(Exception::class) abstract override fun close() } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 3d35c7751c..678f66bc3b 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -30,15 +30,19 @@ import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken +import net.corda.core.transactions.LedgerTransaction import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.days import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.minutes +import net.corda.djvm.analysis.AnalysisConfiguration +import net.corda.djvm.analysis.Whitelist import net.corda.djvm.source.* import net.corda.node.CordaClock import net.corda.node.VersionInfo import net.corda.node.internal.classloading.requireAnnotation import net.corda.node.internal.cordapp.* +import net.corda.node.internal.djvm.DeterministicVerifier import net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy import net.corda.node.internal.rpc.proxies.ThreadContextAdjustingRpcOpsProxy import net.corda.node.services.ContractUpgradeHandler @@ -96,6 +100,8 @@ import rx.Observable import rx.Scheduler import java.io.IOException import java.lang.reflect.InvocationTargetException +import java.net.URL +import java.net.URLClassLoader import java.nio.file.Path import java.security.KeyPair import java.security.KeyStoreException @@ -127,8 +133,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, protected val flowManager: FlowManager, val serverThread: AffinityExecutor.ServiceAffinityExecutor, val busyNodeLatch: ReusableLatch = ReusableLatch(), - bootstrapSource: ApiSource = EmptyApi, - djvmCordaSource: UserSource? = null) : SingletonSerializeAsToken() { + private val djvmBootstrapSource: ApiSource = EmptyApi, + private val djvmCordaSource: UserSource? = null) : SingletonSerializeAsToken() { protected abstract val log: Logger @Suppress("LeakingThis") @@ -194,7 +200,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val pkToIdCache = PublicKeyToOwningIdentityCacheImpl(database, cacheFactory) @Suppress("LeakingThis") val keyManagementService = makeKeyManagementService(identityService).tokenize() - val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersStorage, transactionStorage, bootstrapSource, djvmCordaSource).also { + val servicesForResolution = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersStorage, transactionStorage).also { attachments.servicesForResolution = it } @Suppress("LeakingThis") @@ -1072,6 +1078,27 @@ abstract class AbstractNode(val configuration: NodeConfiguration, override fun registerUnloadHandler(runOnStop: () -> Unit) { this@AbstractNode.runOnStop += runOnStop } + + override fun specialise(ltx: LedgerTransaction): LedgerTransaction { + val ledgerTransaction = servicesForResolution.specialise(ltx) + + // Do nothing unless we have Corda's deterministic libraries. + val cordaSource = djvmCordaSource ?: return ledgerTransaction + + // Specialise the LedgerTransaction here so that + // contracts are verified inside the DJVM! + return ledgerTransaction.specialise { tx, cl -> + (cl as? URLClassLoader)?.run { DeterministicVerifier(tx, cl, createSandbox(cordaSource, cl.urLs)) } ?: BasicVerifier(tx, cl) + } + } + + private fun createSandbox(cordaSource: UserSource, userSource: Array): AnalysisConfiguration { + return AnalysisConfiguration.createRoot( + userSource = cordaSource, + whitelist = Whitelist.MINIMAL, + bootstrapSource = djvmBootstrapSource + ).createChild(UserPathSource(userSource), null) + } } } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 37dcd53627..38ba8be766 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -111,7 +111,7 @@ open class Node(configuration: NodeConfiguration, flowManager, // Under normal (non-test execution) it will always be "1" AffinityExecutor.ServiceAffinityExecutor("Node thread-${sameVmNodeCounter.incrementAndGet()}", 1), - bootstrapSource = createBootstrapSource(configuration), + djvmBootstrapSource = createBootstrapSource(configuration), djvmCordaSource = createDeterministicClasspath(configuration) ) { diff --git a/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt b/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt index 70e8f82b0b..f5836c0cc5 100644 --- a/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/ServicesForResolutionImpl.kt @@ -2,7 +2,6 @@ package net.corda.node.internal import net.corda.core.contracts.* import net.corda.core.cordapp.CordappProvider -import net.corda.core.internal.BasicVerifier import net.corda.core.internal.SerializedStateAndRef import net.corda.core.node.NetworkParameters import net.corda.core.node.ServicesForResolution @@ -11,26 +10,16 @@ import net.corda.core.node.services.IdentityService import net.corda.core.node.services.NetworkParametersService import net.corda.core.node.services.TransactionStorage import net.corda.core.transactions.ContractUpgradeWireTransaction -import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.NotaryChangeWireTransaction import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction.Companion.resolveStateRefBinaryComponent -import net.corda.djvm.analysis.AnalysisConfiguration -import net.corda.djvm.analysis.Whitelist -import net.corda.djvm.source.ApiSource -import net.corda.djvm.source.UserPathSource -import net.corda.djvm.source.UserSource -import net.corda.node.internal.djvm.DeterministicVerifier -import java.net.URLClassLoader data class ServicesForResolutionImpl( override val identityService: IdentityService, override val attachments: AttachmentStorage, override val cordappProvider: CordappProvider, override val networkParametersService: NetworkParametersService, - private val validatedTransactions: TransactionStorage, - private val djvmBootstrapSource: ApiSource, - private val djvmCordaSource: UserSource? + private val validatedTransactions: TransactionStorage ) : ServicesForResolution { override val networkParameters: NetworkParameters get() = networkParametersService.lookup(networkParametersService.currentHash) ?: throw IllegalArgumentException("No current parameters in network parameters storage") @@ -80,23 +69,4 @@ data class ServicesForResolutionImpl( } return inner(stateRef, null) } - - override fun specialise(ltx: LedgerTransaction): LedgerTransaction { - // Do nothing unless we have Corda's deterministic libraries. - val cordaSource = djvmCordaSource ?: return ltx - - // Specialise the LedgerTransaction here so that - // contracts are verified inside the DJVM! - return ltx.specialise { tx, cl -> - (cl as? URLClassLoader)?.run { DeterministicVerifier(tx, cl, createSandbox(cordaSource, cl)) } ?: BasicVerifier(tx, cl) - } - } - - private fun createSandbox(cordaSource: UserSource, classLoader: URLClassLoader): AnalysisConfiguration { - return AnalysisConfiguration.createRoot( - userSource = cordaSource, - whitelist = Whitelist.MINIMAL, - bootstrapSource = djvmBootstrapSource - ).createChild(UserPathSource(classLoader.urLs), null) - } } diff --git a/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt b/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt index f1e933c93a..7c2490c823 100644 --- a/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt +++ b/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt @@ -18,9 +18,10 @@ class DeterministicVerifier( ) : Verifier(ltx, transactionClassLoader) { override fun verifyContracts() { - val configuration = SandboxConfiguration.of( - enableTracing = false, - analysisConfiguration = analysisConfiguration + val configuration = SandboxConfiguration.createFor( + analysisConfiguration = analysisConfiguration, + profile = ExecutionProfile.DEFAULT, + enableTracing = false ) val verifierClass = ClassSource.fromClassName(ContractVerifier::class.java.name) val result = IsolatedTask(verifierClass.qualifiedClassName, configuration).run { @@ -48,8 +49,9 @@ class DeterministicVerifier( } } + @Throws(Exception::class) override fun close() { - analysisConfiguration.close() + analysisConfiguration.closeAll() } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 48386df295..dde4af7310 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -21,7 +21,6 @@ import net.corda.core.node.services.* import net.corda.core.serialization.SerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.NetworkHostAndPort -import net.corda.djvm.source.EmptyApi import net.corda.node.VersionInfo import net.corda.node.internal.ServicesForResolutionImpl import net.corda.node.internal.cordapp.JarScanningCordappLoader @@ -431,7 +430,7 @@ open class MockServices private constructor( override var networkParametersService: NetworkParametersService = MockNetworkParametersStorage(initialNetworkParameters) protected val servicesForResolution: ServicesForResolution - get() = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersService, validatedTransactions, EmptyApi, null) + get() = ServicesForResolutionImpl(identityService, attachments, cordappProvider, networkParametersService, validatedTransactions) internal fun makeVaultService(schemaService: SchemaService, database: CordaPersistence, cordappLoader: CordappLoader): VaultServiceInternal { return NodeVaultService(clock, keyManagementService, servicesForResolution, database, schemaService, cordappLoader.appClassLoader).apply { start() } @@ -491,4 +490,4 @@ fun createMockCordaService(serviceHub: MockServices, serv } } return MockAppServiceHubImpl(serviceHub, serviceConstructor).serviceInstance -} \ No newline at end of file +}