mirror of
https://github.com/corda/corda.git
synced 2025-02-01 00:45:59 +00:00
First working commit
First working commit Formatting clean up Revert All_tests.xml Remove extra space Feedback from code review First working commit Revert All_tests.xml Remove extra space Feedback from code review
This commit is contained in:
parent
c450c70f9a
commit
791022f130
@ -8,6 +8,15 @@
|
||||
|
||||
package contracts
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.JsonSerializer
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
import com.fasterxml.jackson.databind.type.SimpleType
|
||||
import core.*
|
||||
import core.crypto.SecureHash
|
||||
import core.node.services.DummyTimestampingAuthority
|
||||
@ -15,6 +24,7 @@ import org.apache.commons.jexl3.JexlBuilder
|
||||
import org.apache.commons.jexl3.MapContext
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.security.PublicKey
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
|
||||
@ -167,8 +177,6 @@ class InterestRateSwap() : Contract {
|
||||
val hashLegalDocs: String
|
||||
)
|
||||
|
||||
data class Expression(val expr: String)
|
||||
|
||||
/**
|
||||
* The Calculation data class is "mutable" through out the life of the swap, as in, it's the only thing that contains
|
||||
* data that will changed from state to state (Recall that the design insists that everything is immutable, so we actually
|
||||
@ -177,7 +185,7 @@ class InterestRateSwap() : Contract {
|
||||
data class Calculation(
|
||||
val expression: Expression,
|
||||
val floatingLegPaymentSchedule: Map<LocalDate, FloatingRatePaymentEvent>,
|
||||
val fixedLegpaymentSchedule: Map<LocalDate, FixedRatePaymentEvent>
|
||||
val fixedLegPaymentSchedule: Map<LocalDate, FixedRatePaymentEvent>
|
||||
) {
|
||||
/**
|
||||
* Gets the date of the next fixing.
|
||||
@ -185,7 +193,7 @@ class InterestRateSwap() : Contract {
|
||||
*/
|
||||
fun nextFixingDate(): LocalDate? {
|
||||
return floatingLegPaymentSchedule.
|
||||
filter { it.value.rate is OracleRetrievableReferenceRate }.// TODO - a better way to determine what fixings remain to be fixed
|
||||
filter { it.value.rate is ReferenceRate }.// TODO - a better way to determine what fixings remain to be fixed
|
||||
minBy { it.value.fixingDate.toEpochDay() }?.value?.fixingDate
|
||||
}
|
||||
|
||||
@ -203,7 +211,7 @@ class InterestRateSwap() : Contract {
|
||||
val newFloatingLPS = floatingLegPaymentSchedule + (paymentEvent.date to paymentEvent.withNewRate(newRate))
|
||||
return Calculation(expression = expression,
|
||||
floatingLegPaymentSchedule = newFloatingLPS,
|
||||
fixedLegpaymentSchedule = fixedLegpaymentSchedule)
|
||||
fixedLegPaymentSchedule = fixedLegPaymentSchedule)
|
||||
}
|
||||
|
||||
fun exportSchedule() {
|
||||
@ -297,7 +305,7 @@ class InterestRateSwap() : Contract {
|
||||
*/
|
||||
override fun verify(tx: TransactionForVerification) {
|
||||
val command = tx.commands.requireSingleCommand<InterestRateSwap.Commands>()
|
||||
val time = tx.getTimestampBy(DummyTimestampingAuthority.identity)?.midpoint
|
||||
val time = tx.commands.getTimestampByName("Mock Company 0", "Bank of Zurich")?.midpoint
|
||||
if (time == null) throw IllegalArgumentException("must be timestamped")
|
||||
|
||||
val irs = tx.outStates.filterIsInstance<InterestRateSwap.State>().single()
|
||||
@ -306,7 +314,7 @@ class InterestRateSwap() : Contract {
|
||||
requireThat {
|
||||
"There are no in states for an agreement" by tx.inStates.isEmpty()
|
||||
"The fixed rate is non zero" by (irs.fixedLeg.fixedRate != FixedRate(PercentageRatioUnit("0.0")))
|
||||
"There are events in the fix schedule" by (irs.calculation.fixedLegpaymentSchedule.size > 0)
|
||||
"There are events in the fix schedule" by (irs.calculation.fixedLegPaymentSchedule.size > 0)
|
||||
"There are events in the float schedule" by (irs.calculation.floatingLegPaymentSchedule.size > 0)
|
||||
// "There are fixes in the schedule" by (irs.calculation.floatingLegPaymentSchedule!!.size > 0)
|
||||
// TODO: shortlist of other tests
|
||||
@ -348,8 +356,14 @@ class InterestRateSwap() : Contract {
|
||||
val floatingLeg: FloatingLeg,
|
||||
val calculation: Calculation,
|
||||
val common: Common
|
||||
) : ContractState {
|
||||
) : LinearState {
|
||||
override val programRef = IRS_PROGRAM_ID
|
||||
override val thread = SecureHash.sha256(common.tradeID)
|
||||
override val ref = common.tradeID
|
||||
|
||||
override fun isRelevant(ourKeys: Set<PublicKey>): Boolean {
|
||||
return (fixedLeg.fixedRatePayer.owningKey in ourKeys) || (floatingLeg.floatingRatePayer.owningKey in ourKeys)
|
||||
}
|
||||
|
||||
/**
|
||||
* For evaluating arbitrary java on the platform
|
||||
@ -408,9 +422,6 @@ class InterestRateSwap() : Contract {
|
||||
var floatingLegPaymentSchedule: MutableMap<LocalDate, FloatingRatePaymentEvent> = HashMap()
|
||||
periodStartDate = floatingLeg.effectiveDate
|
||||
|
||||
// TODO: Temporary until implemented via Rates Oracle.
|
||||
val telerate = TelerateOracle("3750")
|
||||
|
||||
// Now create a schedule for the floating and fixes.
|
||||
for (periodEndDate in dates) {
|
||||
val paymentEvent = FloatingRatePaymentEvent(
|
||||
@ -421,8 +432,7 @@ class InterestRateSwap() : Contract {
|
||||
floatingLeg.dayCountBasisYear,
|
||||
calcFixingDate(periodStartDate, floatingLeg.fixingPeriod, floatingLeg.fixingCalendar),
|
||||
floatingLeg.notional,
|
||||
// TODO: OracleRetrievableReferenceRate will be replaced via oracle v soon.
|
||||
OracleRetrievableReferenceRate(telerate, floatingLeg.indexTenor, floatingLeg.index)
|
||||
ReferenceRate(floatingLeg.indexSource, floatingLeg.indexTenor, floatingLeg.index)
|
||||
)
|
||||
|
||||
floatingLegPaymentSchedule.put(periodEndDate, paymentEvent)
|
||||
|
@ -10,6 +10,6 @@ package contracts
|
||||
|
||||
fun InterestRateSwap.State.exportIRSToCSV() : String =
|
||||
"Fixed Leg\n" + FixedRatePaymentEvent.CSVHeader + "\n" +
|
||||
this.calculation.fixedLegpaymentSchedule.toSortedMap().values.map{ it.asCSV() }.joinToString("\n") + "\n" +
|
||||
this.calculation.fixedLegPaymentSchedule.toSortedMap().values.map{ it.asCSV() }.joinToString("\n") + "\n" +
|
||||
"Floating Leg\n" + FloatingRatePaymentEvent.CSVHeader + "\n" +
|
||||
this.calculation.floatingLegPaymentSchedule.toSortedMap().values.map{ it.asCSV() }.joinToString("\n") + "\n"
|
||||
|
@ -1,5 +1,13 @@
|
||||
package contracts
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
|
||||
import com.fasterxml.jackson.databind.type.SimpleType
|
||||
import core.Amount
|
||||
import core.Tenor
|
||||
import java.math.BigDecimal
|
||||
@ -50,43 +58,7 @@ open class FloatingRate: Rate(null)
|
||||
* So a reference rate is a rate that takes its value from a source at a given date
|
||||
* e.g. LIBOR 6M as of 17 March 2016. Hence it requires a source (name) and a value date in the getAsOf(..) method.
|
||||
*/
|
||||
abstract class ReferenceRate(val name: String): FloatingRate() {
|
||||
abstract fun getAsOf(date: LocalDate?) : RatioUnit
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete implementation of the above for testing purposes
|
||||
*/
|
||||
open class TestReferenceRate(val testrate: String) : ReferenceRate(testrate) {
|
||||
override fun getAsOf(date: LocalDate?) : RatioUnit {
|
||||
return testrate.percent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a source of data.
|
||||
*/
|
||||
abstract class Oracle() { abstract fun retrieve(tenor: Tenor, date: LocalDate) : RatioUnit }
|
||||
|
||||
class ReutersOracle() : Oracle() {
|
||||
override fun retrieve(tenor: Tenor, date: LocalDate): RatioUnit {
|
||||
TODO("Reuters Oracle retrieval")
|
||||
}
|
||||
}
|
||||
|
||||
class TelerateOracle(page: String) : Oracle() {
|
||||
override fun retrieve(tenor: Tenor, date: LocalDate): RatioUnit {
|
||||
TODO("Telerate Oracle retrieval")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Reference rate that is retrieved via an Oracle.
|
||||
*/
|
||||
open class OracleRetrievableReferenceRate(val oracle: Oracle, val tenor: Tenor, referenceRate: String) : ReferenceRate(referenceRate) {
|
||||
override fun getAsOf(date: LocalDate?): RatioUnit {
|
||||
return oracle.retrieve(tenor,date!!)
|
||||
}
|
||||
class ReferenceRate(val oracle: String, val tenor: Tenor, val name: String) : FloatingRate() {
|
||||
override fun toString(): String = "$name - $tenor"
|
||||
}
|
||||
|
||||
|
@ -47,4 +47,7 @@ dependencies {
|
||||
// Apache JEXL: An embeddable expression evaluation library.
|
||||
// This may be temporary until we experiment with other ways to do on-the-fly contract specialisation via an API.
|
||||
compile "org.apache.commons:commons-jexl3:3.0"
|
||||
|
||||
// For JSON
|
||||
compile "com.fasterxml.jackson.core:jackson-databind:2.5.5"
|
||||
}
|
||||
|
@ -8,6 +8,14 @@
|
||||
|
||||
package core
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.JsonSerializer
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
import java.math.BigDecimal
|
||||
import java.time.DayOfWeek
|
||||
import java.time.LocalDate
|
||||
@ -82,7 +90,25 @@ data class FixOf(val name: String, val forDay: LocalDate, val ofTenor: Tenor)
|
||||
/** A [Fix] represents a named interest rate, on a given day, for a given duration. It can be embedded in a tx. */
|
||||
data class Fix(val of: FixOf, val value: BigDecimal) : CommandData
|
||||
|
||||
/**
|
||||
* Represents a textual expression of e.g. a formula
|
||||
*
|
||||
*/
|
||||
@JsonDeserialize(using = ExpressionDeserializer::class)
|
||||
@JsonSerialize(using = ExpressionSerializer::class)
|
||||
data class Expression(val expr: String)
|
||||
|
||||
object ExpressionSerializer: JsonSerializer<Expression>() {
|
||||
override fun serialize(expr: Expression, generator: JsonGenerator, provider: SerializerProvider) {
|
||||
generator.writeString(expr.expr)
|
||||
}
|
||||
}
|
||||
|
||||
object ExpressionDeserializer: JsonDeserializer<Expression>() {
|
||||
override fun deserialize(parser: JsonParser, context: DeserializationContext): Expression {
|
||||
return Expression(parser.text)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder class for the Tenor datatype - which is a standardised duration of time until maturity */
|
||||
|
@ -4,3 +4,48 @@ LIBOR 2016-03-16 1M = 0.678
|
||||
LIBOR 2016-03-16 2M = 0.655
|
||||
EURIBOR 2016-03-15 1M = 0.123
|
||||
EURIBOR 2016-03-15 2M = 0.111
|
||||
|
||||
LIBOR 2016-03-08 3M = 0.01
|
||||
LIBOR 2016-06-08 3M = 0.01
|
||||
LIBOR 2016-09-08 3M = 0.01
|
||||
LIBOR 2016-12-08 3M = 0.01
|
||||
LIBOR 2017-03-08 3M = 0.01
|
||||
LIBOR 2017-06-08 3M = 0.01
|
||||
LIBOR 2017-09-07 3M = 0.01
|
||||
LIBOR 2017-12-07 3M = 0.01
|
||||
LIBOR 2018-03-08 3M = 0.01
|
||||
LIBOR 2018-06-07 3M = 0.01
|
||||
LIBOR 2018-09-06 3M = 0.01
|
||||
LIBOR 2018-12-06 3M = 0.01
|
||||
LIBOR 2019-03-07 3M = 0.01
|
||||
LIBOR 2019-06-06 3M = 0.01
|
||||
LIBOR 2019-09-06 3M = 0.01
|
||||
LIBOR 2019-12-06 3M = 0.01
|
||||
LIBOR 2020-03-06 3M = 0.01
|
||||
LIBOR 2020-06-08 3M = 0.01
|
||||
LIBOR 2020-09-08 3M = 0.01
|
||||
LIBOR 2020-12-08 3M = 0.01
|
||||
LIBOR 2021-03-08 3M = 0.01
|
||||
LIBOR 2021-06-08 3M = 0.01
|
||||
LIBOR 2021-09-08 3M = 0.01
|
||||
LIBOR 2021-12-08 3M = 0.01
|
||||
LIBOR 2022-03-08 3M = 0.01
|
||||
LIBOR 2022-06-08 3M = 0.01
|
||||
LIBOR 2022-09-08 3M = 0.01
|
||||
LIBOR 2022-12-08 3M = 0.01
|
||||
LIBOR 2023-03-08 3M = 0.01
|
||||
LIBOR 2023-06-08 3M = 0.01
|
||||
LIBOR 2023-09-07 3M = 0.01
|
||||
LIBOR 2023-12-07 3M = 0.01
|
||||
LIBOR 2024-03-07 3M = 0.01
|
||||
LIBOR 2024-06-06 3M = 0.01
|
||||
LIBOR 2024-09-06 3M = 0.01
|
||||
LIBOR 2024-12-06 3M = 0.01
|
||||
LIBOR 2025-03-06 3M = 0.01
|
||||
LIBOR 2025-06-06 3M = 0.01
|
||||
LIBOR 2025-09-08 3M = 0.01
|
||||
LIBOR 2025-12-08 3M = 0.01
|
||||
LIBOR 2026-03-06 3M = 0.01
|
||||
LIBOR 2026-06-08 3M = 0.01
|
||||
LIBOR 2026-09-08 3M = 0.01
|
||||
LIBOR 2026-12-08 3M = 0.01
|
||||
|
@ -7,6 +7,7 @@ import core.crypto.SecureHash
|
||||
import core.node.AbstractNode
|
||||
import core.protocols.ProtocolLogic
|
||||
import core.serialization.SerializedBytes
|
||||
import core.utilities.ANSIProgressRenderer
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
import kotlin.reflect.KParameter
|
||||
@ -87,6 +88,7 @@ class APIServerImpl(val node: AbstractNode): APIServer {
|
||||
}
|
||||
// If we get here then we matched every parameter
|
||||
val protocol = constructor.callBy(params) as ProtocolLogic<*>
|
||||
ANSIProgressRenderer.progressTracker = protocol.progressTracker
|
||||
val future = node.smm.add("api-call",protocol)
|
||||
return future
|
||||
}
|
||||
|
33
src/main/kotlin/api/ResponseFilter.kt
Normal file
33
src/main/kotlin/api/ResponseFilter.kt
Normal file
@ -0,0 +1,33 @@
|
||||
package api
|
||||
|
||||
import javax.ws.rs.container.ContainerRequestContext
|
||||
import javax.ws.rs.container.ContainerResponseContext
|
||||
import javax.ws.rs.container.ContainerResponseFilter
|
||||
import javax.ws.rs.ext.Provider
|
||||
|
||||
/**
|
||||
* This adds headers needed for cross site scripting on API clients
|
||||
*/
|
||||
@Provider
|
||||
class ResponseFilter: ContainerResponseFilter {
|
||||
override fun filter(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
|
||||
val headers = responseContext.headers
|
||||
|
||||
/**
|
||||
* TODO we need to revisit this for security reasons
|
||||
*
|
||||
* We don't want this scriptable from any web page anywhere, but for demo reasons
|
||||
* we're making this really easy to access pending a proper security approach including
|
||||
* access control and authentication at a network and software level
|
||||
*
|
||||
*/
|
||||
headers.add("Access-Control-Allow-Origin","*")
|
||||
|
||||
if(requestContext.method == "OPTIONS") {
|
||||
headers.add("Access-Control-Allow-Headers", "Content-Type,Accept,Origin")
|
||||
headers.add("Access-Control-Allow-Methods", "POST,PUT,GET,OPTIONS")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -26,6 +26,7 @@ data class LegallyIdentifiableNode(val address: SingleMessageRecipient, val iden
|
||||
*/
|
||||
interface NetworkMapService {
|
||||
val timestampingNodes: List<LegallyIdentifiableNode>
|
||||
val ratesOracleNodes: List<LegallyIdentifiableNode>
|
||||
val partyNodes: List<LegallyIdentifiableNode>
|
||||
|
||||
fun nodeForPartyName(name: String): LegallyIdentifiableNode? = partyNodes.singleOrNull { it.identity.name == name }
|
||||
@ -37,6 +38,7 @@ class MockNetworkMapService : NetworkMapService {
|
||||
data class MockAddress(val id: String): SingleMessageRecipient
|
||||
|
||||
override val timestampingNodes = Collections.synchronizedList(ArrayList<LegallyIdentifiableNode>())
|
||||
override val ratesOracleNodes = Collections.synchronizedList(ArrayList<LegallyIdentifiableNode>())
|
||||
override val partyNodes = Collections.synchronizedList(ArrayList<LegallyIdentifiableNode>())
|
||||
|
||||
init {
|
||||
|
@ -168,10 +168,11 @@ class StateMachineManager(val serviceHub: ServiceHub, val runInThread: Executor)
|
||||
fun <T> add(loggerName: String, logic: ProtocolLogic<T>): ListenableFuture<T> {
|
||||
val logger = LoggerFactory.getLogger(loggerName)
|
||||
val fiber = ProtocolStateMachine(logic)
|
||||
// Need to add before iterating in case of immediate completion
|
||||
_stateMachines.add(logic)
|
||||
iterateStateMachine(fiber, serviceHub.networkService, logger, null, null) {
|
||||
it.start()
|
||||
}
|
||||
_stateMachines.add(logic)
|
||||
totalStartedProtocols.inc()
|
||||
return fiber.resultFuture
|
||||
}
|
||||
|
@ -76,7 +76,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
CASH_PROGRAM_ID to Cash::class.java,
|
||||
CP_PROGRAM_ID to CommercialPaper::class.java,
|
||||
CROWDFUND_PROGRAM_ID to CrowdFund::class.java,
|
||||
DUMMY_PROGRAM_ID to DummyContract::class.java
|
||||
DUMMY_PROGRAM_ID to DummyContract::class.java,
|
||||
IRS_PROGRAM_ID to InterestRateSwap::class.java
|
||||
)
|
||||
|
||||
override fun <T : Contract> get(hash: SecureHash): T {
|
||||
|
@ -9,6 +9,7 @@
|
||||
package core.node
|
||||
|
||||
import api.Config
|
||||
import api.ResponseFilter
|
||||
import com.codahale.metrics.JmxReporter
|
||||
import com.google.common.net.HostAndPort
|
||||
import core.messaging.LegallyIdentifiableNode
|
||||
@ -94,6 +95,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration
|
||||
val resourceConfig = ResourceConfig()
|
||||
// Add your API provider classes (annotated for JAX-RS) here
|
||||
resourceConfig.register(Config(services))
|
||||
resourceConfig.register(ResponseFilter())
|
||||
resourceConfig.register(api)
|
||||
// Give the app a slightly better name in JMX rather than a randomly generated one and enable JMX
|
||||
resourceConfig.addProperties(mapOf(ServerProperties.APPLICATION_NAME to "node.api",
|
||||
|
@ -135,9 +135,9 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort)
|
||||
session.createQueue(myHostPort.toString(), "inbound", false)
|
||||
inboundConsumer = session.createConsumer("inbound").setMessageHandler { message: ClientMessage ->
|
||||
// This code runs for every inbound message.
|
||||
try {
|
||||
if (!message.containsProperty(TOPIC_PROPERTY)) {
|
||||
log.warn("Received message without a ${TOPIC_PROPERTY} property, ignoring")
|
||||
// TODO: Figure out whether we always need to acknowledge messages, even when invalid.
|
||||
return@setMessageHandler
|
||||
}
|
||||
val topic = message.getStringProperty(TOPIC_PROPERTY)
|
||||
@ -171,8 +171,10 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
message.acknowledge()
|
||||
}
|
||||
}
|
||||
session.start()
|
||||
|
||||
mutex.locked { running = true }
|
||||
|
34
src/main/kotlin/demos/DemoClock.kt
Normal file
34
src/main/kotlin/demos/DemoClock.kt
Normal file
@ -0,0 +1,34 @@
|
||||
package demos
|
||||
|
||||
import java.time.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
/**
|
||||
* A [Clock] that can have the date advanced for use in demos
|
||||
*/
|
||||
@ThreadSafe
|
||||
class DemoClock(private var delegateClock: Clock = Clock.systemUTC()) : Clock() {
|
||||
|
||||
@Synchronized fun updateDate(date: LocalDate): Boolean {
|
||||
val currentDate = LocalDate.now(this)
|
||||
if(currentDate.isBefore(date)) {
|
||||
// It's ok to increment
|
||||
delegateClock = Clock.offset(delegateClock, Duration.between(currentDate.atStartOfDay(),date.atStartOfDay()))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Synchronized override fun instant(): Instant {
|
||||
return delegateClock.instant()
|
||||
}
|
||||
|
||||
@Synchronized override fun withZone(zone: ZoneId): Clock {
|
||||
return DemoClock(delegateClock.withZone(zone))
|
||||
}
|
||||
|
||||
@Synchronized override fun getZone(): ZoneId {
|
||||
return delegateClock.zone
|
||||
}
|
||||
|
||||
}
|
@ -50,10 +50,13 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder,
|
||||
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
progressTracker.currentStep = progressTracker.steps[0]
|
||||
val fix = query()
|
||||
progressTracker.currentStep = WORKING
|
||||
checkFixIsNearExpected(fix)
|
||||
tx.addCommand(fix, oracle.identity.owningKey)
|
||||
beforeSigning(fix)
|
||||
progressTracker.currentStep = SIGNING
|
||||
tx.addSignatureUnchecked(sign())
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import core.node.services.TimestamperService
|
||||
import core.protocols.ProtocolLogic
|
||||
import core.random63BitValue
|
||||
import core.serialization.SerializedBytes
|
||||
import core.utilities.ProgressTracker
|
||||
|
||||
/**
|
||||
* The TimestampingProtocol class is the client code that talks to a [NodeTimestamperService] on some remote node. It is a
|
||||
@ -31,7 +32,8 @@ import core.serialization.SerializedBytes
|
||||
* a network message: use it only from spare application threads that don't have to respond to anything.
|
||||
*/
|
||||
class TimestampingProtocol(private val node: LegallyIdentifiableNode,
|
||||
private val wtxBytes: SerializedBytes<WireTransaction>) : ProtocolLogic<DigitalSignature.LegallyIdentifiable>() {
|
||||
private val wtxBytes: SerializedBytes<WireTransaction>,
|
||||
override val progressTracker: ProgressTracker = TimestampingProtocol.tracker()) : ProtocolLogic<DigitalSignature.LegallyIdentifiable>() {
|
||||
|
||||
class Client(private val stateMachineManager: StateMachineManager, private val node: LegallyIdentifiableNode) : TimestamperService {
|
||||
override val identity: Party = node.identity
|
||||
@ -41,9 +43,18 @@ class TimestampingProtocol(private val node: LegallyIdentifiableNode,
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
object REQUESTING : ProgressTracker.Step("Requesting signature by timestamping service")
|
||||
object VALIDATING : ProgressTracker.Step("Validating received signature from timestamping service")
|
||||
|
||||
fun tracker() = ProgressTracker(REQUESTING, VALIDATING)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Suspendable
|
||||
override fun call(): DigitalSignature.LegallyIdentifiable {
|
||||
progressTracker.currentStep = REQUESTING
|
||||
val sessionID = random63BitValue()
|
||||
val replyTopic = "${NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC}.$sessionID"
|
||||
val req = Request(wtxBytes, serviceHub.networkService.myAddress, replyTopic)
|
||||
@ -52,6 +63,7 @@ class TimestampingProtocol(private val node: LegallyIdentifiableNode,
|
||||
NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC, node.address, 0, sessionID, req)
|
||||
|
||||
// Check that the timestamping authority gave us back a valid signature and didn't break somehow
|
||||
progressTracker.currentStep = VALIDATING
|
||||
maybeSignature.validate { sig ->
|
||||
sig.verifyWithECDSA(wtxBytes)
|
||||
return sig
|
||||
|
@ -74,11 +74,11 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
|
||||
//expression = "( fixedLeg.notional * (fixedLeg.fixedRate)) - (floatingLeg.notional * (rateSchedule.get(context.getDate('currentDate'))))",
|
||||
|
||||
// How it's ended up looking, which I think is now broken but it's a WIP.
|
||||
expression = InterestRateSwap.Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
|
||||
expression = Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
|
||||
"(floatingLeg.notional.pennies * (calculation.fixingSchedule.get(context.getDate('currentDate')).rate.ratioUnit.value))"),
|
||||
|
||||
floatingLegPaymentSchedule = HashMap(),
|
||||
fixedLegpaymentSchedule = HashMap()
|
||||
fixedLegPaymentSchedule = HashMap()
|
||||
)
|
||||
|
||||
val EUR = currency("EUR")
|
||||
@ -94,13 +94,13 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
|
||||
valuationDate = "Every Local Business Day",
|
||||
notificationTime = "2:00pm London",
|
||||
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
|
||||
interestRate = OracleRetrievableReferenceRate(TelerateOracle("T3270"), Tenor("6M"), "EONIA"),
|
||||
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),
|
||||
addressForTransfers = "",
|
||||
exposure = UnknownType(),
|
||||
localBusinessDay = BusinessCalendar.getInstance("London"),
|
||||
tradeID = "trade1",
|
||||
hashLegalDocs = "put hash here",
|
||||
dailyInterestAmount = InterestRateSwap.Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
|
||||
dailyInterestAmount = Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
|
||||
)
|
||||
|
||||
InterestRateSwap.State(fixedLeg = fixedLeg, floatingLeg = floatingLeg, calculation = calculation, common = common)
|
||||
@ -165,11 +165,11 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
|
||||
//expression = "( fixedLeg.notional * (fixedLeg.fixedRate)) - (floatingLeg.notional * (rateSchedule.get(context.getDate('currentDate'))))",
|
||||
|
||||
// How it's ended up looking, which I think is now broken but it's a WIP.
|
||||
expression = InterestRateSwap.Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
|
||||
expression = Expression("( fixedLeg.notional.pennies * (fixedLeg.fixedRate.ratioUnit.value)) -" +
|
||||
"(floatingLeg.notional.pennies * (calculation.fixingSchedule.get(context.getDate('currentDate')).rate.ratioUnit.value))"),
|
||||
|
||||
floatingLegPaymentSchedule = HashMap(),
|
||||
fixedLegpaymentSchedule = HashMap()
|
||||
fixedLegPaymentSchedule = HashMap()
|
||||
)
|
||||
|
||||
val EUR = currency("EUR")
|
||||
@ -185,13 +185,13 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
|
||||
valuationDate = "Every Local Business Day",
|
||||
notificationTime = "2:00pm London",
|
||||
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
|
||||
interestRate = OracleRetrievableReferenceRate(TelerateOracle("T3270"), Tenor("6M"), "EONIA"),
|
||||
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),
|
||||
addressForTransfers = "",
|
||||
exposure = UnknownType(),
|
||||
localBusinessDay = BusinessCalendar.getInstance("London"),
|
||||
tradeID = "trade1",
|
||||
hashLegalDocs = "put hash here",
|
||||
dailyInterestAmount = InterestRateSwap.Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
|
||||
dailyInterestAmount = Expression("(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360")
|
||||
)
|
||||
|
||||
return InterestRateSwap.State(fixedLeg = fixedLeg, floatingLeg = floatingLeg, calculation = calculation, common = common)
|
||||
@ -335,12 +335,6 @@ class IRSTests {
|
||||
// TODO: r1*r2 ?
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reference rate testing`() {
|
||||
val r1 = TestReferenceRate("5")
|
||||
assert(100 * r1.getAsOf(null) == 5)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `expression calculation testing`() {
|
||||
val dummyIRS = singleIRS()
|
||||
@ -366,7 +360,7 @@ class IRSTests {
|
||||
|
||||
for (i in stuffToPrint) {
|
||||
println(i)
|
||||
var z = dummyIRS.evaluateCalculation(LocalDate.of(2016, 9, 12), InterestRateSwap.Expression(i))
|
||||
var z = dummyIRS.evaluateCalculation(LocalDate.of(2016, 9, 12), Expression(i))
|
||||
println(z.javaClass)
|
||||
println(z)
|
||||
println("-----------")
|
||||
|
@ -38,6 +38,8 @@ object TestUtils {
|
||||
val keypair = generateKeyPair()
|
||||
val keypair2 = generateKeyPair()
|
||||
val keypair3 = generateKeyPair()
|
||||
val keypair4 = generateKeyPair()
|
||||
val keypair5 = generateKeyPair()
|
||||
}
|
||||
// A dummy time at which we will be pretending test transactions are created.
|
||||
val TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z")
|
||||
@ -49,6 +51,14 @@ val MEGA_CORP_PUBKEY = MEGA_CORP_KEY.public
|
||||
val MINI_CORP_KEY = TestUtils.keypair2
|
||||
val MINI_CORP_PUBKEY = MINI_CORP_KEY.public
|
||||
|
||||
// TODO remove once mock API is retired
|
||||
val EXCALIBUR_BANK_KEY = TestUtils.keypair4
|
||||
val EXCALIBUR_BANK_PUBKEY = EXCALIBUR_BANK_KEY.public
|
||||
|
||||
// TODO remove once mock API is retired
|
||||
val A_N_OTHER_BANK_KEY = TestUtils.keypair5
|
||||
val A_N_OTHER_BANK_PUBKEY = A_N_OTHER_BANK_KEY.public
|
||||
|
||||
val ORACLE_KEY = TestUtils.keypair3
|
||||
val ORACLE_PUBKEY = ORACLE_KEY.public
|
||||
|
||||
@ -64,11 +74,17 @@ val BOB = BOB_KEY.public
|
||||
val MEGA_CORP = Party("MegaCorp", MEGA_CORP_PUBKEY)
|
||||
val MINI_CORP = Party("MiniCorp", MINI_CORP_PUBKEY)
|
||||
|
||||
val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DummyTimestampingAuthority.key)
|
||||
// TODO remove once mock API is retired
|
||||
val EXCALIBUR_BANK = Party("Excalibur", EXCALIBUR_BANK_PUBKEY)
|
||||
val A_N_OTHER_BANK = Party("ANOther",A_N_OTHER_BANK_PUBKEY)
|
||||
|
||||
val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, EXCALIBUR_BANK_KEY, A_N_OTHER_BANK_KEY, DummyTimestampingAuthority.key)
|
||||
|
||||
val TEST_KEYS_TO_CORP_MAP: Map<PublicKey, Party> = mapOf(
|
||||
MEGA_CORP_PUBKEY to MEGA_CORP,
|
||||
MINI_CORP_PUBKEY to MINI_CORP,
|
||||
EXCALIBUR_BANK_PUBKEY to EXCALIBUR_BANK,
|
||||
A_N_OTHER_BANK_PUBKEY to A_N_OTHER_BANK,
|
||||
DUMMY_TIMESTAMPER.identity.owningKey to DUMMY_TIMESTAMPER.identity
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user