Cleaned up the trader, irs and simm demos so that things like the driver are used in test so that the node module isn't a compile dependency.

This has resulted in some classes moving into core, such as ClockUtils and FiberBox.
This commit is contained in:
Shams Asari 2017-06-14 15:59:17 +01:00
parent 4195adfb7b
commit 155bb029da
29 changed files with 159 additions and 159 deletions

View File

@ -409,10 +409,10 @@ interface KeyManagementService {
fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey
}
// TODO: Move to a more appropriate location
/**
* An interface that denotes a service that can accept file uploads.
*/
// TODO This is no longer used and can be removed
interface FileUploader {
/**
* Accepts the data in the given input stream, and returns some sort of useful return message that will be sent

View File

@ -4,9 +4,8 @@ import net.corda.core.node.services.FileUploader
/**
* A service that implements AcceptsFileUpload can have new binary data provided to it via an HTTP upload.
*
* TODO: In future, also accept uploads over the MQ interface too.
*/
// TODO This is no longer used and can be removed
interface AcceptsFileUpload : FileUploader {
/** A string that prefixes the URLs, e.g. "attachments" or "interest-rates". Should be OK for URLs. */
val dataTypePrefix: String

View File

@ -33,8 +33,8 @@ import kotlin.concurrent.withLock
* to be temporary. In addition, it's enitrely possible to envisage a time when we want public [net.corda.core.flows.FlowLogic]
* implementations to be able to wait for some condition to become true outside of message send/receive. At that point
* we may revisit this implementation and indeed the whole model for this, when we understand that requirement more fully.
*
*/
// TODO This is no longer used and can be removed
class FiberBox<out T>(private val content: T, private val lock: Lock = ReentrantLock()) {
private var mutated: SettableFuture<Boolean>? = null

View File

@ -26,8 +26,6 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Corda integration dependencies
compile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -35,7 +33,6 @@ dependencies {
compile project(':core')
compile project(':finance')
compile project(':webserver')
compile project(':test-utils')
// Javax is required for webapis
compile "org.glassfish.jersey.core:jersey-server:${jersey_version}"
@ -43,6 +40,10 @@ dependencies {
// Cordapp dependencies
// Specify your cordapp's dependencies below, including dependent cordapps
compile "com.squareup.okhttp3:okhttp:$okhttp_version"
testCompile project(':test-utils')
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
}
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {

View File

@ -4,7 +4,6 @@ import com.google.common.net.HostAndPort
import com.google.common.util.concurrent.Futures
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.getOrThrow
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.services.ServiceInfo
import net.corda.core.toFuture
import net.corda.core.utilities.DUMMY_BANK_A
@ -12,20 +11,17 @@ import net.corda.core.utilities.DUMMY_BANK_B
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.irs.api.NodeInterestRates
import net.corda.irs.contract.InterestRateSwap
import net.corda.irs.utilities.postJson
import net.corda.irs.utilities.putJson
import net.corda.irs.utilities.uploadFile
import net.corda.testing.driver.driver
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.IntegrationTestCategory
import net.corda.testing.driver.driver
import net.corda.testing.http.HttpApi
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import rx.Observable
import rx.observables.BlockingObservable
import java.net.URL
import java.time.Duration
import java.time.LocalDate
@ -56,7 +52,7 @@ class IRSDemoTest : IntegrationTestCategory {
println("All webservers started")
val (controllerApi, nodeAApi, nodeBApi) = listOf(controller, nodeA, nodeB).zip(listOf(controllerAddr, nodeAAddr, nodeBAddr)).map {
val (_, nodeAApi, nodeBApi) = listOf(controller, nodeA, nodeB).zip(listOf(controllerAddr, nodeAAddr, nodeBAddr)).map {
val mapper = net.corda.jackson.JacksonSupport.createDefaultMapper(it.first.rpc)
HttpApi.fromHostAndPort(it.second, "api/irs", mapper = mapper)
}
@ -108,7 +104,7 @@ class IRSDemoTest : IntegrationTestCategory {
private fun runUploadRates(host: HostAndPort) {
println("Running upload rates against $host")
val fileContents = loadResourceFile("net/corda/irs/simulation/example.rates.txt")
val url = URL("http://$host/upload/interest-rates")
val url = URL("http://$host/api/irs/fixes")
assertThat(uploadFile(url, fileContents)).isTrue()
}

View File

@ -8,11 +8,7 @@ import net.corda.core.messaging.startFlow
import net.corda.core.utilities.loggerFor
import net.corda.irs.contract.InterestRateSwap
import net.corda.irs.flows.AutoOfferFlow
import net.corda.irs.flows.UpdateBusinessDayFlow
import java.net.URI
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
@ -28,8 +24,6 @@ import javax.ws.rs.core.Response
*
* TODO: where we currently refer to singular external deal reference, of course this could easily be multiple identifiers e.g. CUSIP, ISIN.
*
* GET /api/irs/demodate - return the current date as viewed by the system in YYYY-MM-DD format.
* PUT /api/irs/demodate - put date in format YYYY-MM-DD to advance the current date as viewed by the system and
* simulate any associated business processing (currently fixing).
*
* TODO: replace simulated date advancement with business event based implementation
@ -88,28 +82,4 @@ class InterestRateSwapAPI(val rpc: CordaRPCOps) {
return Response.ok().entity(deal).build()
}
}
@PUT
@Path("demodate")
@Consumes(MediaType.APPLICATION_JSON)
fun storeDemoDate(newDemoDate: LocalDate): Response {
val priorDemoDate = fetchDemoDate()
// Can only move date forwards
if (newDemoDate.isAfter(priorDemoDate)) {
// TODO: Remove this suppress when we upgrade to kotlin 1.1 or when JetBrain fixes the bug.
@Suppress("UNSUPPORTED_FEATURE")
rpc.startFlow(UpdateBusinessDayFlow::Broadcast, newDemoDate).returnValue.getOrThrow()
return Response.ok().build()
}
val msg = "demodate is already $priorDemoDate and can only be updated with a later date"
logger.error("Attempt to set demodate to $newDemoDate but $msg")
return Response.status(Response.Status.CONFLICT).entity(msg).build()
}
@GET
@Path("demodate")
@Produces(MediaType.APPLICATION_JSON)
fun fetchDemoDate(): LocalDate {
return LocalDateTime.ofInstant(rpc.currentNodeTime(), ZoneId.systemDefault()).toLocalDate()
}
}

View File

@ -5,17 +5,19 @@ import net.corda.contracts.BusinessCalendar
import net.corda.contracts.Fix
import net.corda.contracts.FixOf
import net.corda.contracts.Tenor
import net.corda.contracts.math.CubicSplineInterpolator
import net.corda.contracts.math.Interpolator
import net.corda.contracts.math.InterpolatorFactory
import net.corda.core.RetryableException
import net.corda.core.ThreadBox
import net.corda.core.contracts.Command
import net.corda.core.crypto.DigitalSignature
import net.corda.core.crypto.MerkleTreeException
import net.corda.core.crypto.keys
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.contracts.math.CubicSplineInterpolator
import net.corda.contracts.math.Interpolator
import net.corda.contracts.math.InterpolatorFactory
import net.corda.core.node.PluginServiceHub
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.CordaService
@ -25,20 +27,12 @@ import net.corda.core.transactions.FilteredTransaction
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.irs.flows.RatesFixFlow
import net.corda.node.services.api.AcceptsFileUpload
import net.corda.node.utilities.AbstractJDBCHashSet
import net.corda.node.utilities.FiberBox
import net.corda.node.utilities.JDBCHashedTable
import net.corda.node.utilities.localDate
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.statements.InsertStatement
import java.io.InputStream
import java.math.BigDecimal
import java.security.PublicKey
import java.time.Instant
import java.time.LocalDate
import java.util.*
import javax.annotation.concurrent.ThreadSafe
import kotlin.collections.HashSet
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
@ -76,7 +70,7 @@ object NodeInterestRates {
val request = receive<RatesFixFlow.QueryRequest>(otherParty).unwrap { it }
progressTracker.currentStep = RECEIVED
val oracle = serviceHub.cordaService(Oracle::class.java)
val answers = oracle.query(request.queries, request.deadline)
val answers = oracle.query(request.queries)
progressTracker.currentStep = SENDING
send(otherParty, answers)
}
@ -91,7 +85,7 @@ object NodeInterestRates {
@ThreadSafe
// DOCSTART 3
@CordaService
class Oracle(val identity: Party, private val signingKey: PublicKey, val services: ServiceHub) : AcceptsFileUpload, SingletonSerializeAsToken() {
class Oracle(val identity: Party, private val signingKey: PublicKey, val services: ServiceHub) : SingletonSerializeAsToken() {
constructor(services: PluginServiceHub) : this(
services.myInfo.serviceIdentities(type).first(),
services.myInfo.serviceIdentities(type).first().owningKey.keys.first { services.keyManagementService.keys.contains(it) },
@ -104,56 +98,34 @@ object NodeInterestRates {
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")
val ofTenor = varchar("of_tenor", length = 16)
val value = decimal("value", scale = 20, precision = 16)
}
private class InnerState {
val fixes = object : AbstractJDBCHashSet<Fix, Table>(Table) {
override fun elementFromRow(row: ResultRow): Fix {
return Fix(FixOf(row[table.name], row[table.forDay], Tenor(row[table.ofTenor])), row[table.value])
}
override fun addElementToInsert(insert: InsertStatement, entry: Fix, finalizables: MutableList<() -> Unit>) {
insert[table.name] = entry.of.name
insert[table.forDay] = entry.of.forDay
insert[table.ofTenor] = entry.of.ofTenor.name
insert[table.value] = entry.value
}
}
// TODO Update this to use a database once we have an database API
val fixes = HashSet<Fix>()
var container: FixContainer = FixContainer(fixes)
}
private val mutex = FiberBox(InnerState())
private val mutex = ThreadBox(InnerState())
var knownFixes: FixContainer
set(value) {
require(value.size > 0)
mutex.write {
mutex.locked {
fixes.clear()
fixes.addAll(value.fixes)
container = value
}
}
get() = mutex.read { container }
get() = mutex.locked { container }
// Make this the last bit of initialisation logic so fully constructed when entered into instances map
init {
require(signingKey in identity.owningKey.keys)
}
/**
* This method will now wait until the given deadline if the fix for the given [FixOf] is not immediately
* available. To implement this, [FiberBox.readWithDeadline] will loop if the deadline is not reached and we throw
* [UnknownFix] as it implements [RetryableException] which has special meaning to this function.
*/
@Suspendable
fun query(queries: List<FixOf>, deadline: Instant): List<Fix> {
fun query(queries: List<FixOf>): List<Fix> {
require(queries.isNotEmpty())
return mutex.readWithDeadline(services.clock, deadline) {
return mutex.locked {
val answers: List<Fix?> = queries.map { container[it] }
val firstNull = answers.indexOf(null)
if (firstNull != -1) {
@ -204,20 +176,21 @@ object NodeInterestRates {
}
// DOCEND 1
// File upload support
override val dataTypePrefix = "interest-rates"
override val acceptableFileExtensions = listOf(".rates", ".txt")
override fun upload(file: InputStream): String {
val fixes = parseFile(file.bufferedReader().readText())
knownFixes = fixes
return "Interest rates oracle accepted ${fixes.size} new interest rate fixes"
fun uploadFixes(s: String) {
knownFixes = parseFile(s)
}
}
// TODO: can we split into two? Fix not available (retryable/transient) and unknown (permanent)
class UnknownFix(val fix: FixOf) : RetryableException("Unknown fix: $fix")
// Upload the raw fix data via RPC. In a real system the oracle data would be taken from a database.
@StartableByRPC
class UploadFixesFlow(val s: String) : FlowLogic<Unit>() {
@Suspendable
override fun call() = serviceHub.cordaService(Oracle::class.java).uploadFixes(s)
}
/** Fix container, for every fix name & date pair stores a tenor to interest rate map - [InterpolatingRateMap] */
class FixContainer(val fixes: Set<Fix>, val factory: InterpolatorFactory = CubicSplineInterpolator) {
private val container = buildContainer(fixes)
@ -298,17 +271,21 @@ object NodeInterestRates {
map(String::trim).
// Filter out comment and empty lines.
filterNot { it.startsWith("#") || it.isBlank() }.
map { parseFix(it) }.
map(this::parseFix).
toSet()
return FixContainer(fixes)
}
/** Parses a string of the form "LIBOR 16-March-2016 1M = 0.678" into a [Fix] */
fun parseFix(s: String): Fix {
private fun parseFix(s: String): Fix {
try {
val (key, value) = s.split('=').map(String::trim)
val of = parseFixOf(key)
val rate = BigDecimal(value)
return Fix(of, rate)
} catch (e: Exception) {
throw IllegalArgumentException("Unable to parse fix $s: ${e.message}", e)
}
}
/** Parses a string of the form "LIBOR 16-March-2016 1M" into a [FixOf] */

View File

@ -13,9 +13,7 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.irs.flows.RatesFixFlow.FixOutOfRange
import net.corda.irs.utilities.suggestInterestRateAnnouncementTimeWindow
import java.math.BigDecimal
import java.time.Instant
import java.util.*
import java.util.function.Predicate
@ -48,7 +46,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder,
class FixOutOfRange(@Suppress("unused") val byAmount: BigDecimal) : Exception("Fix out of range by $byAmount")
@CordaSerializable
data class QueryRequest(val queries: List<FixOf>, val deadline: Instant)
data class QueryRequest(val queries: List<FixOf>)
@CordaSerializable
data class SignRequest(val ftx: FilteredTransaction)
@ -99,9 +97,8 @@ open class RatesFixFlow(protected val tx: TransactionBuilder,
class FixQueryFlow(val fixOf: FixOf, val oracle: Party) : FlowLogic<Fix>() {
@Suspendable
override fun call(): Fix {
val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.name.toString(), fixOf.forDay).untilTime!!
// TODO: add deadline to receive
val resp = sendAndReceive<ArrayList<Fix>>(oracle, QueryRequest(listOf(fixOf), deadline))
val resp = sendAndReceive<ArrayList<Fix>>(oracle, QueryRequest(listOf(fixOf)))
return resp.unwrap {
val fix = it.first()

View File

@ -1,6 +1,9 @@
package net.corda.irs.utilities
import okhttp3.*
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import java.net.URL
import java.util.concurrent.TimeUnit
@ -24,10 +27,7 @@ fun postJson(url: URL, data: String): Boolean {
}
fun uploadFile(url: URL, file: String): Boolean {
val body = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("rates", "net/corda/irs/simulation/example.rates.txt", RequestBody.create(MediaType.parse("text/plain"), file))
.build()
val body = RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), file)
return makeRequest(Request.Builder().url(url).post(body).build())
}

View File

@ -4,7 +4,6 @@ package net.corda.irs
import com.google.common.net.HostAndPort
import joptsimple.OptionParser
import net.corda.irs.api.IRSDemoClientApi
import kotlin.system.exitProcess
enum class Role {

View File

@ -1,4 +1,4 @@
package net.corda.irs.api
package net.corda.irs
import com.google.common.net.HostAndPort
import net.corda.irs.utilities.uploadFile
@ -25,7 +25,7 @@ class IRSDemoClientApi(private val hostAndPort: HostAndPort) {
// TODO: Add uploading of files to the HTTP API
fun runUploadRates() {
val fileContents = IOUtils.toString(Thread.currentThread().contextClassLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt"), Charsets.UTF_8.name())
val url = URL("http://$hostAndPort/upload/interest-rates")
val url = URL("http://$hostAndPort/api/irs/fixes")
check(uploadFile(url, fileContents))
println("Rates successfully uploaded!")
}

View File

@ -0,0 +1,55 @@
package net.corda.irs.api
import net.corda.core.getOrThrow
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.loggerFor
import net.corda.irs.flows.UpdateBusinessDayFlow
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
/**
* GET /api/irs/demodate - return the current date as viewed by the system in YYYY-MM-DD format.
* PUT /api/irs/demodate - put date in format YYYY-MM-DD to advance the current date as viewed by the system and
* POST /api/irs/fixes - store the fixing data as a text file
*/
@Path("irs")
class InterestRatesSwapDemoAPI(val rpc: CordaRPCOps) {
companion object {
private val logger = loggerFor<InterestRatesSwapDemoAPI>()
}
@PUT
@Path("demodate")
@Consumes(MediaType.APPLICATION_JSON)
fun storeDemoDate(newDemoDate: LocalDate): Response {
val priorDemoDate = fetchDemoDate()
// Can only move date forwards
if (newDemoDate.isAfter(priorDemoDate)) {
rpc.startFlow(UpdateBusinessDayFlow::Broadcast, newDemoDate).returnValue.getOrThrow()
return Response.ok().build()
}
val msg = "demodate is already $priorDemoDate and can only be updated with a later date"
logger.error("Attempt to set demodate to $newDemoDate but $msg")
return Response.status(Response.Status.CONFLICT).entity(msg).build()
}
@GET
@Path("demodate")
@Produces(MediaType.APPLICATION_JSON)
fun fetchDemoDate(): LocalDate {
return LocalDateTime.ofInstant(rpc.currentNodeTime(), ZoneId.systemDefault()).toLocalDate()
}
@POST
@Path("fixes")
@Consumes(MediaType.TEXT_PLAIN)
fun storeFixes(file: String): Response {
rpc.startFlow(NodeInterestRates::UploadFixesFlow, file).returnValue.getOrThrow()
return Response.ok().build()
}
}

View File

@ -1,4 +1,4 @@
package net.corda.irs.testing
package net.corda.irs.api
import net.corda.contracts.Fix
import net.corda.contracts.FixOf
@ -18,7 +18,6 @@ import net.corda.core.utilities.ALICE
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.core.utilities.LogHelper
import net.corda.core.utilities.ProgressTracker
import net.corda.irs.api.NodeInterestRates
import net.corda.irs.flows.RatesFixFlow
import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
@ -54,8 +53,6 @@ class NodeInterestRatesTest {
val DUMMY_CASH_ISSUER_KEY = generateKeyPair()
val DUMMY_CASH_ISSUER = Party(X500Name("CN=Cash issuer,O=R3,OU=corda,L=London,C=UK"), DUMMY_CASH_ISSUER_KEY.public)
val dummyServices = MockServices(DUMMY_CASH_ISSUER_KEY, MEGA_CORP_KEY)
val clock get() = dummyServices.clock
lateinit var oracle: NodeInterestRates.Oracle
lateinit var dataSource: Closeable
lateinit var database: Database
@ -75,7 +72,11 @@ class NodeInterestRatesTest {
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction {
oracle = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY.public, dummyServices).apply { knownFixes = TEST_DATA }
oracle = NodeInterestRates.Oracle(
MEGA_CORP,
MEGA_CORP_KEY.public,
MockServices(DUMMY_CASH_ISSUER_KEY, MEGA_CORP_KEY)
).apply { knownFixes = TEST_DATA }
}
}
@ -88,7 +89,7 @@ class NodeInterestRatesTest {
fun `query successfully`() {
database.transaction {
val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
val res = oracle.query(listOf(q), clock.instant())
val res = oracle.query(listOf(q))
assertEquals(1, res.size)
assertEquals("0.678".bd, res[0].value)
assertEquals(q, res[0].of)
@ -100,7 +101,7 @@ class NodeInterestRatesTest {
database.transaction {
val q1 = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")
val q2 = NodeInterestRates.parseFixOf("LIBOR 2016-03-15 1M")
val e = assertFailsWith<NodeInterestRates.UnknownFix> { oracle.query(listOf(q1, q2), clock.instant()) }
val e = assertFailsWith<NodeInterestRates.UnknownFix> { oracle.query(listOf(q1, q2)) }
assertEquals(e.fix, q2)
}
}
@ -109,7 +110,7 @@ class NodeInterestRatesTest {
fun `query successfully with interpolated rate`() {
database.transaction {
val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 5M")
val res = oracle.query(listOf(q), clock.instant())
val res = oracle.query(listOf(q))
assertEquals(1, res.size)
Assert.assertEquals(0.7316228, res[0].value.toDouble(), 0.0000001)
assertEquals(q, res[0].of)
@ -120,14 +121,14 @@ class NodeInterestRatesTest {
fun `rate missing and unable to interpolate`() {
database.transaction {
val q = NodeInterestRates.parseFixOf("EURIBOR 2016-03-15 3M")
assertFailsWith<NodeInterestRates.UnknownFix> { oracle.query(listOf(q), clock.instant()) }
assertFailsWith<NodeInterestRates.UnknownFix> { oracle.query(listOf(q)) }
}
}
@Test
fun `empty query`() {
database.transaction {
assertFailsWith<IllegalArgumentException> { oracle.query(emptyList(), clock.instant()) }
assertFailsWith<IllegalArgumentException> { oracle.query(emptyList()) }
}
}
@ -157,7 +158,7 @@ class NodeInterestRatesTest {
fun `sign successfully`() {
database.transaction {
val tx = makeTX()
val fix = oracle.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")), clock.instant()).first()
val fix = oracle.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M"))).first()
tx.addCommand(fix, oracle.identity.owningKey)
// Sign successfully.
val wtx = tx.toWireTransaction()
@ -185,7 +186,7 @@ class NodeInterestRatesTest {
fun `do not sign too many leaves`() {
database.transaction {
val tx = makeTX()
val fix = oracle.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")), clock.instant()).first()
val fix = oracle.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M"))).first()
fun filtering(elem: Any): Boolean {
return when (elem) {
is Command -> oracle.identity.owningKey in elem.signers && elem.value is Fix

View File

@ -1,4 +1,4 @@
package net.corda.irs.testing
package net.corda.irs.contract
import net.corda.contracts.*
import net.corda.core.contracts.*
@ -7,7 +7,6 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.core.utilities.DUMMY_NOTARY_KEY
import net.corda.core.utilities.TEST_TX_TIME
import net.corda.irs.contract.*
import net.corda.testing.*
import net.corda.testing.node.MockServices
import org.junit.Test

View File

@ -11,7 +11,6 @@ import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.node.utilities.TestClock
import net.corda.testing.node.MockNetworkMapCache
import java.time.LocalDate
/**
@ -19,8 +18,6 @@ import java.time.LocalDate
*/
object UpdateBusinessDayFlow {
// This is not really a HandshakeMessage but needs to be so that the send uses the default session ID. This will
// resolve itself when the flow session stuff is done.
@CordaSerializable
data class UpdateBusinessDayMessage(val date: LocalDate)
@ -32,7 +29,6 @@ object UpdateBusinessDayFlow {
}
}
@InitiatingFlow
@StartableByRPC
class Broadcast(val date: LocalDate, override val progressTracker: ProgressTracker) : FlowLogic<Unit>() {
@ -65,12 +61,7 @@ object UpdateBusinessDayFlow {
@Suspendable
private fun doNextRecipient(recipient: NodeInfo) {
if (recipient.address is MockNetworkMapCache.MockAddress) {
// Ignore
} else {
send(recipient.legalIdentity, UpdateBusinessDayMessage(date))
}
}
}
}

View File

@ -0,0 +1,9 @@
package net.corda.irs.plugin
import net.corda.irs.api.InterestRatesSwapDemoAPI
import net.corda.webserver.services.WebServerPluginRegistry
import java.util.function.Function
class IRSDemoPlugin : WebServerPluginRegistry {
override val webApis = listOf(Function(::InterestRatesSwapDemoAPI))
}

View File

@ -0,0 +1,3 @@
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
net.corda.irs.plugin.IRSPlugin
net.corda.irs.plugin.IRSDemoPlugin

View File

@ -7,6 +7,7 @@ apply plugin: 'us.kirchmeier.capsule'
dependencies {
compile project(':samples:irs-demo')
compile project(':test-utils')
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
@ -16,7 +17,6 @@ dependencies {
compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
compile project(':core')
compile project(':finance')
testCompile project(':test-utils')
// Javax is required for webapis
compile "org.glassfish.jersey.core:jersey-server:${jersey_version}"

View File

@ -15,9 +15,9 @@ import net.corda.core.crypto.commonName
import net.corda.core.serialization.deserialize
import net.corda.core.then
import net.corda.core.utilities.ProgressTracker
import net.corda.irs.simulation.IRSSimulation
import net.corda.irs.simulation.Simulation
import net.corda.netmap.VisualiserViewModel.Style
import net.corda.netmap.simulation.IRSSimulation
import net.corda.netmap.simulation.Simulation
import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.statemachine.SessionConfirm
import net.corda.node.services.statemachine.SessionEnd

View File

@ -9,7 +9,7 @@ import javafx.scene.shape.Line
import javafx.util.Duration
import net.corda.core.crypto.commonName
import net.corda.core.utilities.ProgressTracker
import net.corda.irs.simulation.IRSSimulation
import net.corda.netmap.simulation.IRSSimulation
import net.corda.testing.node.MockNetwork
import org.bouncycastle.asn1.x500.X500Name
import java.util.*
@ -50,7 +50,7 @@ class VisualiserViewModel {
var bankCount: Int = 0
var serviceCount: Int = 0
var stepDuration = Duration.millis(500.0)
var stepDuration: Duration = Duration.millis(500.0)
var runningPausedState: NetworkMapVisualiser.RunningPausedState = NetworkMapVisualiser.RunningPausedState.Paused()
var displayStyle: Style = Style.MAP

View File

@ -1,4 +1,4 @@
package net.corda.irs.simulation
package net.corda.netmap.simulation
import co.paralleluniverse.fibers.Suspendable
import com.fasterxml.jackson.databind.ObjectMapper

View File

@ -1,4 +1,4 @@
package net.corda.irs.simulation
package net.corda.netmap.simulation
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
@ -133,7 +133,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java)
javaClass.classLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt").use {
database.transaction {
installCordaService(NodeInterestRates.Oracle::class.java).upload(it)
installCordaService(NodeInterestRates.Oracle::class.java).uploadFixes(it.reader().readText())
}
}
return this

View File

@ -1,8 +1,7 @@
package net.corda.irs.testing
package net.corda.netmap.simulation
import net.corda.core.getOrThrow
import net.corda.core.utilities.LogHelper
import net.corda.irs.simulation.IRSSimulation
import org.junit.Test
class IRSSimulationTest {

View File

@ -27,8 +27,6 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Corda integration dependencies
compile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -36,7 +34,6 @@ dependencies {
compile project(':core')
compile project(':webserver')
compile project(':finance')
compile project(':test-utils')
// Javax is required for webapis
compile "org.glassfish.jersey.core:jersey-server:${jersey_version}"
@ -53,6 +50,10 @@ dependencies {
compile "com.opengamma.strata:strata-collect:${strata_version}"
compile "com.opengamma.strata:strata-loader:${strata_version}"
compile "com.opengamma.strata:strata-math:${strata_version}"
testCompile project(':test-utils')
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
}
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {

View File

@ -22,7 +22,6 @@ import net.corda.core.utilities.unwrap
import net.corda.flows.AbstractStateReplacementFlow.Proposal
import net.corda.flows.StateReplacementException
import net.corda.flows.TwoPartyDealFlow
import net.corda.node.services.messaging.Ack
import net.corda.vega.analytics.*
import net.corda.vega.contracts.*
import net.corda.vega.portfolio.Portfolio
@ -320,4 +319,6 @@ object SimmFlow {
})
}
}
private object Ack
}

View File

@ -1,14 +1,14 @@
package net.corda.vega
import com.google.common.util.concurrent.Futures
import net.corda.core.crypto.X509Utilities
import net.corda.core.getOrThrow
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.DUMMY_BANK_A
import net.corda.core.utilities.DUMMY_BANK_B
import net.corda.core.utilities.DUMMY_BANK_C
import net.corda.testing.driver.driver
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.driver.driver
/**
* Sample main used for running within an IDE. Starts 4 nodes (A, B, C and Notary/Controller) as an alternative to running via gradle
@ -17,7 +17,7 @@ import net.corda.node.services.transactions.SimpleNotaryService
*/
fun main(args: Array<String>) {
driver(dsl = {
startNode(X509Utilities.getDevX509Name("Controller"), setOf(ServiceInfo(SimpleNotaryService.type)))
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
val (nodeA, nodeB, nodeC) = Futures.allAsList(
startNode(DUMMY_BANK_A.name),
startNode(DUMMY_BANK_B.name),

View File

@ -23,15 +23,12 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Corda integration dependencies
compile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
compile project(':core')
compile project(':finance')
compile project(':test-utils')
// Corda Plugins: dependent flows and services
compile project(':samples:bank-of-corda-demo')
@ -45,6 +42,10 @@ dependencies {
exclude group: "bouncycastle"
}
testCompile project(':test-utils')
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Cordapp dependencies
// Specify your cordapp's dependencies below, including dependent cordapps
}

View File

@ -11,6 +11,7 @@ import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.BOC
import net.corda.testing.driver.driver
import net.corda.traderdemo.flow.SellerFlow
/**
* This file is exclusively for being able to run your nodes through an IDE (as opposed to running deployNodes)
@ -19,7 +20,7 @@ import net.corda.testing.driver.driver
fun main(args: Array<String>) {
val permissions = setOf(
startFlowPermission<IssuerFlow.IssuanceRequester>(),
startFlowPermission<net.corda.traderdemo.flow.SellerFlow>())
startFlowPermission<SellerFlow>())
val demoUser = listOf(User("demo", "demo", permissions))
driver(driverDirectory = "build" / "trader-demo-nodes", isDebug = true) {
val user = User("user1", "test", permissions = setOf(startFlowPermission<IssuerFlow.IssuanceRequester>()))