diff --git a/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt b/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt index a6b6a36b03..61dab01549 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt @@ -11,10 +11,13 @@ import kotlin.annotation.AnnotationTarget.CLASS * * The service class has to implement [net.corda.core.serialization.SerializeAsToken] to ensure correct usage within flows. * (If possible extend [net.corda.core.serialization.SingletonSerializeAsToken] instead as it removes the boilerplate.) + * + * The annotated class should expose its [ServiceType] via a public static field named `type`, so that the service is + * only loaded in nodes that declare the type in their advertisedServices. */ // TODO Handle the singleton serialisation of Corda services automatically, removing the need to implement SerializeAsToken // TODO Currently all nodes which load the plugin will attempt to load the service even if it's not revelant to them. The // underlying problem is that the entire CorDapp jar is used as a dependency, when in fact it's just the client-facing // bit of the CorDapp that should be depended on (e.g. the initiating flows). @Target(CLASS) -annotation class CordaService \ No newline at end of file +annotation class CordaService diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index 754026fa45..a266487d1a 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -43,8 +43,8 @@ dependencies { exclude group: "bouncycastle" } - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') } mainClassName = "net.corda.docs.ClientRpcTutorialKt" 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 353b15a551..d81753a44f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -268,16 +268,31 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, private fun installCordaServices(scanResult: ScanResult): List { return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class).mapNotNull { - try { - installCordaService(it) - } catch (e: NoSuchMethodException) { - log.error("${it.name}, as a Corda service, must have a constructor with a single parameter " + - "of type ${PluginServiceHub::class.java.name}") - null - } catch (e: Exception) { - log.error("Unable to install Corda service ${it.name}", e) - null - } + tryInstallCordaService(it) + } + } + + private fun tryInstallCordaService(serviceClass: Class): T? { + /** TODO: This mechanism may get replaced by a different one, see comments on [CordaService]. */ + val typeField = try { + serviceClass.getField("type") + } catch (e: NoSuchFieldException) { + null + } + if (typeField == null) { + log.warn("${serviceClass.name} does not have a type field, optimistically proceeding with install.") + } else if (info.serviceIdentities(typeField.get(null) as ServiceType).isEmpty()) { + return null + } + return try { + installCordaService(serviceClass) + } catch (e: NoSuchMethodException) { + log.error("${serviceClass.name}, as a Corda service, must have a constructor with a single parameter " + + "of type ${PluginServiceHub::class.java.name}") + null + } catch (e: Exception) { + log.error("Unable to install Corda service ${serviceClass.name}", e) + null } } diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt index 133b674307..f69779844f 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt @@ -18,6 +18,7 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize +import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor import net.corda.node.services.api.AbstractNodeService import net.corda.node.services.api.ServiceHubInternal @@ -135,10 +136,10 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal, val minimumPlatformVersion: Int) : NetworkMapService, AbstractNodeService(services) { companion object { /** - * Maximum credible size for a registration request. Generally requests are around 500-600 bytes, so this gives a + * Maximum credible size for a registration request. Generally requests are around 2000-6000 bytes, so this gives a * 10 times overhead. */ - private const val MAX_SIZE_REGISTRATION_REQUEST_BYTES = 5500 + private const val MAX_SIZE_REGISTRATION_REQUEST_BYTES = 40000 private val logger = loggerFor() } @@ -232,7 +233,9 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal, } private fun processRegistrationRequest(request: RegistrationRequest): RegistrationResponse { - if (request.wireReg.raw.size > MAX_SIZE_REGISTRATION_REQUEST_BYTES) { + val requestSize = request.wireReg.raw.size + logger.debug { "Received registration request of size: $requestSize" } + if (requestSize > MAX_SIZE_REGISTRATION_REQUEST_BYTES) { return RegistrationResponse("Request is too big") } diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index ec2d727ff0..7b7a02e5b7 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -26,8 +26,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':test-utils') diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index c369d8100d..60455c299e 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -26,8 +26,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':client:jfx') compile project(':client:rpc') diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 7ef056ceb5..00f36bf82f 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -30,8 +30,8 @@ dependencies { testCompile "org.assertj:assertj-core:${assertj_version}" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':finance') compile project(':webserver') diff --git a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt index 56a45f388d..9639272865 100644 --- a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt +++ b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt @@ -39,7 +39,7 @@ class IRSDemoTest : IntegrationTestCategory { systemProperties = mapOf("net.corda.node.cordapp.scan.package" to "net.corda.irs")) { val (controller, nodeA, nodeB) = Futures.allAsList( - startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))), + startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))), startNode(DUMMY_BANK_A.name, rpcUsers = listOf(rpcUser)), startNode(DUMMY_BANK_B.name) ).getOrThrow() diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt index 103f016a3c..7233173531 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt @@ -17,7 +17,7 @@ import net.corda.node.services.transactions.SimpleNotaryService fun main(args: Array) { driver(dsl = { val (controller, nodeA, nodeB) = Futures.allAsList( - startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))), + startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))), startNode(DUMMY_BANK_A.name), startNode(DUMMY_BANK_B.name) ).getOrThrow() diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt index f4cc09ea4c..a2ef62ec66 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt @@ -49,8 +49,6 @@ import kotlin.collections.set * for signing. */ object NodeInterestRates { - val type = ServiceType.corda.getSubType("interest_rates") - // DOCSTART 2 @InitiatedBy(RatesFixFlow.FixSignFlow::class) class FixSignHandler(val otherParty: Party) : FlowLogic() { @@ -95,6 +93,11 @@ object NodeInterestRates { ) // DOCEND 3 + companion object { + @JvmField + val type = ServiceType.corda.getSubType("interest_rates") + } + private object Table : JDBCHashedTable("demo_interest_rate_fixes") { val name = varchar("index_name", length = 255) val forDay = localDate("for_day") diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt index 5674787976..d9a9abe266 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt @@ -10,6 +10,7 @@ import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.TransactionBuilder +import net.corda.irs.api.NodeInterestRates import net.corda.irs.flows.FixingFlow import net.corda.irs.utilities.suggestInterestRateAnnouncementTimeWindow import org.apache.commons.jexl3.JexlBuilder @@ -190,10 +191,6 @@ class FloatingRatePaymentEvent(date: LocalDate, class InterestRateSwap : Contract { override val legalContractReference = SecureHash.sha256("is_this_the_text_of_the_contract ? TBD") - companion object { - val oracleType = ServiceType.corda.getSubType("interest_rates") - } - /** * This Common area contains all the information that is not leg specific. */ @@ -665,7 +662,7 @@ class InterestRateSwap : Contract { override val contract = IRS_PROGRAM_ID override val oracleType: ServiceType - get() = InterestRateSwap.oracleType + get() = NodeInterestRates.Oracle.type override val ref = common.tradeID diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt index c2f93f75f9..966c9709da 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt @@ -121,7 +121,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, advertisedServices: Set, id: Int, overrideServices: Map?, entropyRoot: BigInteger): MockNetwork.MockNode { - require(advertisedServices.containsType(NodeInterestRates.type)) + require(advertisedServices.containsType(NodeInterestRates.Oracle.type)) val cfg = TestNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = RATES_SERVICE_NAME, @@ -166,7 +166,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, = network.createNode(networkMap.info.address, nodeFactory = NotaryNodeFactory, advertisedServices = ServiceInfo(SimpleNotaryService.type)) as SimulatedNode val regulators: List = listOf(network.createNode(networkMap.info.address, start = false, nodeFactory = RegulatorFactory) as SimulatedNode) val ratesOracle: SimulatedNode - = network.createNode(networkMap.info.address, start = false, nodeFactory = RatesOracleFactory, advertisedServices = ServiceInfo(NodeInterestRates.type)) as SimulatedNode + = network.createNode(networkMap.info.address, start = false, nodeFactory = RatesOracleFactory, advertisedServices = ServiceInfo(NodeInterestRates.Oracle.type)) as SimulatedNode // All nodes must be in one of these two lists for the purposes of the visualiser tool. val serviceProviders: List = listOf(notary, ratesOracle, networkMap) diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt index c1ad4256ec..a91ac74f74 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt @@ -209,7 +209,7 @@ class NodeInterestRatesTest { fun `network tearoff`() { val net = MockNetwork() val n1 = net.createNotaryNode() - val n2 = net.createNode(n1.info.address, advertisedServices = ServiceInfo(NodeInterestRates.type)) + val n2 = net.createNode(n1.info.address, advertisedServices = ServiceInfo(NodeInterestRates.Oracle.type)) n2.registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java) n2.registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java) n2.database.transaction { @@ -217,7 +217,7 @@ class NodeInterestRatesTest { } val tx = TransactionType.General.Builder(null) val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") - val oracle = n2.info.serviceIdentities(NodeInterestRates.type).first() + val oracle = n2.info.serviceIdentities(NodeInterestRates.Oracle.type).first() val flow = FilteredRatesFlow(tx, oracle, fixOf, "0.675".bd, "0.1".bd) LogHelper.setLevel("rates") net.runNetwork() diff --git a/samples/network-visualiser/build.gradle b/samples/network-visualiser/build.gradle index 7d95c04a9a..8170451d88 100644 --- a/samples/network-visualiser/build.gradle +++ b/samples/network-visualiser/build.gradle @@ -12,8 +12,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':finance') testCompile project(':test-utils') diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index c526c4ab9b..938b38cfd4 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -18,8 +18,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':client:jfx') compile project(':client:rpc') diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 95c8d55cf5..6aa9ee1434 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -31,8 +31,8 @@ dependencies { testCompile "org.assertj:assertj-core:${assertj_version}" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':node') compile project(':webserver') diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 58b96b7cf7..c7213addf5 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -27,8 +27,8 @@ dependencies { testCompile "org.assertj:assertj-core:${assertj_version}" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':finance') compile project(':test-utils')