mirror of
https://github.com/corda/corda.git
synced 2025-02-21 17:56:54 +00:00
Make the trader demo attach a PDF to the commercial paper self-issuance and then scan for it on the buyer side, print out the path on the filesystem where the PDF can be found.
This commit is contained in:
parent
8d906c703d
commit
1123c28f02
2
.idea/runConfigurations/Node__seller.xml
generated
2
.idea/runConfigurations/Node__seller.xml
generated
@ -3,7 +3,7 @@
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="core.node.TraderDemoKt" />
|
||||
<option name="VM_PARAMETERS" value="-ea -javaagent:lib/quasar.jar -Dco.paralleluniverse.fibers.verifyInstrumentation" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--dir=seller --fake-trade-with=localhost --network-address=localhost:31338 --timestamper-identity-file=buyer/identity-public --timestamper-address=localhost" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--dir=seller --fake-trade-with=localhost --network-address=localhost:31327 --timestamper-identity-file=buyer/identity-public --timestamper-address=localhost" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
|
10
build.gradle
10
build.gradle
@ -12,7 +12,8 @@ allprojects {
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.0.0'
|
||||
ext.quasar_version = '0.7.4'
|
||||
// TODO: Reset to 0.7.5 when released. We need the snapshot for a TLS serialization related fix.
|
||||
ext.quasar_version = '0.7.5-SNAPSHOT'
|
||||
ext.asm_version = '0.5.3'
|
||||
ext.artemis_version = '1.2.0'
|
||||
ext.jetty_version = '9.3.7.v20160115'
|
||||
@ -28,7 +29,7 @@ buildscript {
|
||||
|
||||
|
||||
repositories {
|
||||
// mavenLocal()
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'http://oss.sonatype.org/content/repositories/snapshots'
|
||||
@ -67,12 +68,7 @@ dependencies {
|
||||
// JOpt: for command line flags.
|
||||
compile "net.sf.jopt-simple:jopt-simple:4.9"
|
||||
|
||||
// Kryo: object graph serialization.
|
||||
compile "com.esotericsoftware:kryo:3.0.3"
|
||||
compile "de.javakaffee:kryo-serializers:0.37"
|
||||
|
||||
// Quasar: for the bytecode rewriting for state machines.
|
||||
compile("co.paralleluniverse:quasar-core:${quasar_version}:jdk8")
|
||||
quasar("co.paralleluniverse:quasar-core:${quasar_version}:jdk8@jar")
|
||||
|
||||
// Artemis: for reliable p2p message queues.
|
||||
|
@ -67,6 +67,12 @@ apply plugin: CanonicalizerPlugin
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven {
|
||||
url 'http://oss.sonatype.org/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -7,7 +7,6 @@ apply plugin: 'kotlin'
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
// Dokka (JavaDoc equivalent for Kotlin) download is a big download and also
|
||||
@ -22,7 +21,12 @@ buildscript {
|
||||
// apply plugin: 'org.jetbrains.dokka'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven {
|
||||
url 'http://oss.sonatype.org/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -41,6 +45,10 @@ dependencies {
|
||||
// RxJava: observable streams of events.
|
||||
compile "io.reactivex:rxkotlin:0.40.1"
|
||||
|
||||
// Kryo: object graph serialization.
|
||||
compile "com.esotericsoftware:kryo:3.0.3"
|
||||
compile "de.javakaffee:kryo-serializers:0.37"
|
||||
|
||||
// Quasar: for the bytecode rewriting for state machines.
|
||||
compile "co.paralleluniverse:quasar-core:${quasar_version}:jdk8"
|
||||
|
||||
|
@ -100,9 +100,10 @@ data class WireTransaction(val inputs: List<StateRef>,
|
||||
override fun toString(): String {
|
||||
val buf = StringBuilder()
|
||||
buf.appendln("Transaction:")
|
||||
for (input in inputs) buf.appendln("${Emoji.rightArrow}INPUT: $input")
|
||||
for (output in outputs) buf.appendln("${Emoji.leftArrow}OUTPUT: $output")
|
||||
for (command in commands) buf.appendln("${Emoji.diamond}COMMAND: $command")
|
||||
for (input in inputs) buf.appendln("${Emoji.rightArrow}INPUT: $input")
|
||||
for (output in outputs) buf.appendln("${Emoji.leftArrow}OUTPUT: $output")
|
||||
for (command in commands) buf.appendln("${Emoji.diamond}COMMAND: $command")
|
||||
for (attachment in attachments) buf.appendln("${Emoji.paperclip}ATTACHMENT: $attachment")
|
||||
return buf.toString()
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ if [[ "$mode" == "buyer" ]]; then
|
||||
elif [[ "$mode" == "seller" ]]; then
|
||||
if [ ! -d seller ]; then
|
||||
mkdir seller
|
||||
echo "myLegalName = Bank of Giza" >seller/config
|
||||
echo "myLegalName = Bank of London" >seller/config
|
||||
fi
|
||||
|
||||
build/install/r3prototyping/bin/r3prototyping --dir=seller --fake-trade-with=localhost --network-address=localhost:31340 --timestamper-identity-file=buyer/identity-public --timestamper-address=localhost
|
||||
|
@ -14,6 +14,7 @@ import contracts.CommercialPaper
|
||||
import contracts.protocols.TwoPartyTradeProtocol
|
||||
import core.*
|
||||
import core.crypto.DigitalSignature
|
||||
import core.crypto.SecureHash
|
||||
import core.crypto.generateKeyPair
|
||||
import core.messaging.LegallyIdentifiableNode
|
||||
import core.messaging.SingleMessageRecipient
|
||||
@ -31,6 +32,7 @@ import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import kotlin.system.exitProcess
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
// TRADING DEMO
|
||||
//
|
||||
@ -93,7 +95,14 @@ fun main(args: Array<String>) {
|
||||
val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, config, timestamperId).start() }
|
||||
|
||||
if (listening) {
|
||||
val buyer = TraderDemoProtocolBuyer()
|
||||
// For demo purposes just extract attachment jars when saved to disk, so the user can explore them.
|
||||
// Buyer will fetch the attachment from the seller.
|
||||
val attachmentsPath = (node.storage.attachments as NodeAttachmentStorage).let {
|
||||
it.automaticallyExtractAttachments = true
|
||||
it.storePath
|
||||
}
|
||||
|
||||
val buyer = TraderDemoProtocolBuyer(attachmentsPath)
|
||||
ANSIProgressRenderer.progressTracker = buyer.progressTracker
|
||||
node.smm.add("demo.buyer", buyer).get() // This thread will halt forever here.
|
||||
} else {
|
||||
@ -101,6 +110,15 @@ fun main(args: Array<String>) {
|
||||
println("Need the --fake-trade-with command line argument")
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
// Make sure we have the transaction prospectus attachment loaded into our store.
|
||||
if (node.storage.attachments.openAttachment(TraderDemoProtocolSeller.PROSPECTUS_HASH) == null) {
|
||||
TraderDemoProtocolSeller::class.java.getResourceAsStream("bank-of-london-cp.jar").use {
|
||||
val id = node.storage.attachments.importAttachment(it)
|
||||
assertEquals(TraderDemoProtocolSeller.PROSPECTUS_HASH, id)
|
||||
}
|
||||
}
|
||||
|
||||
val peerAddr = HostAndPort.fromString(options.valuesOf(fakeTradeWithArg).single()).withDefaultPort(Node.DEFAULT_PORT)
|
||||
val otherSide = ArtemisMessagingService.makeRecipient(peerAddr)
|
||||
val seller = TraderDemoProtocolSeller(myNetAddr, otherSide)
|
||||
@ -112,7 +130,7 @@ fun main(args: Array<String>) {
|
||||
|
||||
// We create a couple of ad-hoc test protocols that wrap the two party trade protocol, to give us the demo logic.
|
||||
|
||||
class TraderDemoProtocolBuyer() : ProtocolLogic<Unit>() {
|
||||
class TraderDemoProtocolBuyer(private val attachmentsPath: Path) : ProtocolLogic<Unit>() {
|
||||
companion object {
|
||||
object WAITING_FOR_SELLER_TO_CONNECT : ProgressTracker.Step("Waiting for seller to connect to us")
|
||||
object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset")
|
||||
@ -146,17 +164,38 @@ class TraderDemoProtocolBuyer() : ProtocolLogic<Unit>() {
|
||||
|
||||
logger.info("Purchase complete - we are a happy customer! Final transaction is: " +
|
||||
"\n\n${Emoji.renderIfSupported(tradeTX.tx)}")
|
||||
|
||||
logIssuanceAttachment(tradeTX)
|
||||
} catch(e: Exception) {
|
||||
logger.error("Something went wrong whilst trading!", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun logIssuanceAttachment(tradeTX: SignedTransaction) {
|
||||
// Find the original CP issuance.
|
||||
val search = TransactionGraphSearch(serviceHub.storageService.validatedTransactions, listOf(tradeTX.tx))
|
||||
search.query = TransactionGraphSearch.Query(withCommandOfType = CommercialPaper.Commands.Issue::class.java)
|
||||
val cpIssuance = search.call().single()
|
||||
|
||||
cpIssuance.attachments.first().let {
|
||||
val p = attachmentsPath.toAbsolutePath().resolve("$it.jar")
|
||||
logger.info("""
|
||||
|
||||
The issuance of the commercial paper came with an attachment. You can find it expanded in this directory:
|
||||
$p
|
||||
|
||||
${Emoji.renderIfSupported(cpIssuance)}""")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TraderDemoProtocolSeller(val myAddress: HostAndPort,
|
||||
val otherSide: SingleMessageRecipient,
|
||||
override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic<Unit>() {
|
||||
companion object {
|
||||
val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9")
|
||||
|
||||
object ANNOUNCING : ProgressTracker.Step("Announcing to the buyer node")
|
||||
object SELF_ISSUING : ProgressTracker.Step("Got session ID back, issuing and timestamping some commercial paper")
|
||||
object TRADING : ProgressTracker.Step("Starting the trade protocol")
|
||||
@ -179,7 +218,7 @@ class TraderDemoProtocolSeller(val myAddress: HostAndPort,
|
||||
|
||||
val tsa = serviceHub.networkMapService.timestampingNodes[0]
|
||||
val cpOwnerKey = serviceHub.keyManagementService.freshKey()
|
||||
val commercialPaper = makeFakeCommercialPaper(cpOwnerKey.public, tsa)
|
||||
val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, tsa)
|
||||
|
||||
progressTracker.currentStep = TRADING
|
||||
|
||||
@ -199,19 +238,25 @@ class TraderDemoProtocolSeller(val myAddress: HostAndPort,
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
fun makeFakeCommercialPaper(ownedBy: PublicKey, tsa: LegallyIdentifiableNode): StateAndRef<CommercialPaper.State> {
|
||||
fun selfIssueSomeCommercialPaper(ownedBy: PublicKey, tsa: LegallyIdentifiableNode): StateAndRef<CommercialPaper.State> {
|
||||
// Make a fake company that's issued its own paper.
|
||||
val keyPair = generateKeyPair()
|
||||
val party = Party("MegaCorp, Inc", keyPair.public)
|
||||
val party = Party("Bank of London", keyPair.public)
|
||||
|
||||
val issuance = run {
|
||||
val tx = CommercialPaper().generateIssue(party.ref(1,2,3), 1100.DOLLARS, Instant.now() + 10.days)
|
||||
|
||||
// TODO: Consider moving these two steps below into generateIssue.
|
||||
|
||||
// Attach the prospectus.
|
||||
tx.addAttachment(serviceHub.storageService.attachments.openAttachment(PROSPECTUS_HASH)!!)
|
||||
|
||||
// Timestamp it, all CP must be timestamped.
|
||||
tx.setTime(Instant.now(), tsa.identity, 30.seconds)
|
||||
val tsaSig = subProtocol(TimestampingProtocol(tsa, tx.toWireTransaction().serialized))
|
||||
tx.checkAndAddSignature(tsaSig)
|
||||
|
||||
tx.signWith(keyPair)
|
||||
|
||||
tx.toSignedTransaction(true)
|
||||
}
|
||||
|
||||
|
BIN
src/main/resources/core/node/bank-of-london-cp.jar
Normal file
BIN
src/main/resources/core/node/bank-of-london-cp.jar
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user