Merge pull request #5928 from corda/chrisr3-inprocess-whitelists

CORDA-3566: Always add TestCordapps to the classpath when building _driverSerializationEnv.
This commit is contained in:
Matthew Nesbit 2020-02-19 13:52:34 +00:00 committed by GitHub
commit 86a4b998d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 172 additions and 29 deletions

View File

@ -0,0 +1,38 @@
package net.corda.contracts.serialization.whitelist
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.Contract
import net.corda.core.contracts.ContractState
import net.corda.core.identity.AbstractParty
import net.corda.core.transactions.LedgerTransaction
class WhitelistContract : Contract {
companion object {
const val MAX_VALUE = 2000L
}
override fun verify(tx: LedgerTransaction) {
val states = tx.outputsOfType<State>()
require(states.isNotEmpty()) {
"Requires at least one data state"
}
states.forEach {
require(it.whitelistData in WhitelistData(0)..WhitelistData(MAX_VALUE)) {
"WhitelistData $it exceeds maximum value!"
}
}
}
@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate")
class State(val owner: AbstractParty, val whitelistData: WhitelistData) : ContractState {
override val participants: List<AbstractParty> = listOf(owner)
@Override
override fun toString(): String {
return whitelistData.toString()
}
}
class Operate : CommandData
}

View File

@ -0,0 +1,15 @@
package net.corda.contracts.serialization.whitelist
import net.corda.core.serialization.SerializationWhitelist
data class WhitelistData(val value: Long) : Comparable<WhitelistData> {
override fun compareTo(other: WhitelistData): Int {
return value.compareTo(other.value)
}
override fun toString(): String = "$value things"
}
class Whitelist : SerializationWhitelist {
override val whitelist = listOf(WhitelistData::class.java)
}

View File

@ -6,11 +6,9 @@ import net.corda.core.contracts.Command
import net.corda.core.contracts.CommandData
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@InitiatingFlow
@StartableByRPC
class SandboxAttachmentFlow(private val command: CommandData) : FlowLogic<SecureHash>() {
@Suspendable

View File

@ -6,11 +6,9 @@ import net.corda.core.contracts.Command
import net.corda.core.contracts.TypeOnlyCommandData
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@InitiatingFlow
@StartableByRPC
class NonDeterministicFlow(private val trouble: TypeOnlyCommandData) : FlowLogic<SecureHash>() {
@Suspendable

View File

@ -6,12 +6,10 @@ import net.corda.core.contracts.Command
import net.corda.core.contracts.CommandData
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
@InitiatingFlow
@StartableByRPC
class DeterministicCryptoFlow(
private val command: CommandData,

View File

@ -7,11 +7,9 @@ import net.corda.contracts.djvm.whitelist.WhitelistData
import net.corda.core.contracts.Command
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@InitiatingFlow
@StartableByRPC
class DeterministicWhitelistFlow(private val data: WhitelistData) : FlowLogic<SecureHash>() {
@Suspendable

View File

@ -7,11 +7,9 @@ import net.corda.contracts.fixup.dependent.DependentData
import net.corda.core.contracts.Command
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@InitiatingFlow
@StartableByRPC
class CordappFixupFlow(private val data: DependentData) : FlowLogic<SecureHash>() {
@Suspendable

View File

@ -7,11 +7,9 @@ import net.corda.contracts.serialization.custom.CustomSerializerContract.Purchas
import net.corda.core.contracts.Command
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@InitiatingFlow
@StartableByRPC
class CustomSerializerFlow(
private val purchase: Currantsy

View File

@ -7,11 +7,9 @@ import net.corda.contracts.serialization.missing.MissingSerializerContract.Opera
import net.corda.core.contracts.Command
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@InitiatingFlow
@StartableByRPC
class MissingSerializerBuilderFlow(private val value: Long) : FlowLogic<SecureHash>() {
@Suspendable

View File

@ -12,14 +12,12 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.createComponentGroups
import net.corda.core.internal.requiredContractClassName
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction
@InitiatingFlow
@StartableByRPC
class MissingSerializerFlow(private val value: Long) : FlowLogic<SecureHash>() {
@Suspendable

View File

@ -0,0 +1,26 @@
package net.corda.flows.serialization.whitelist
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.serialization.whitelist.WhitelistContract
import net.corda.contracts.serialization.whitelist.WhitelistContract.State
import net.corda.contracts.serialization.whitelist.WhitelistData
import net.corda.core.contracts.Command
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC
import net.corda.core.transactions.TransactionBuilder
@StartableByRPC
class WhitelistFlow(private val data: WhitelistData) : FlowLogic<SecureHash>() {
@Suspendable
override fun call(): SecureHash {
val notary = serviceHub.networkMapCache.notaryIdentities[0]
val stx = serviceHub.signInitialTransaction(
TransactionBuilder(notary)
.addOutputState(State(ourIdentity, data))
.addCommand(Command(WhitelistContract.Operate(), ourIdentity.owningKey))
)
stx.verify(serviceHub, checkSufficientSignatures = false)
return stx.id
}
}

View File

@ -0,0 +1,83 @@
package net.corda.node
import net.corda.client.rpc.CordaRPCClient
import net.corda.contracts.serialization.whitelist.WhitelistData
import net.corda.core.contracts.TransactionVerificationException.ContractRejection
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.flows.serialization.whitelist.WhitelistFlow
import net.corda.node.services.Permissions
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.driver.internal.incrementalPortAllocation
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.User
import net.corda.testing.node.internal.cordappWithPackages
import org.assertj.core.api.Assertions.assertThat
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters
import kotlin.test.assertFailsWith
@RunWith(Parameterized::class)
@Suppress("FunctionName")
class ContractWithSerializationWhitelistTest(private val runInProcess: Boolean) {
companion object {
const val DATA = 123456L
@JvmField
val logger = loggerFor<ContractWithSerializationWhitelistTest>()
@JvmField
val contractCordapp = cordappWithPackages("net.corda.contracts.serialization.whitelist").signed()
@JvmField
val workflowCordapp = cordappWithPackages("net.corda.flows.serialization.whitelist").signed()
fun parametersFor(runInProcess: Boolean): DriverParameters {
return DriverParameters(
portAllocation = incrementalPortAllocation(),
startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)),
cordappsForAllNodes = listOf(contractCordapp, workflowCordapp)
)
}
@Parameters
@JvmStatic
fun modes(): List<Array<Boolean>> = listOf(Array(1) { true }, Array(1) { false })
@BeforeClass
@JvmStatic
fun checkData() {
assertNotCordaSerializable<WhitelistData>()
}
}
@Test(timeout = 300_000)
fun `test serialization whitelist`() {
logger.info("RUN-IN-PROCESS=$runInProcess")
val user = User("u", "p", setOf(Permissions.all()))
driver(parametersFor(runInProcess = runInProcess)) {
val badData = WhitelistData(DATA)
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val ex = assertFailsWith<ContractRejection> {
CordaRPCClient(hostAndPort = alice.rpcAddress)
.start(user.username, user.password)
.use { client ->
client.proxy.startFlow(::WhitelistFlow, badData)
.returnValue
.getOrThrow()
}
}
assertThat(ex)
.hasMessageContaining("WhitelistData $badData exceeds maximum value!")
}
}
}

View File

@ -219,7 +219,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
// present in the CorDapp.
val result = scanResult.getClassesWithSuperclass(NotaryService::class) +
scanResult.getClassesWithSuperclass(SinglePartyNotaryService::class)
if(!result.isEmpty()) {
if (result.isNotEmpty()) {
logger.info("Found notary service CorDapp implementations: " + result.joinToString(", "))
}
return result.firstOrNull()

View File

@ -142,11 +142,7 @@ class DriverDSLImpl(
private lateinit var _notaries: CordaFuture<List<NotaryHandle>>
override val notaryHandles: List<NotaryHandle> get() = _notaries.getOrThrow()
override val cordappsClassLoader: ClassLoader? = if (!startNodesInProcess) {
createCordappsClassLoader(cordappsForAllNodes)
} else {
null
}
override val cordappsClassLoader: URLClassLoader? = createCordappsClassLoader(cordappsForAllNodes)
interface Waitable {
@Throws(InterruptedException::class)
@ -195,14 +191,15 @@ class DriverDSLImpl(
}
override fun shutdown() {
if (waitForAllNodesToFinish) {
state.locked {
processes.forEach { it.waitFor() }
cordappsClassLoader.use { _ ->
if (waitForAllNodesToFinish) {
state.locked {
processes.forEach { it.waitFor() }
}
}
_shutdownManager?.shutdown()
_executorService?.shutdownNow()
}
_shutdownManager?.shutdown()
_executorService?.shutdownNow()
(cordappsClassLoader as? AutoCloseable)?.close()
}
private fun establishRpc(config: NodeConfig, processDeathFuture: CordaFuture<out Process>): CordaFuture<CordaRPCOps> {
@ -992,7 +989,7 @@ class DriverDSLImpl(
return config
}
private fun createCordappsClassLoader(cordapps: Collection<TestCordappInternal>?): ClassLoader? {
private fun createCordappsClassLoader(cordapps: Collection<TestCordappInternal>?): URLClassLoader? {
if (cordapps == null || cordapps.isEmpty()) {
return null
}