Move Interest Rate related classes out of :node to reduce dependency of :node module on any specific contract. (Currently only WalletMonitorService and CashBalanceAsMetricsObserver stop me removing the compil dependency of :node on :contracts rather than :core). This has required that I modify fixing protocol to require information on what class of Oracle to use.

This commit is contained in:
Matthew Nesbit 2016-09-08 17:18:52 +01:00
parent 600c630f91
commit bf0721868e
12 changed files with 36 additions and 28 deletions

View File

@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
import com.r3corda.core.contracts.clauses.* import com.r3corda.core.contracts.clauses.*
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogicRefFactory import com.r3corda.core.protocols.ProtocolLogicRefFactory
import com.r3corda.core.transactions.TransactionBuilder import com.r3corda.core.transactions.TransactionBuilder
import com.r3corda.core.utilities.suggestInterestRateAnnouncementTimeWindow import com.r3corda.core.utilities.suggestInterestRateAnnouncementTimeWindow
@ -187,6 +188,8 @@ class FloatingRatePaymentEvent(date: LocalDate,
class InterestRateSwap() : Contract { class InterestRateSwap() : Contract {
override val legalContractReference = SecureHash.sha256("is_this_the_text_of_the_contract ? TBD") override val legalContractReference = SecureHash.sha256("is_this_the_text_of_the_contract ? TBD")
object OracleType : ServiceType("corda.interest_rates")
/** /**
* This Common area contains all the information that is not leg specific. * This Common area contains all the information that is not leg specific.
*/ */
@ -653,6 +656,9 @@ class InterestRateSwap() : Contract {
override val contract = IRS_PROGRAM_ID override val contract = IRS_PROGRAM_ID
override val oracleType: ServiceType
get() = OracleType
override val ref = common.tradeID override val ref = common.tradeID
override val participants: List<PublicKey> override val participants: List<PublicKey>

View File

@ -4,6 +4,7 @@ import com.r3corda.core.contracts.clauses.Clause
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.crypto.toStringShort import com.r3corda.core.crypto.toStringShort
import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogicRef import com.r3corda.core.protocols.ProtocolLogicRef
import com.r3corda.core.protocols.ProtocolLogicRefFactory import com.r3corda.core.protocols.ProtocolLogicRefFactory
import com.r3corda.core.serialization.OpaqueBytes import com.r3corda.core.serialization.OpaqueBytes
@ -302,6 +303,11 @@ interface FixableDealState : DealState {
*/ */
fun nextFixingOf(): FixOf? fun nextFixingOf(): FixOf?
/**
* What oracle service to use for the fixing
*/
val oracleType: ServiceType
/** /**
* Generate a fixing command for this deal and fix. * Generate a fixing command for this deal and fix.
* *

View File

@ -28,8 +28,6 @@ interface NetworkMapCache {
val networkMapNodes: List<NodeInfo> val networkMapNodes: List<NodeInfo>
/** A list of nodes that advertise a notary service */ /** A list of nodes that advertise a notary service */
val notaryNodes: List<NodeInfo> val notaryNodes: List<NodeInfo>
/** A list of nodes that advertise a rates oracle service */
val ratesOracleNodes: List<NodeInfo>
/** A list of all nodes the cache is aware of */ /** A list of all nodes the cache is aware of */
val partyNodes: List<NodeInfo> val partyNodes: List<NodeInfo>
/** Tracks changes to the network map cache */ /** Tracks changes to the network map cache */

View File

@ -8,6 +8,7 @@ import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.crypto.signWithECDSA
import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.DEFAULT_SESSION_ID import com.r3corda.core.node.services.DEFAULT_SESSION_ID
import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.protocols.ProtocolLogic
import com.r3corda.core.random63BitValue import com.r3corda.core.random63BitValue
import com.r3corda.core.seconds import com.r3corda.core.seconds
@ -374,7 +375,10 @@ object TwoPartyDealProtocol {
val newDeal = deal val newDeal = deal
val ptx = TransactionType.General.Builder(txState.notary) val ptx = TransactionType.General.Builder(txState.notary)
val addFixing = object : RatesFixProtocol(ptx, serviceHub.networkMapCache.ratesOracleNodes[0].identity, fixOf, BigDecimal.ZERO, BigDecimal.ONE) {
val oracle = serviceHub.networkMapCache.get(initiation.oracleType).first()
val addFixing = object : RatesFixProtocol(ptx, oracle.identity, fixOf, BigDecimal.ZERO, BigDecimal.ONE) {
@Suspendable @Suspendable
override fun beforeSigning(fix: Fix) { override fun beforeSigning(fix: Fix) {
newDeal.generateFix(ptx, StateAndRef(txState, handshake.payload), fix) newDeal.generateFix(ptx, StateAndRef(txState, handshake.payload), fix)
@ -423,7 +427,7 @@ object TwoPartyDealProtocol {
/** Used to set up the session between [Floater] and [Fixer] */ /** Used to set up the session between [Floater] and [Fixer] */
data class FixingSessionInitiation(val sessionID: Long, val party: Party, val sender: Party, val timeout: Duration) data class FixingSessionInitiation(val sessionID: Long, val party: Party, val sender: Party, val timeout: Duration, val oracleType: ServiceType)
/** /**
* This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing. * This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing.
@ -451,11 +455,13 @@ object TwoPartyDealProtocol {
progressTracker.nextStep() progressTracker.nextStep()
val dealToFix = serviceHub.loadState(ref) val dealToFix = serviceHub.loadState(ref)
// TODO: this is not the eventual mechanism for identifying the parties // TODO: this is not the eventual mechanism for identifying the parties
val sortedParties = (dealToFix.data as FixableDealState).parties.sortedBy { it.name } val fixableDeal = (dealToFix.data as FixableDealState)
val sortedParties = fixableDeal.parties.sortedBy { it.name }
val oracleType = fixableDeal.oracleType
if (sortedParties[0].name == serviceHub.storageService.myLegalIdentity.name) { if (sortedParties[0].name == serviceHub.storageService.myLegalIdentity.name) {
// Generate sessionID // Generate sessionID
val sessionID = random63BitValue() val sessionID = random63BitValue()
val initation = FixingSessionInitiation(sessionID, sortedParties[0], serviceHub.storageService.myLegalIdentity, timeout) val initation = FixingSessionInitiation(sessionID, sortedParties[0], serviceHub.storageService.myLegalIdentity, timeout, oracleType)
// Send initiation to other side to launch one side of the fixing protocol (the Fixer). // Send initiation to other side to launch one side of the fixing protocol (the Fixer).
send(sortedParties[1], DEFAULT_SESSION_ID, initation) send(sortedParties[1], DEFAULT_SESSION_ID, initation)

View File

@ -21,7 +21,6 @@ import com.r3corda.core.serialization.SingletonSerializeAsToken
import com.r3corda.core.serialization.deserialize import com.r3corda.core.serialization.deserialize
import com.r3corda.core.serialization.serialize import com.r3corda.core.serialization.serialize
import com.r3corda.node.services.api.RegulatorService import com.r3corda.node.services.api.RegulatorService
import com.r3corda.node.services.clientapi.NodeInterestRates
import com.r3corda.node.services.transactions.NotaryService import com.r3corda.node.services.transactions.NotaryService
import com.r3corda.node.utilities.AddOrRemove import com.r3corda.node.utilities.AddOrRemove
import rx.Observable import rx.Observable
@ -42,8 +41,6 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach
get() = get(RegulatorService.Type) get() = get(RegulatorService.Type)
override val notaryNodes: List<NodeInfo> override val notaryNodes: List<NodeInfo>
get() = get(NotaryService.Type) get() = get(NotaryService.Type)
override val ratesOracleNodes: List<NodeInfo>
get() = get(NodeInterestRates.Type)
override val partyNodes: List<NodeInfo> override val partyNodes: List<NodeInfo>
get() = registeredNodes.map { it.value } get() = registeredNodes.map { it.value }
private val _changed = PublishSubject.create<MapChange>() private val _changed = PublishSubject.create<MapChange>()

View File

@ -1,5 +1,4 @@
# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry # Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry
com.r3corda.node.services.clientapi.FixingSessionInitiation$Plugin com.r3corda.node.services.clientapi.FixingSessionInitiation$Plugin
com.r3corda.node.services.clientapi.NodeInterestRates$Plugin
com.r3corda.node.services.NotaryChange$Plugin com.r3corda.node.services.NotaryChange$Plugin
com.r3corda.node.services.persistence.DataVending$Plugin com.r3corda.node.services.persistence.DataVending$Plugin

View File

@ -21,7 +21,7 @@ import com.r3corda.demos.utilities.putJson
import com.r3corda.demos.utilities.uploadFile import com.r3corda.demos.utilities.uploadFile
import com.r3corda.node.internal.AbstractNode import com.r3corda.node.internal.AbstractNode
import com.r3corda.node.internal.Node import com.r3corda.node.internal.Node
import com.r3corda.node.services.clientapi.NodeInterestRates import com.r3corda.demos.api.NodeInterestRates
import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.config.NodeConfigurationFromConfig import com.r3corda.node.services.config.NodeConfigurationFromConfig
import com.r3corda.node.services.messaging.ArtemisMessagingClient import com.r3corda.node.services.messaging.ArtemisMessagingClient

View File

@ -1,28 +1,23 @@
package com.r3corda.demos package com.r3corda.demos
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3corda.contracts.InterestRateSwap
import com.r3corda.contracts.asset.Cash import com.r3corda.contracts.asset.Cash
import com.r3corda.core.contracts.* import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.Party
import com.r3corda.core.logElapsedTime import com.r3corda.core.logElapsedTime
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.ServiceType
import com.r3corda.testing.node.makeTestDataSourceProperties
import com.r3corda.core.serialization.deserialize
import com.r3corda.core.utilities.Emoji import com.r3corda.core.utilities.Emoji
import com.r3corda.core.utilities.LogHelper import com.r3corda.core.utilities.LogHelper
import com.r3corda.demos.api.NodeInterestRates
import com.r3corda.node.internal.Node import com.r3corda.node.internal.Node
import com.r3corda.node.services.clientapi.NodeInterestRates
import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.messaging.ArtemisMessagingClient import com.r3corda.node.services.messaging.ArtemisMessagingClient
import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.services.transactions.NotaryService
import com.r3corda.protocols.RatesFixProtocol import com.r3corda.protocols.RatesFixProtocol
import com.r3corda.testing.node.makeTestDataSourceProperties
import joptsimple.OptionParser import joptsimple.OptionParser
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.math.BigDecimal import java.math.BigDecimal
import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
import java.util.* import java.util.*
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -78,7 +73,7 @@ fun main(args: Array<String>) {
advertisedServices, DemoClock()).setup().start() } advertisedServices, DemoClock()).setup().start() }
node.networkMapRegistrationFuture.get() node.networkMapRegistrationFuture.get()
val notaryNode = node.services.networkMapCache.notaryNodes[0] val notaryNode = node.services.networkMapCache.notaryNodes[0]
val rateOracle = node.services.networkMapCache.ratesOracleNodes[0] val rateOracle = node.services.networkMapCache.get(InterestRateSwap.OracleType).first()
// Make a garbage transaction that includes a rate fix. // Make a garbage transaction that includes a rate fix.
val tx = TransactionType.General.Builder(notaryNode.identity) val tx = TransactionType.General.Builder(notaryNode.identity)

View File

@ -1,4 +1,4 @@
package com.r3corda.node.services.clientapi package com.r3corda.demos.api
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import com.r3corda.core.RetryableException import com.r3corda.core.RetryableException
@ -49,7 +49,7 @@ object NodeInterestRates {
*/ */
class Plugin : CordaPluginRegistry() { class Plugin : CordaPluginRegistry() {
override val requiredProtocols: Map<String, Set<String>> = mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(Duration::class.java.name, StateRef::class.java.name))) override val requiredProtocols: Map<String, Set<String>> = mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(Duration::class.java.name, StateRef::class.java.name)))
override val servicePlugins: List<Class<*>> = listOf(NodeInterestRates.Service::class.java) override val servicePlugins: List<Class<*>> = listOf(Service::class.java)
} }
/** /**

View File

@ -10,7 +10,7 @@ import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.protocols.ProtocolLogic
import com.r3corda.core.then import com.r3corda.core.then
import com.r3corda.core.utilities.ProgressTracker import com.r3corda.core.utilities.ProgressTracker
import com.r3corda.node.services.clientapi.NodeInterestRates import com.r3corda.demos.api.NodeInterestRates
import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.services.transactions.SimpleNotaryService import com.r3corda.node.services.transactions.SimpleNotaryService
@ -109,7 +109,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
object RatesOracleFactory : MockNetwork.Factory { object RatesOracleFactory : MockNetwork.Factory {
override fun create(dir: Path, config: com.r3corda.node.services.config.NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, override fun create(dir: Path, config: com.r3corda.node.services.config.NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
require(advertisedServices.contains(com.r3corda.node.services.clientapi.NodeInterestRates.Type)) require(advertisedServices.contains(NodeInterestRates.Type))
val cfg = object : com.r3corda.node.services.config.NodeConfiguration { val cfg = object : com.r3corda.node.services.config.NodeConfiguration {
override val myLegalName: String = "Rates Service Provider" override val myLegalName: String = "Rates Service Provider"
override val exportJMXto: String = "" override val exportJMXto: String = ""
@ -121,7 +121,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
return object : SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair) { return object : SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
override fun start(): MockNetwork.MockNode { override fun start(): MockNetwork.MockNode {
super.start() super.start()
findService<com.r3corda.node.services.clientapi.NodeInterestRates.Service>().upload(javaClass.getResourceAsStream("example.rates.txt")) findService<NodeInterestRates.Service>().upload(javaClass.getResourceAsStream("example.rates.txt"))
return this return this
} }
} }
@ -156,7 +156,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
= network.createNode(networkMap.info.address, nodeFactory = NotaryNodeFactory, advertisedServices = com.r3corda.node.services.transactions.SimpleNotaryService.Type) as SimulatedNode = network.createNode(networkMap.info.address, nodeFactory = NotaryNodeFactory, advertisedServices = com.r3corda.node.services.transactions.SimpleNotaryService.Type) as SimulatedNode
val regulators: List<SimulatedNode> = listOf(network.createNode(networkMap.info.address, start = false, nodeFactory = RegulatorFactory) as SimulatedNode) val regulators: List<SimulatedNode> = listOf(network.createNode(networkMap.info.address, start = false, nodeFactory = RegulatorFactory) as SimulatedNode)
val ratesOracle: SimulatedNode val ratesOracle: SimulatedNode
= network.createNode(networkMap.info.address, start = false, nodeFactory = RatesOracleFactory, advertisedServices = com.r3corda.node.services.clientapi.NodeInterestRates.Type) as SimulatedNode = network.createNode(networkMap.info.address, start = false, nodeFactory = RatesOracleFactory, advertisedServices = NodeInterestRates.Type) as SimulatedNode
// All nodes must be in one of these two lists for the purposes of the visualiser tool. // All nodes must be in one of these two lists for the purposes of the visualiser tool.
val serviceProviders: List<SimulatedNode> = listOf(notary, ratesOracle, networkMap) val serviceProviders: List<SimulatedNode> = listOf(notary, ratesOracle, networkMap)

View File

@ -1,5 +1,6 @@
# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry # Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry
com.r3corda.demos.IRSDemoPluginRegistry com.r3corda.demos.IRSDemoPluginRegistry
com.r3corda.demos.api.NodeInterestRates$Plugin
com.r3corda.demos.protocols.AutoOfferProtocol$Plugin com.r3corda.demos.protocols.AutoOfferProtocol$Plugin
com.r3corda.demos.protocols.ExitServerProtocol$Plugin com.r3corda.demos.protocols.ExitServerProtocol$Plugin
com.r3corda.demos.protocols.UpdateBusinessDayProtocol$Plugin com.r3corda.demos.protocols.UpdateBusinessDayProtocol$Plugin

View File

@ -1,4 +1,4 @@
package com.r3corda.node.services package com.r3corda.core.testing
import com.r3corda.contracts.asset.CASH import com.r3corda.contracts.asset.CASH
import com.r3corda.contracts.asset.Cash import com.r3corda.contracts.asset.Cash
@ -14,7 +14,7 @@ import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.utilities.DUMMY_NOTARY import com.r3corda.core.utilities.DUMMY_NOTARY
import com.r3corda.core.utilities.LogHelper import com.r3corda.core.utilities.LogHelper
import com.r3corda.testing.node.MockNetwork import com.r3corda.testing.node.MockNetwork
import com.r3corda.node.services.clientapi.NodeInterestRates import com.r3corda.demos.api.NodeInterestRates
import com.r3corda.protocols.RatesFixProtocol import com.r3corda.protocols.RatesFixProtocol
import com.r3corda.testing.ALICE_PUBKEY import com.r3corda.testing.ALICE_PUBKEY
import com.r3corda.testing.MEGA_CORP import com.r3corda.testing.MEGA_CORP