mirror of
https://github.com/corda/corda.git
synced 2025-02-20 09:26:41 +00:00
CORDA-3584: Now cope with 2 contract jars with same hash but different name (#5952)
* CORDA-3484: Now cope with 2 contract jars with same hash but different name, we just select one and use that. * ENT-3584: Contract jars are now generated on the fly. * CORDA-3584: Reverted changes to CordappProviderImpl. Exception is raised if node started with multiple jars with same hash. * ENT-3584: Fixing test failure. * CORDA-3584: Switch to test extension method instead of reflection to access internal member. * ENT-3584: Address review comment. Dont fully qualify exception. * CORDA-3584: Address review comment and converted lazy to a resettable one. * CORDA-3584: Removed unused logger. * CORDA-3584: Fixed visibility. * CORDA-3584: Removed synchronized * CORDA-3584: Removed CordappResolver * CORDA-3584: Reverted change in gradle file and fixed test. * CORDA-3584: Removed V3 from test description as it wasn't actually V3 specific. * CORDA-3584: Address review comment. Let classes be garbage collected.
This commit is contained in:
parent
2c9c2985c0
commit
fe625d0f37
@ -13,7 +13,6 @@ import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.cordapp.CordappResolver
|
||||
import net.corda.core.internal.warnOnce
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -95,7 +94,7 @@ private constructor(private val otherSideSession: FlowSession?,
|
||||
override fun call(): LinkedHashMap<Party, AnonymousParty> {
|
||||
val session = if (otherParty != null && otherParty != otherSideSession?.counterparty) {
|
||||
logger.warnOnce("The current usage of SwapIdentitiesFlow is unsafe. Please consider upgrading your CorDapp to use " +
|
||||
"SwapIdentitiesFlow with FlowSessions. (${CordappResolver.currentCordapp?.info})")
|
||||
"SwapIdentitiesFlow with FlowSessions. (${serviceHub.getAppContext().cordapp.info})")
|
||||
initiateFlow(otherParty)
|
||||
} else {
|
||||
otherSideSession!!
|
||||
|
@ -4,7 +4,6 @@ import com.natpryce.hamkrest.and
|
||||
import com.natpryce.hamkrest.assertion.assertThat
|
||||
import net.corda.core.flows.FinalityFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.cordapp.CordappResolver
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
@ -25,7 +24,8 @@ class FinalityFlowTests : WithFinality {
|
||||
private val CHARLIE = TestIdentity(CHARLIE_NAME, 90).party
|
||||
}
|
||||
|
||||
override val mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, enclosedCordapp()))
|
||||
override val mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, enclosedCordapp(),
|
||||
CustomCordapp(targetPlatformVersion = 3, classes = setOf(FinalityFlow::class.java))))
|
||||
|
||||
private val aliceNode = makeNode(ALICE_NAME)
|
||||
|
||||
@ -60,11 +60,8 @@ class FinalityFlowTests : WithFinality {
|
||||
fun `allow use of the old API if the CorDapp target version is 3`() {
|
||||
val oldBob = createBob(cordapps = listOf(tokenOldCordapp()))
|
||||
val stx = aliceNode.issuesCashTo(oldBob)
|
||||
val resultFuture = CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
|
||||
@Suppress("DEPRECATION")
|
||||
aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture
|
||||
}
|
||||
resultFuture.getOrThrow()
|
||||
@Suppress("DEPRECATION")
|
||||
aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture.getOrThrow()
|
||||
assertThat(oldBob.services.validatedTransactions.getTransaction(stx.id)).isNotNull()
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
|
||||
import net.corda.core.internal.cordapp.CordappResolver
|
||||
import net.corda.core.internal.pushToLoggingContext
|
||||
import net.corda.core.internal.warnOnce
|
||||
import net.corda.core.node.StatesToRecord
|
||||
@ -136,7 +135,7 @@ class FinalityFlow private constructor(val transaction: SignedTransaction,
|
||||
override fun call(): SignedTransaction {
|
||||
if (!newApi) {
|
||||
logger.warnOnce("The current usage of FinalityFlow is unsafe. Please consider upgrading your CorDapp to use " +
|
||||
"FinalityFlow with FlowSessions. (${CordappResolver.currentCordapp?.info})")
|
||||
"FinalityFlow with FlowSessions. (${serviceHub.getAppContext().cordapp.info})")
|
||||
} else {
|
||||
require(sessions.none { serviceHub.myInfo.isLegalIdentity(it.counterparty) }) {
|
||||
"Do not provide flow sessions for the local node. FinalityFlow will record the notarised transaction locally."
|
||||
|
@ -1,133 +0,0 @@
|
||||
package net.corda.core.internal.cordapp
|
||||
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.PLATFORM_VERSION
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.warnOnce
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* Provides a way to acquire information about the calling CorDapp.
|
||||
*/
|
||||
object CordappResolver {
|
||||
|
||||
private val logger = loggerFor<CordappResolver>()
|
||||
private val cordappClasses: ConcurrentHashMap<String, Set<Cordapp>> = ConcurrentHashMap()
|
||||
|
||||
private val insideInMemoryTest: Boolean by lazy { insideInMemoryTest() }
|
||||
|
||||
// TODO Use the StackWalker API once we migrate to Java 9+
|
||||
private var cordappResolver: () -> Cordapp? = {
|
||||
Exception().stackTrace
|
||||
.mapNotNull { cordappClasses[it.className] }
|
||||
// in case there are multiple classes matched, we select the first one having a single CorDapp registered against it.
|
||||
.firstOrNull { it.size == 1 }
|
||||
// otherwise we return null, signalling we cannot reliably determine the current CorDapp.
|
||||
?.single()
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates class names with CorDapps or logs a warning when a CorDapp is already registered for a given class.
|
||||
* This could happen when trying to run different versions of the same CorDapp on the same node.
|
||||
*
|
||||
* @throws IllegalStateException when multiple CorDapps are registered for the same contract class,
|
||||
* since this can lead to undefined behaviour.
|
||||
*/
|
||||
@Synchronized
|
||||
fun register(cordapp: Cordapp) {
|
||||
val contractClasses = cordapp.contractClassNames.toSet()
|
||||
val existingClasses = cordappClasses.keys
|
||||
val classesToRegister = cordapp.cordappClasses.toSet()
|
||||
val notAlreadyRegisteredClasses = classesToRegister - existingClasses
|
||||
val alreadyRegistered= HashMap(cordappClasses).apply { keys.retainAll(classesToRegister) }
|
||||
|
||||
notAlreadyRegisteredClasses.forEach { cordappClasses[it] = setOf(cordapp) }
|
||||
|
||||
for ((registeredClassName, registeredCordapps) in alreadyRegistered) {
|
||||
val duplicateCordapps = registeredCordapps.filter { it.jarHash == cordapp.jarHash }.toSet()
|
||||
|
||||
if (duplicateCordapps.isNotEmpty()) {
|
||||
logger.warnOnce("The CorDapp (name: ${cordapp.info.shortName}, file: ${cordapp.name}) " +
|
||||
"is installed multiple times on the node. The following files correspond to the exact same content: " +
|
||||
"${duplicateCordapps.map { it.name }}")
|
||||
continue
|
||||
}
|
||||
// During in-memory tests, the spawned nodes share the same CordappResolver, so detected conflicts can be spurious.
|
||||
if (registeredClassName in contractClasses && !insideInMemoryTest) {
|
||||
throw IllegalStateException("More than one CorDapp installed on the node for contract $registeredClassName. " +
|
||||
"Please remove the previous version when upgrading to a new version.")
|
||||
}
|
||||
|
||||
cordappClasses[registeredClassName] = registeredCordapps + cordapp
|
||||
}
|
||||
}
|
||||
|
||||
private fun insideInMemoryTest(): Boolean {
|
||||
return Exception().stackTrace.any {
|
||||
it.className.startsWith("net.corda.testing.node.internal.InternalMockNetwork") ||
|
||||
it.className.startsWith("net.corda.testing.node.internal.InProcessNode") ||
|
||||
it.className.startsWith("net.corda.testing.node.MockServices")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This should only be used when making a change that would break compatibility with existing CorDapps. The change
|
||||
* can then be version-gated, meaning the old behaviour is used if the calling CorDapp's target version is lower
|
||||
* than the platform version that introduces the new behaviour.
|
||||
* In situations where a `[CordappProvider]` is available the CorDapp context should be obtained from there.
|
||||
*
|
||||
* @return Information about the CorDapp from which the invoker is called, null if called outside a CorDapp or the
|
||||
* calling CorDapp cannot be reliably determined.
|
||||
*/
|
||||
val currentCordapp: Cordapp? get() = cordappResolver()
|
||||
|
||||
/**
|
||||
* Returns the target version of the current calling CorDapp. Defaults to platform version 1 if there isn't one,
|
||||
* assuming only basic platform capabilities.
|
||||
*/
|
||||
val currentTargetVersion: Int get() = currentCordapp?.targetPlatformVersion ?: 1
|
||||
|
||||
// A list of extra CorDapps added to the current CorDapps list for testing purposes.
|
||||
private var extraCordappsForTesting = listOf<Cordapp>()
|
||||
|
||||
/**
|
||||
* Return all the CorDapps that were involved in the call stack at the point the provided exception was generated.
|
||||
*
|
||||
* This is provided to allow splitting the cost of generating the exception and retrieving the CorDapps involved.
|
||||
*/
|
||||
fun cordappsFromException(exception: Exception): List<Cordapp> {
|
||||
val apps = exception.stackTrace
|
||||
.mapNotNull { cordappClasses[it.className] }
|
||||
.flatten()
|
||||
.distinct()
|
||||
return (apps + extraCordappsForTesting)
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily apply a fake CorDapp with the given parameters. For use in testing.
|
||||
*/
|
||||
@Synchronized
|
||||
@VisibleForTesting
|
||||
fun <T> withTestCordapp(minimumPlatformVersion: Int = 1,
|
||||
targetPlatformVersion: Int = PLATFORM_VERSION,
|
||||
extraApps: List<CordappImpl> = listOf(),
|
||||
block: () -> T): T {
|
||||
val currentResolver = cordappResolver
|
||||
cordappResolver = {
|
||||
CordappImpl.TEST_INSTANCE.copy(minimumPlatformVersion = minimumPlatformVersion, targetPlatformVersion = targetPlatformVersion)
|
||||
}
|
||||
extraCordappsForTesting = listOf(cordappResolver()!!) + extraApps
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
cordappResolver = currentResolver
|
||||
extraCordappsForTesting = listOf()
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun clear() {
|
||||
cordappClasses.clear()
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package net.corda.core.internal.cordapp
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.lang.IllegalStateException
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class CordappResolverTest {
|
||||
@Before
|
||||
@After
|
||||
fun clearCordappInfoResolver() {
|
||||
CordappResolver.clear()
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `the correct cordapp resolver is used after calling withCordappInfo`() {
|
||||
val defaultTargetVersion = 222
|
||||
|
||||
CordappResolver.register(CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf(javaClass.name),
|
||||
minimumPlatformVersion = 3,
|
||||
targetPlatformVersion = defaultTargetVersion
|
||||
))
|
||||
assertEquals(defaultTargetVersion, CordappResolver.currentTargetVersion)
|
||||
|
||||
val expectedTargetVersion = 555
|
||||
CordappResolver.withTestCordapp(targetPlatformVersion = expectedTargetVersion) {
|
||||
val actualTargetVersion = CordappResolver.currentTargetVersion
|
||||
assertEquals(expectedTargetVersion, actualTargetVersion)
|
||||
}
|
||||
assertEquals(defaultTargetVersion, CordappResolver.currentTargetVersion)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `when the same cordapp is registered for the same class multiple times, the resolver deduplicates and returns it as the current one`() {
|
||||
CordappResolver.register(CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf(javaClass.name),
|
||||
minimumPlatformVersion = 3,
|
||||
targetPlatformVersion = 222
|
||||
))
|
||||
CordappResolver.register(CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf(javaClass.name),
|
||||
minimumPlatformVersion = 2,
|
||||
targetPlatformVersion = 456
|
||||
))
|
||||
assertThat(CordappResolver.currentCordapp).isNotNull()
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `when different cordapps are registered for the same (non-contract) class, the resolver returns null`() {
|
||||
CordappResolver.register(CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf("ContractClass1"),
|
||||
minimumPlatformVersion = 3,
|
||||
targetPlatformVersion = 222,
|
||||
jarHash = SecureHash.randomSHA256()
|
||||
))
|
||||
CordappResolver.register(CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf("ContractClass2"),
|
||||
minimumPlatformVersion = 2,
|
||||
targetPlatformVersion = 456,
|
||||
jarHash = SecureHash.randomSHA256()
|
||||
))
|
||||
assertThat(CordappResolver.currentCordapp).isNull()
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `when different cordapps are registered for the same (contract) class, the resolver throws an exception`() {
|
||||
val firstCordapp = CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf(javaClass.name),
|
||||
minimumPlatformVersion = 3,
|
||||
targetPlatformVersion = 222,
|
||||
jarHash = SecureHash.randomSHA256()
|
||||
)
|
||||
val secondCordapp = CordappImpl.TEST_INSTANCE.copy(
|
||||
contractClassNames = listOf(javaClass.name),
|
||||
minimumPlatformVersion = 2,
|
||||
targetPlatformVersion = 456,
|
||||
jarHash = SecureHash.randomSHA256()
|
||||
)
|
||||
|
||||
CordappResolver.register(firstCordapp)
|
||||
assertThatThrownBy { CordappResolver.register(secondCordapp) }
|
||||
.isInstanceOf(IllegalStateException::class.java)
|
||||
.hasMessageContaining("More than one CorDapp installed on the node for contract ${javaClass.name}. " +
|
||||
"Please remove the previous version when upgrading to a new version.")
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,6 @@ import net.corda.core.flows.*
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.internal.cordapp.CordappImpl
|
||||
import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN_INFO
|
||||
import net.corda.core.internal.cordapp.CordappResolver
|
||||
import net.corda.core.internal.cordapp.get
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
import net.corda.core.internal.notary.SinglePartyNotaryService
|
||||
@ -30,6 +29,7 @@ import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.jar.JarInputStream
|
||||
import java.util.jar.Manifest
|
||||
import java.util.zip.ZipInputStream
|
||||
@ -52,7 +52,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
||||
logger.info("Loading CorDapps from ${cordappJarPaths.joinToString()}")
|
||||
}
|
||||
}
|
||||
|
||||
private val cordappClasses: ConcurrentHashMap<String, Set<Cordapp>> = ConcurrentHashMap()
|
||||
override val cordapps: List<CordappImpl> by lazy { loadCordapps() + extraCordapps }
|
||||
|
||||
override val appClassLoader: URLClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
|
||||
@ -128,10 +128,35 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
||||
}
|
||||
}
|
||||
}
|
||||
cordapps.forEach(CordappResolver::register)
|
||||
cordapps.forEach(::register)
|
||||
return cordapps
|
||||
}
|
||||
|
||||
private fun register(cordapp: Cordapp) {
|
||||
val contractClasses = cordapp.contractClassNames.toSet()
|
||||
val existingClasses = cordappClasses.keys
|
||||
val classesToRegister = cordapp.cordappClasses.toSet()
|
||||
val notAlreadyRegisteredClasses = classesToRegister - existingClasses
|
||||
val alreadyRegistered= HashMap(cordappClasses).apply { keys.retainAll(classesToRegister) }
|
||||
|
||||
notAlreadyRegisteredClasses.forEach { cordappClasses[it] = setOf(cordapp) }
|
||||
|
||||
for ((registeredClassName, registeredCordapps) in alreadyRegistered) {
|
||||
val duplicateCordapps = registeredCordapps.filter { it.jarHash == cordapp.jarHash }.toSet()
|
||||
|
||||
if (duplicateCordapps.isNotEmpty()) {
|
||||
throw IllegalStateException("The CorDapp (name: ${cordapp.info.shortName}, file: ${cordapp.name}) " +
|
||||
"is installed multiple times on the node. The following files correspond to the exact same content: " +
|
||||
"${duplicateCordapps.map { it.name }}")
|
||||
}
|
||||
if (registeredClassName in contractClasses) {
|
||||
throw IllegalStateException("More than one CorDapp installed on the node for contract $registeredClassName. " +
|
||||
"Please remove the previous version when upgrading to a new version.")
|
||||
}
|
||||
cordappClasses[registeredClassName] = registeredCordapps + cordapp
|
||||
}
|
||||
}
|
||||
|
||||
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
|
||||
val manifest: Manifest? = url.url.openStream().use { JarInputStream(it).manifest }
|
||||
val info = parseCordappInfo(manifest, CordappImpl.jarName(url.url))
|
||||
|
@ -5,7 +5,8 @@ import com.typesafe.config.ConfigFactory
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.core.internal.ContractJarTestUtils
|
||||
import net.corda.testing.core.internal.SelfCleaningDir
|
||||
import net.corda.testing.internal.MockCordappConfigProvider
|
||||
import net.corda.testing.services.MockAttachmentStorage
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@ -14,7 +15,9 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.IllegalStateException
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.util.jar.JarOutputStream
|
||||
import java.util.zip.Deflater.NO_COMPRESSION
|
||||
import java.util.zip.ZipEntry
|
||||
@ -56,7 +59,6 @@ class CordappProviderImplTests {
|
||||
}
|
||||
|
||||
private lateinit var attachmentStore: AttachmentStorage
|
||||
private val whitelistedContractImplementations = testNetworkParameters().whitelistedContractImplementations
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
@ -189,6 +191,33 @@ class CordappProviderImplTests {
|
||||
assertThat(fixedIDs).containsExactlyInAnyOrder(ID2, ID4)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `test an exception is raised when we have two jars with the same hash`() {
|
||||
|
||||
SelfCleaningDir().use { file ->
|
||||
val jarAndSigner = ContractJarTestUtils.makeTestSignedContractJar(file.path, "com.example.MyContract")
|
||||
val signedJarPath = jarAndSigner.first
|
||||
val duplicateJarPath = signedJarPath.parent.resolve("duplicate-" + signedJarPath.fileName)
|
||||
|
||||
Files.copy(signedJarPath, duplicateJarPath)
|
||||
assertFailsWith<IllegalStateException> {
|
||||
newCordappProvider(signedJarPath.toUri().toURL(), duplicateJarPath.toUri().toURL())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `test an exception is raised when two jars share a contract`() {
|
||||
|
||||
SelfCleaningDir().use { file ->
|
||||
val jarA = ContractJarTestUtils.makeTestContractJar(file.path, listOf("com.example.MyContract", "com.example.AnotherContractForA"), generateManifest = false, jarFileName = "sampleA.jar")
|
||||
val jarB = ContractJarTestUtils.makeTestContractJar(file.path, listOf("com.example.MyContract", "com.example.AnotherContractForB"), generateManifest = false, jarFileName = "sampleB.jar")
|
||||
assertFailsWith<IllegalStateException> {
|
||||
newCordappProvider(jarA.toUri().toURL(), jarB.toUri().toURL())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.writeFixupRules(vararg lines: String): File {
|
||||
JarOutputStream(FileOutputStream(this)).use { jar ->
|
||||
jar.setMethod(DEFLATED)
|
||||
|
@ -5,7 +5,6 @@ import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FinalityFlow
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.internal.cordapp.CordappResolver
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
@ -35,7 +34,8 @@ class FinalityHandlerTest {
|
||||
fun `sent to flow hospital on error and attempted retry on node restart`() {
|
||||
// Setup a network where only Alice has the finance CorDapp and it sends a cash tx to Bob who doesn't have the
|
||||
// CorDapp. Bob's FinalityHandler will error when validating the tx.
|
||||
val alice = mockNet.createNode(InternalMockNodeParameters(legalName = ALICE_NAME, additionalCordapps = FINANCE_CORDAPPS))
|
||||
val alice = mockNet.createNode(InternalMockNodeParameters(legalName = ALICE_NAME,
|
||||
additionalCordapps = FINANCE_CORDAPPS + CustomCordapp(targetPlatformVersion = 3, classes = setOf(FinalityFlow::class.java))))
|
||||
|
||||
var bob = mockNet.createNode(InternalMockNodeParameters(
|
||||
legalName = BOB_NAME,
|
||||
@ -82,11 +82,9 @@ class FinalityHandlerTest {
|
||||
}
|
||||
|
||||
private fun TestStartedNode.finaliseWithOldApi(stx: SignedTransaction): CordaFuture<SignedTransaction> {
|
||||
return CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
|
||||
@Suppress("DEPRECATION")
|
||||
services.startFlow(FinalityFlow(stx)).resultFuture.apply {
|
||||
@Suppress("DEPRECATION")
|
||||
return services.startFlow(FinalityFlow(stx)).resultFuture.apply {
|
||||
mockNet.runNetwork()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package net.corda.node.services.vault
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.nhaarman.mockito_kotlin.argThat
|
||||
import com.nhaarman.mockito_kotlin.doNothing
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.contracts.*
|
||||
@ -11,7 +10,6 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.identity.*
|
||||
import net.corda.core.internal.NotaryChangeTransactionBuilder
|
||||
import net.corda.core.internal.cordapp.CordappResolver
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.node.NotaryInfo
|
||||
import net.corda.core.node.StatesToRecord
|
||||
@ -887,7 +885,7 @@ class NodeVaultServiceTest {
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `V3 vault queries return all states by default`() {
|
||||
fun `Vault queries return all states by default`() {
|
||||
fun createTx(number: Int, vararg participants: Party): SignedTransaction {
|
||||
return services.signInitialTransaction(TransactionBuilder(DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyState(number, participants.toList()), DummyContract.PROGRAM_ID)
|
||||
@ -897,20 +895,18 @@ class NodeVaultServiceTest {
|
||||
|
||||
fun List<StateAndRef<DummyState>>.getNumbers() = map { it.state.data.magicNumber }.toSet()
|
||||
|
||||
CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(1, megaCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(2, miniCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(3, miniCorp.party, megaCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ALL_VISIBLE, listOf(createTx(4, miniCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ALL_VISIBLE, listOf(createTx(5, bankOfCorda.party)))
|
||||
services.recordTransactions(StatesToRecord.ALL_VISIBLE, listOf(createTx(6, megaCorp.party, bankOfCorda.party)))
|
||||
services.recordTransactions(StatesToRecord.NONE, listOf(createTx(7, bankOfCorda.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(1, megaCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(2, miniCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(3, miniCorp.party, megaCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ALL_VISIBLE, listOf(createTx(4, miniCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ALL_VISIBLE, listOf(createTx(5, bankOfCorda.party)))
|
||||
services.recordTransactions(StatesToRecord.ALL_VISIBLE, listOf(createTx(6, megaCorp.party, bankOfCorda.party)))
|
||||
services.recordTransactions(StatesToRecord.NONE, listOf(createTx(7, bankOfCorda.party)))
|
||||
|
||||
// Test one.
|
||||
// RelevancyStatus is ALL by default. This should return five states.
|
||||
val resultOne = vaultService.queryBy<DummyState>().states.getNumbers()
|
||||
assertEquals(setOf(1, 3, 4, 5, 6), resultOne)
|
||||
}
|
||||
// Test one.
|
||||
// RelevancyStatus is ALL by default. This should return five states.
|
||||
val resultOne = vaultService.queryBy<DummyState>().states.getNumbers()
|
||||
assertEquals(setOf(1, 3, 4, 5, 6), resultOne)
|
||||
|
||||
// We should never see 2 or 7.
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user