mirror of
https://github.com/corda/corda.git
synced 2025-02-04 10:11:14 +00:00
Allow upload of interest rate fixes to the oracle over HTTP.
This commit is contained in:
parent
2b4a1eedc3
commit
29e58ce3db
@ -39,3 +39,24 @@ containers, you can also fetch a specific file within the attachment by appendin
|
|||||||
|
|
||||||
http://localhost:31338/attachments/DECD098666B9657314870E192CED0C3519C2C9D395507A238338F8D003929DE9/path/within/zip.txt
|
http://localhost:31338/attachments/DECD098666B9657314870E192CED0C3519C2C9D395507A238338F8D003929DE9/path/within/zip.txt
|
||||||
|
|
||||||
|
Uploading interest rate fixes
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
If you would like to operate an interest rate fixing service (oracle), you can upload fix data by uploading data in
|
||||||
|
a simple text format to the ``/upload/interest-rates`` path on the web server.
|
||||||
|
|
||||||
|
The file looks like this::
|
||||||
|
|
||||||
|
# Some pretend noddy rate fixes, for the interest rate oracles.
|
||||||
|
|
||||||
|
LIBOR 2016-03-16 30 = 0.678
|
||||||
|
LIBOR 2016-03-16 60 = 0.655
|
||||||
|
EURIBOR 2016-03-15 30 = 0.123
|
||||||
|
EURIBOR 2016-03-15 60 = 0.111
|
||||||
|
|
||||||
|
The columns are:
|
||||||
|
|
||||||
|
* Name of the fix
|
||||||
|
* Date of the fix
|
||||||
|
* The tenor / time to maturity in days
|
||||||
|
* The interest rate itself
|
6
scripts/example.rates.txt
Normal file
6
scripts/example.rates.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Some pretend noddy rate fixes, for the interest rate oracles.
|
||||||
|
|
||||||
|
LIBOR 2016-03-16 30 = 0.678
|
||||||
|
LIBOR 2016-03-16 60 = 0.655
|
||||||
|
EURIBOR 2016-03-15 30 = 0.123
|
||||||
|
EURIBOR 2016-03-15 60 = 0.111
|
@ -92,11 +92,11 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
|||||||
log.info("Node starting up ...")
|
log.info("Node starting up ...")
|
||||||
|
|
||||||
storage = initialiseStorageService(dir)
|
storage = initialiseStorageService(dir)
|
||||||
|
|
||||||
net = makeMessagingService()
|
net = makeMessagingService()
|
||||||
smm = StateMachineManager(services, serverThread)
|
smm = StateMachineManager(services, serverThread)
|
||||||
wallet = NodeWalletService(services)
|
wallet = NodeWalletService(services)
|
||||||
keyManagement = E2ETestKeyManagementService()
|
keyManagement = E2ETestKeyManagementService()
|
||||||
|
makeInterestRateOracleService()
|
||||||
|
|
||||||
// Insert a network map entry for the timestamper: this is all temp scaffolding and will go away. If we are
|
// Insert a network map entry for the timestamper: this is all temp scaffolding and will go away. If we are
|
||||||
// given the details, the timestamping node is somewhere else. Otherwise, we do our own timestamping.
|
// given the details, the timestamping node is somewhere else. Otherwise, we do our own timestamping.
|
||||||
@ -118,6 +118,12 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun makeInterestRateOracleService() {
|
||||||
|
// Constructing the service registers message handlers that ensure the service won't be garbage collected.
|
||||||
|
// TODO: Once the service has data, automatically register with the network map service (once built).
|
||||||
|
_servicesThatAcceptUploads += NodeInterestRates.Service(this)
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun makeIdentityService(): IdentityService {
|
protected open fun makeIdentityService(): IdentityService {
|
||||||
// We don't have any identity infrastructure right now, so we just throw together the only two identities we
|
// We don't have any identity infrastructure right now, so we just throw together the only two identities we
|
||||||
// know about: our own, and the identity of the remote timestamper node (if any).
|
// know about: our own, and the identity of the remote timestamper node (if any).
|
||||||
|
@ -13,8 +13,10 @@ import core.crypto.DigitalSignature
|
|||||||
import core.crypto.signWithECDSA
|
import core.crypto.signWithECDSA
|
||||||
import core.messaging.send
|
import core.messaging.send
|
||||||
import core.node.AbstractNode
|
import core.node.AbstractNode
|
||||||
|
import core.node.AcceptsFileUpload
|
||||||
import core.serialization.deserialize
|
import core.serialization.deserialize
|
||||||
import protocols.RatesFixProtocol
|
import protocols.RatesFixProtocol
|
||||||
|
import java.io.InputStream
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -31,13 +33,6 @@ import javax.annotation.concurrent.ThreadSafe
|
|||||||
* for signing.
|
* for signing.
|
||||||
*/
|
*/
|
||||||
object NodeInterestRates {
|
object NodeInterestRates {
|
||||||
val INITIAL_FIXES = parseFile("""
|
|
||||||
LIBOR 2016-03-16 30 = 0.678
|
|
||||||
LIBOR 2016-03-16 60 = 0.655
|
|
||||||
EURIBOR 2016-03-15 30 = 0.123
|
|
||||||
EURIBOR 2016-03-15 60 = 0.111
|
|
||||||
""".trimIndent())
|
|
||||||
|
|
||||||
/** Parses a string of the form "LIBOR 16-March-2016 30 = 0.678" into a [FixOf] and [Fix] */
|
/** Parses a string of the form "LIBOR 16-March-2016 30 = 0.678" into a [FixOf] and [Fix] */
|
||||||
fun parseOneRate(s: String): Pair<FixOf, Fix> {
|
fun parseOneRate(s: String): Pair<FixOf, Fix> {
|
||||||
val (key, value) = s.split('=').map { it.trim() }
|
val (key, value) = s.split('=').map { it.trim() }
|
||||||
@ -65,7 +60,7 @@ object NodeInterestRates {
|
|||||||
/**
|
/**
|
||||||
* The Service that wraps [Oracle] and handles messages/network interaction/request scrubbing.
|
* The Service that wraps [Oracle] and handles messages/network interaction/request scrubbing.
|
||||||
*/
|
*/
|
||||||
class Service(node: AbstractNode) {
|
class Service(node: AbstractNode) : AcceptsFileUpload {
|
||||||
val ss = node.services.storageService
|
val ss = node.services.storageService
|
||||||
val oracle = Oracle(ss.myLegalIdentity, ss.myLegalIdentityKey)
|
val oracle = Oracle(ss.myLegalIdentity, ss.myLegalIdentityKey)
|
||||||
val net = node.services.networkService
|
val net = node.services.networkService
|
||||||
@ -90,6 +85,29 @@ object NodeInterestRates {
|
|||||||
net.send("${RatesFixProtocol.TOPIC}.query.${request.sessionID}", request.replyTo, answers)
|
net.send("${RatesFixProtocol.TOPIC}.query.${request.sessionID}", request.replyTo, answers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File upload support
|
||||||
|
override val dataTypePrefix = "interest-rates"
|
||||||
|
override val acceptableFileExtensions = listOf(".rates", ".txt")
|
||||||
|
|
||||||
|
override fun upload(data: InputStream): String {
|
||||||
|
val fixes: Map<FixOf, Fix> = data.
|
||||||
|
bufferedReader().
|
||||||
|
readLines().
|
||||||
|
map { it.trim() }.
|
||||||
|
// Filter out comment and empty lines.
|
||||||
|
filterNot { it.startsWith("#") || it.isBlank() }.
|
||||||
|
map { parseOneRate(it) }.
|
||||||
|
associate { it.first to it.second }
|
||||||
|
|
||||||
|
// TODO: Save the uploaded fixes to the storage service and reload on construction.
|
||||||
|
|
||||||
|
// This assignment is thread safe because knownFixes is volatile and the oracle code always snapshots
|
||||||
|
// the pointer to the stack before working with the map.
|
||||||
|
oracle.knownFixes = fixes
|
||||||
|
|
||||||
|
return "Accepted ${fixes.size} new interest rate fixes"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +120,7 @@ object NodeInterestRates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The fix data being served by this oracle. */
|
/** The fix data being served by this oracle. */
|
||||||
@Transient var knownFixes = INITIAL_FIXES
|
@Transient var knownFixes = emptyMap<FixOf, Fix>()
|
||||||
set(value) {
|
set(value) {
|
||||||
require(value.isNotEmpty())
|
require(value.isNotEmpty())
|
||||||
field = value
|
field = value
|
||||||
|
@ -81,7 +81,7 @@ class NodeInterestRatesTest {
|
|||||||
fun network() {
|
fun network() {
|
||||||
val net = MockNetwork()
|
val net = MockNetwork()
|
||||||
val (n1, n2) = net.createTwoNodes()
|
val (n1, n2) = net.createTwoNodes()
|
||||||
NodeInterestRates.Service(n2)
|
NodeInterestRates.Service(n2).oracle.knownFixes = TEST_DATA
|
||||||
|
|
||||||
val tx = TransactionBuilder()
|
val tx = TransactionBuilder()
|
||||||
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30")
|
val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 30")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user