Migrate DJVM specialisation into AbstractNode's ServiceHubInternalImpl.

This commit is contained in:
Chris Rankin 2019-08-02 13:06:32 +01:00
parent 7fdbbeb9ae
commit 56cc8a0b8f
6 changed files with 41 additions and 42 deletions

View File

@ -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()
}

View File

@ -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<S>(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<S>(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<S>(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<URL>): AnalysisConfiguration {
return AnalysisConfiguration.createRoot(
userSource = cordaSource,
whitelist = Whitelist.MINIMAL,
bootstrapSource = djvmBootstrapSource
).createChild(UserPathSource(userSource), null)
}
}
}

View File

@ -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)
) {

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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 <T : SerializeAsToken> createMockCordaService(serviceHub: MockServices, serv
}
}
return MockAppServiceHubImpl(serviceHub, serviceConstructor).serviceInstance
}
}