Simplifies two-party trade protocol to return SignedTransaction instead of a pair of other forms.

This commit is contained in:
Mike Hearn 2016-02-12 15:49:18 +01:00
parent 6deef5b598
commit 9f4897f7c4
4 changed files with 32 additions and 33 deletions

View File

@ -111,7 +111,7 @@ each side.
fun runSeller(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode,
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount,
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<Pair<WireTransaction, LedgerTransaction>> {
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<SignedTransaction> {
val seller = Seller(otherSide, timestampingAuthority, assetToSell, price, myKeyPair, buyerSessionID)
smm.add("$TRADE_TOPIC.seller", seller)
return seller.resultFuture
@ -119,7 +119,7 @@ each side.
fun runBuyer(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode,
otherSide: SingleMessageRecipient, acceptablePrice: Amount, typeToBuy: Class<out OwnableState>,
sessionID: Long): ListenableFuture<Pair<WireTransaction, LedgerTransaction>> {
sessionID: Long): ListenableFuture<SignedTransaction> {
val buyer = Buyer(otherSide, timestampingAuthority.identity, acceptablePrice, typeToBuy, sessionID)
smm.add("$TRADE_TOPIC.buyer", buyer)
return buyer.resultFuture
@ -140,9 +140,9 @@ each side.
val assetToSell: StateAndRef<OwnableState>,
val price: Amount,
val myKeyPair: KeyPair,
val buyerSessionID: Long) : ProtocolStateMachine<Pair<WireTransaction, LedgerTransaction>>() {
val buyerSessionID: Long) : ProtocolStateMachine<SignedTransaction>() {
@Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> {
override fun call(): SignedTransaction {
TODO()
}
}
@ -156,9 +156,9 @@ each side.
val timestampingAuthority: Party,
val acceptablePrice: Amount,
val typeToBuy: Class<out OwnableState>,
val sessionID: Long) : ProtocolStateMachine<Pair<WireTransaction, LedgerTransaction>>() {
val sessionID: Long) : ProtocolStateMachine<SignedTransaction>() {
@Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> {
override fun call(): SignedTransaction {
TODO()
}
}
@ -251,9 +251,9 @@ Let's implement the ``Seller.call`` method. This will be invoked by the platform
val ourSignature = signWithOurKey(partialTX)
val tsaSig = timestamp(partialTX)
val ledgerTX = sendSignatures(partialTX, ourSignature, tsaSig)
val stx: SignedTransaction = sendSignatures(partialTX, ourSignature, tsaSig)
return Pair(partialTX.tx, ledgerTX)
return stx
Here we see the outline of the procedure. We receive a proposed trade transaction from the buyer and check that it's
valid. Then we sign with our own key, request a timestamping authority to assert with another signature that the
@ -338,16 +338,16 @@ Here's the rest of the code:
@Suspendable
open fun sendSignatures(partialTX: SignedTransaction, ourSignature: DigitalSignature.WithKey,
tsaSig: DigitalSignature.LegallyIdentifiable): LedgerTransaction {
tsaSig: DigitalSignature.LegallyIdentifiable): SignedTransaction {
val fullySigned = partialTX + tsaSig + ourSignature
val ltx = fullySigned.verifyToLedgerTransaction(serviceHub.identityService)
fullySigned.verify()
// TODO: We should run it through our full TransactionGroup of all transactions here.
logger.trace { "Built finished transaction, sending back to secondary!" }
send(TRADE_TOPIC, otherSide, buyerSessionID, SignaturesFromSeller(tsaSig, ourSignature))
return ltx
return fullySigned
}
It's should be all pretty straightforward: here, ``txBits`` is the raw byte array representing the transaction.
@ -372,7 +372,7 @@ OK, let's do the same for the buyer side:
.. sourcecode:: kotlin
@Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> {
override fun call(): SignedTransaction {
val tradeRequest = receiveAndValidateTradeRequest()
val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
val stx = signWithOurKeys(cashSigningPubKeys, ptx)
@ -380,10 +380,10 @@ OK, let's do the same for the buyer side:
logger.trace { "Got signatures from seller, verifying ... "}
val fullySigned = stx + signatures.timestampAuthoritySig + signatures.sellerSig
val ltx = fullySigned.verifyToLedgerTransaction(serviceHub.identityService)
fullySigned.verify()
logger.trace { "Fully signed transaction was valid. Trade complete! :-)" }
return Pair(fullySigned.tx, ltx)
return fullySigned
}
@Suspendable

View File

@ -53,7 +53,7 @@ object TwoPartyTradeProtocol {
fun runSeller(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode,
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount,
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<Pair<WireTransaction, LedgerTransaction>> {
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<SignedTransaction> {
val seller = Seller(otherSide, timestampingAuthority, assetToSell, price, myKeyPair, buyerSessionID)
smm.add("$TRADE_TOPIC.seller", seller)
return seller.resultFuture
@ -61,7 +61,7 @@ object TwoPartyTradeProtocol {
fun runBuyer(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode,
otherSide: SingleMessageRecipient, acceptablePrice: Amount, typeToBuy: Class<out OwnableState>,
sessionID: Long): ListenableFuture<Pair<WireTransaction, LedgerTransaction>> {
sessionID: Long): ListenableFuture<SignedTransaction> {
val buyer = Buyer(otherSide, timestampingAuthority.identity, acceptablePrice, typeToBuy, sessionID)
smm.add("$TRADE_TOPIC.buyer", buyer)
return buyer.resultFuture
@ -82,18 +82,18 @@ object TwoPartyTradeProtocol {
val assetToSell: StateAndRef<OwnableState>,
val price: Amount,
val myKeyPair: KeyPair,
val buyerSessionID: Long) : ProtocolStateMachine<Pair<WireTransaction, LedgerTransaction>>() {
val buyerSessionID: Long) : ProtocolStateMachine<SignedTransaction>() {
@Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> {
override fun call(): SignedTransaction {
val partialTX: SignedTransaction = receiveAndCheckProposedTransaction()
// These two steps could be done in parallel, in theory. Our framework doesn't support that yet though.
val ourSignature = signWithOurKey(partialTX)
val tsaSig = timestamp(partialTX)
val ledgerTX = sendSignatures(partialTX, ourSignature, tsaSig)
val signedTransaction = sendSignatures(partialTX, ourSignature, tsaSig)
return Pair(partialTX.tx, ledgerTX)
return signedTransaction
}
@Suspendable
@ -136,16 +136,15 @@ object TwoPartyTradeProtocol {
@Suspendable
open fun sendSignatures(partialTX: SignedTransaction, ourSignature: DigitalSignature.WithKey,
tsaSig: DigitalSignature.LegallyIdentifiable): LedgerTransaction {
tsaSig: DigitalSignature.LegallyIdentifiable): SignedTransaction {
val fullySigned = partialTX + tsaSig + ourSignature
val ltx = fullySigned.verifyToLedgerTransaction(serviceHub.identityService)
// TODO: We should run it through our full TransactionGroup of all transactions here.
logger.trace { "Built finished transaction, sending back to secondary!" }
send(TRADE_TOPIC, otherSide, buyerSessionID, SignaturesFromSeller(tsaSig, ourSignature))
return ltx
return fullySigned
}
}
@ -158,9 +157,9 @@ object TwoPartyTradeProtocol {
val timestampingAuthority: Party,
val acceptablePrice: Amount,
val typeToBuy: Class<out OwnableState>,
val sessionID: Long) : ProtocolStateMachine<Pair<WireTransaction, LedgerTransaction>>() {
val sessionID: Long) : ProtocolStateMachine<SignedTransaction>() {
@Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> {
override fun call(): SignedTransaction {
val tradeRequest = receiveAndValidateTradeRequest()
val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
val stx = signWithOurKeys(cashSigningPubKeys, ptx)
@ -168,10 +167,10 @@ object TwoPartyTradeProtocol {
logger.trace { "Got signatures from seller, verifying ... "}
val fullySigned = stx + signatures.timestampAuthoritySig + signatures.sellerSig
val ltx = fullySigned.verifyToLedgerTransaction(serviceHub.identityService)
fullySigned.verify()
logger.trace { "Fully signed transaction was valid. Trade complete! :-)" }
return Pair(fullySigned.tx, ltx)
logger.trace { "Signatures received are valid. Trade complete! :-)" }
return fullySigned
}
@Suspendable

View File

@ -110,7 +110,7 @@ fun main(args: Array<String>) {
println()
println("Purchase complete - we are a happy customer! Final transaction is:")
println()
println(Emoji.renderIfSupported(it.first))
println(Emoji.renderIfSupported(it))
println()
println("Waiting for another seller to connect. Or press Ctrl-C to shut me down.")
}
@ -145,7 +145,7 @@ fun main(args: Array<String>) {
println()
println("Final transaction is")
println()
println(Emoji.renderIfSupported(it.first))
println(Emoji.renderIfSupported(it))
println()
node.stop()
}

View File

@ -88,7 +88,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
assertEquals(aliceResult.get(), bobResult.get())
txns.add(aliceResult.get().first)
txns.add(aliceResult.get().tx)
verify()
}
}
@ -178,8 +178,8 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
assertTrue(bobsNode.pump(false))
// Bob is now finished and has the same transaction as Alice.
val tx = bobFuture.get()
txns.add(tx.first)
val stx = bobFuture.get()
txns.add(stx.tx)
verify()
assertTrue(smm.stateMachines.isEmpty())