mirror of
https://github.com/corda/corda.git
synced 2025-01-14 00:39:57 +00:00
Merge pull request #764 from corda/colljos-merge-230418
OS -> ENT merge
This commit is contained in:
commit
5ae35b70dc
@ -3228,7 +3228,7 @@ public static final class net.corda.core.transactions.FilteredTransaction$Compan
|
||||
@org.jetbrains.annotations.NotNull public final List inputsOfType(Class)
|
||||
public String toString()
|
||||
public final void verify()
|
||||
public static final net.corda.core.transactions.LedgerTransaction$Companion Companion
|
||||
@java.lang.Deprecated public static final net.corda.core.transactions.LedgerTransaction$Companion Companion
|
||||
##
|
||||
public static final class net.corda.core.transactions.LedgerTransaction$InOutGroup extends java.lang.Object
|
||||
public <init>(List, List, Object)
|
||||
@ -3334,7 +3334,7 @@ public static final class net.corda.core.transactions.NotaryChangeWireTransactio
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.SignedTransaction withAdditionalSignature(java.security.KeyPair, net.corda.core.crypto.SignatureMetadata)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.SignedTransaction withAdditionalSignature(net.corda.core.crypto.TransactionSignature)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.transactions.SignedTransaction withAdditionalSignatures(Iterable)
|
||||
public static final net.corda.core.transactions.SignedTransaction$Companion Companion
|
||||
@java.lang.Deprecated public static final net.corda.core.transactions.SignedTransaction$Companion Companion
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.transactions.SignedTransaction$SignaturesMissingException extends java.security.SignatureException implements net.corda.core.CordaThrowable, net.corda.core.contracts.NamedByHash
|
||||
public <init>(Set, List, net.corda.core.crypto.SecureHash)
|
||||
|
@ -183,8 +183,8 @@ allprojects {
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
kotlinOptions {
|
||||
languageVersion = "1.1"
|
||||
apiVersion = "1.1"
|
||||
languageVersion = "1.2"
|
||||
apiVersion = "1.2"
|
||||
jvmTarget = "1.8"
|
||||
javaParameters = true // Useful for reflection.
|
||||
}
|
||||
|
@ -474,3 +474,8 @@ fun NotarisationRequest.generateSignature(serviceHub: ServiceHub): NotarisationR
|
||||
}
|
||||
|
||||
val PublicKey.hash: SecureHash get() = encoded.sha256()
|
||||
|
||||
/**
|
||||
* Extension method for providing a sumBy method that processes and returns a Long
|
||||
*/
|
||||
fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long = this.map { selector(it) }.sum()
|
||||
|
@ -140,7 +140,3 @@ fun <V> Future<V>.getOrThrow(timeout: Duration? = null): V = try {
|
||||
throw e.cause!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension method for providing a sumBy method that processes and returns a Long
|
||||
*/
|
||||
fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long = this.map { selector(it) }.sum()
|
||||
|
@ -11,6 +11,7 @@
|
||||
package net.corda.core.flows;
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.Primitives;
|
||||
import net.corda.core.identity.Party;
|
||||
import net.corda.testing.core.TestConstants;
|
||||
@ -23,13 +24,12 @@ import org.junit.Test;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static net.corda.testing.core.TestUtils.singleIdentity;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class FlowsInJavaTest {
|
||||
private final MockNetwork mockNet = new MockNetwork(emptyList());
|
||||
private final MockNetwork mockNet = new MockNetwork(ImmutableList.of("net.corda.core.flows"));
|
||||
private StartedMockNode aliceNode;
|
||||
private StartedMockNode bobNode;
|
||||
private Party bob;
|
||||
@ -48,7 +48,6 @@ public class FlowsInJavaTest {
|
||||
|
||||
@Test
|
||||
public void suspendableActionInsideUnwrap() throws Exception {
|
||||
bobNode.registerInitiatedFlow(SendHelloAndThenReceive.class);
|
||||
Future<String> result = aliceNode.startFlow(new SendInUnwrapFlow(bob));
|
||||
mockNet.runNetwork();
|
||||
assertThat(result.get()).isEqualTo("Hello");
|
||||
|
@ -51,7 +51,7 @@ class CollectSignaturesFlowTests {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
|
||||
mockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.core.flows"))
|
||||
aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
charlieNode = mockNet.createPartyNode(CHARLIE_NAME)
|
||||
@ -66,12 +66,6 @@ class CollectSignaturesFlowTests {
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
|
||||
private fun registerFlowOnAllNodes(flowClass: KClass<out FlowLogic<*>>) {
|
||||
listOf(aliceNode, bobNode, charlieNode).forEach {
|
||||
it.registerInitiatedFlow(flowClass.java)
|
||||
}
|
||||
}
|
||||
|
||||
// With this flow, the initiator starts the "CollectTransactionFlow". It is then the responders responsibility to
|
||||
// override "checkTransaction" and add whatever logic their require to verify the SignedTransaction they are
|
||||
// receiving off the wire.
|
||||
@ -120,7 +114,6 @@ class CollectSignaturesFlowTests {
|
||||
// Normally this is handled by TransactionKeyFlow, but here we have to manually let A know about the identity
|
||||
aliceNode.services.identityService.verifyAndRegisterIdentity(bConfidentialIdentity)
|
||||
}
|
||||
registerFlowOnAllNodes(TestFlow.Responder::class)
|
||||
val magicNumber = 1337
|
||||
val parties = listOf(alice, bConfidentialIdentity.party, charlie)
|
||||
val state = DummyContract.MultiOwnerState(magicNumber, parties)
|
||||
|
@ -48,12 +48,10 @@ class ResolveTransactionsFlowTest {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
|
||||
mockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.core.internal"))
|
||||
notaryNode = mockNet.defaultNotaryNode
|
||||
megaCorpNode = mockNet.createPartyNode(CordaX500Name("MegaCorp", "London", "GB"))
|
||||
miniCorpNode = mockNet.createPartyNode(CordaX500Name("MiniCorp", "London", "GB"))
|
||||
megaCorpNode.registerInitiatedFlow(TestResponseFlow::class.java)
|
||||
miniCorpNode.registerInitiatedFlow(TestResponseFlow::class.java)
|
||||
notary = mockNet.defaultNotaryIdentity
|
||||
megaCorp = megaCorpNode.info.singleIdentity()
|
||||
miniCorp = miniCorpNode.info.singleIdentity()
|
||||
|
@ -165,24 +165,6 @@ Nodes are created on the ``MockNetwork`` using:
|
||||
}
|
||||
}
|
||||
|
||||
Registering a node's initiated flows
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Regular Corda nodes automatically register any response flows defined in their installed CorDapps. When using a
|
||||
``MockNetwork``, each ``StartedMockNode`` must manually register any responder flows it wishes to use.
|
||||
|
||||
Responder flows are registered as follows:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
nodeA.registerInitiatedFlow(ExampleFlow.Acceptor::class.java)
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
nodeA.registerInitiatedFlow(ExampleFlow.Acceptor.class);
|
||||
|
||||
Running the network
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
package net.corda.docs.tutorial.mocknetwork
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.google.common.collect.ImmutableList
|
||||
import net.corda.core.contracts.requireThat
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowSession
|
||||
@ -72,10 +73,9 @@ class TutorialMockNetwork {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockNet = MockNetwork(emptyList())
|
||||
mockNet = MockNetwork(ImmutableList.of("net.corda.docs.tutorial.mocknetwork"))
|
||||
nodeA = mockNet.createPartyNode()
|
||||
nodeB = mockNet.createPartyNode()
|
||||
nodeB.registerInitiatedFlow(FlowB::class.java)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -61,10 +61,6 @@ transactions are valid) inside a ``database.transaction``. All node flows run w
|
||||
nodes themselves, but any time we need to use the database directly from a unit test, you need to provide a database
|
||||
transaction as shown here.
|
||||
|
||||
With regards to initiated flows (see :doc:`flow-state-machines` for information on initiated and initiating flows), the
|
||||
full node automatically registers them by scanning the CorDapp jars. In a unit test environment this is not possible so
|
||||
``MockNode`` has the ``registerInitiatedFlow`` method to manually register an initiated flow.
|
||||
|
||||
.. MockNetwork message manipulation
|
||||
.. --------------------------------
|
||||
.. The MockNetwork has the ability to manipulate message streams. You can use this to test your flows behaviour on corrupted,
|
||||
|
@ -15,6 +15,7 @@ import net.corda.behave.file.currentDirectory
|
||||
import net.corda.behave.logging.getLogger
|
||||
import net.corda.behave.process.output.OutputListener
|
||||
import rx.Observable
|
||||
import rx.Subscriber
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
@ -153,8 +154,9 @@ open class Command(
|
||||
return exitCode
|
||||
}
|
||||
|
||||
fun use(action: (Command, Observable<String>) -> Unit = { _, _ -> }): Int {
|
||||
fun use(subscriber: Subscriber<String>, action: (Command, Observable<String>) -> Unit = { _, _ -> }): Int {
|
||||
try {
|
||||
output.subscribe(subscriber)
|
||||
start()
|
||||
action(this, output)
|
||||
} finally {
|
||||
|
@ -1,18 +0,0 @@
|
||||
package net.corda.behave.scenarios
|
||||
|
||||
import cucumber.api.java.After
|
||||
import cucumber.api.java.Before
|
||||
|
||||
@Suppress("KDocMissingDocumentation")
|
||||
class ScenarioHooks(private val state: ScenarioState) {
|
||||
|
||||
@Before
|
||||
fun beforeScenario() {
|
||||
}
|
||||
|
||||
@After
|
||||
fun afterScenario() {
|
||||
state.stopNetwork()
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@ import net.corda.behave.scenarios.ScenarioState
|
||||
import net.corda.behave.scenarios.api.StepsBlock
|
||||
import net.corda.behave.scenarios.helpers.Vault
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.utilities.sumByLong
|
||||
import net.corda.core.internal.sumByLong
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
|
||||
class VaultSteps : StepsBlock {
|
||||
|
@ -31,8 +31,7 @@ class CommandTests {
|
||||
@Test
|
||||
fun `output stream for command can be observed`() {
|
||||
val subscriber = TestSubscriber<String>()
|
||||
val exitCode = Command(listOf("ls", "/")).use { _, output ->
|
||||
output.subscribe(subscriber)
|
||||
val exitCode = Command(listOf("ls", "/")).use(subscriber) { _, output ->
|
||||
subscriber.awaitTerminalEvent()
|
||||
subscriber.assertCompleted()
|
||||
subscriber.assertNoErrors()
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* R3 Proprietary and Confidential
|
||||
*
|
||||
* Copyright (c) 2018 R3 Limited. All rights reserved.
|
||||
*
|
||||
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
|
||||
*
|
||||
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
|
||||
*/
|
||||
|
||||
package net.corda.behave.service
|
||||
|
||||
import net.corda.behave.service.database.PostgreSQLService
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
class PostreSQLServiceTests {
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `postgres can be started and stopped`() {
|
||||
val service = PostgreSQLService("test-postgres", 12345, "postgres")
|
||||
val didStart = service.start()
|
||||
service.stop()
|
||||
assertThat(didStart).isTrue()
|
||||
}
|
||||
|
||||
}
|
@ -13,40 +13,53 @@ package net.corda.nodeapi.internal
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.contracts.UpgradedContract
|
||||
import net.corda.core.contracts.UpgradedContractWithLegacyConstraint
|
||||
import net.corda.core.internal.copyTo
|
||||
import net.corda.core.internal.deleteIfExists
|
||||
import net.corda.core.internal.logElapsedTime
|
||||
import net.corda.core.internal.read
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.InputStream
|
||||
import java.lang.reflect.Modifier
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.Collections.singleton
|
||||
|
||||
// When scanning of the CorDapp Jar is performed without "corda-core.jar" being the in the classpath, there is no way to appreciate
|
||||
// relationships between those interfaces, therefore they have to be listed explicitly.
|
||||
val coreContractClasses = setOf(Contract::class, UpgradedContractWithLegacyConstraint::class, UpgradedContract::class)
|
||||
|
||||
/**
|
||||
* Scans the jar for contracts.
|
||||
* @returns: found contract class names or null if none found
|
||||
*/
|
||||
fun scanJarForContracts(cordappJar: Path): List<ContractClassName> {
|
||||
val currentClassLoader = Contract::class.java.classLoader
|
||||
val scanResult = FastClasspathScanner()
|
||||
.addClassLoader(currentClassLoader)
|
||||
.overrideClasspath(cordappJar, Paths.get(Contract::class.java.protectionDomain.codeSource.location.toURI()))
|
||||
// A set of a single element may look odd, but if this is removed "Path" which itself is an `Iterable`
|
||||
// is getting broken into pieces to scan individually, which doesn't yield desired effect.
|
||||
.overrideClasspath(singleton(cordappJar))
|
||||
.scan()
|
||||
val contracts = (scanResult.getNamesOfClassesImplementing(Contract::class.qualifiedName) ).distinct()
|
||||
val contracts = coreContractClasses.flatMap { contractClass -> scanResult.getNamesOfClassesImplementing(contractClass.qualifiedName) }.distinct()
|
||||
|
||||
// Only keep instantiable contracts
|
||||
return URLClassLoader(arrayOf(cordappJar.toUri().toURL()), currentClassLoader).use {
|
||||
return URLClassLoader(arrayOf(cordappJar.toUri().toURL()), Contract::class.java.classLoader).use {
|
||||
contracts.map(it::loadClass).filter { !it.isInterface && !Modifier.isAbstract(it.modifiers) }
|
||||
}.map { it.name }
|
||||
}
|
||||
|
||||
private val logger = LoggerFactory.getLogger("ClassloaderUtils")
|
||||
|
||||
fun <T> withContractsInJar(jarInputStream: InputStream, withContracts: (List<ContractClassName>, InputStream) -> T): T {
|
||||
val tempFile = Files.createTempFile("attachment", ".jar")
|
||||
try {
|
||||
jarInputStream.copyTo(tempFile, StandardCopyOption.REPLACE_EXISTING)
|
||||
val contracts = scanJarForContracts(tempFile.toAbsolutePath())
|
||||
val cordappJar = tempFile.toAbsolutePath()
|
||||
val contracts = logElapsedTime("Contracts loading for '$cordappJar'", logger) {
|
||||
scanJarForContracts(cordappJar)
|
||||
}
|
||||
return tempFile.read { withContracts(contracts, it) }
|
||||
} finally {
|
||||
tempFile.deleteIfExists()
|
||||
|
@ -27,6 +27,7 @@ import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.node.internal.classloading.requireAnnotation
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.nodeapi.internal.coreContractClasses
|
||||
import net.corda.nodeapi.internal.serialization.DefaultWhitelist
|
||||
import org.apache.commons.collections4.map.LRUMap
|
||||
import java.io.File
|
||||
@ -251,13 +252,7 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
}
|
||||
|
||||
private fun findContractClassNames(scanResult: RestrictedScanResult): List<String> {
|
||||
return (scanResult.getNamesOfClassesImplementing(Contract::class) +
|
||||
scanResult.getNamesOfClassesImplementing(UpgradedContract::class) +
|
||||
// Even though UpgradedContractWithLegacyConstraint implements UpgradedContract
|
||||
// we need to specify it separately. Otherwise, classes implementing UpgradedContractWithLegacyConstraint
|
||||
// don't get picked up.
|
||||
scanResult.getNamesOfClassesImplementing(UpgradedContractWithLegacyConstraint::class))
|
||||
.distinct()
|
||||
return coreContractClasses.flatMap { scanResult.getNamesOfClassesImplementing(it) }.distinct()
|
||||
}
|
||||
|
||||
private fun findPlugins(cordappJarPath: RestrictedURL): List<SerializationWhitelist> {
|
||||
|
@ -59,7 +59,6 @@ class TraderDemoTest : IntegrationTest() {
|
||||
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser)),
|
||||
startNode(providedName = BOC_NAME, rpcUsers = listOf(bankUser))
|
||||
).map { (it.getOrThrow() as InProcess) }
|
||||
nodeA.registerInitiatedFlow(BuyerFlow::class.java)
|
||||
val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map {
|
||||
val client = CordaRPCClient(it.rpcAddress)
|
||||
client.start(demoUser.username, demoUser.password).proxy
|
||||
|
Loading…
Reference in New Issue
Block a user