Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.magiadigital.cobranzas.flow
- import co.paralleluniverse.fibers.Suspendable
- import com.magiadigital.cobranzas.contract.DocumentContract
- import com.magiadigital.cobranzas.state.DocumentState
- import net.corda.core.contracts.*
- import net.corda.core.crypto.Party
- import net.corda.core.crypto.SecureHash
- import net.corda.core.crypto.composite
- import net.corda.core.crypto.signWithECDSA
- import net.corda.core.flows.FlowLogic
- import net.corda.core.node.ServiceHub
- import net.corda.core.node.services.Vault
- import net.corda.core.node.services.linearHeadsOfType
- import net.corda.core.node.services.unconsumedStates
- import net.corda.core.seconds
- import net.corda.core.transactions.SignedTransaction
- import net.corda.core.utilities.ProgressTracker
- import net.corda.core.utilities.unwrap
- import net.corda.flows.FinalityFlow
- import net.corda.flows.NotaryFlow
- import java.util.EnumSet
- import net.corda.core.contracts.*
- import net.corda.core.crypto.*
- import net.corda.core.node.PluginServiceHub
- import net.corda.core.node.services.linearHeadsOfType
- import net.corda.core.serialization.CordaSerializable
- import net.corda.core.utilities.unwrap
- import java.security.PublicKey
- import java.time.Duration
- /**
- * This flow allows two parties (the [Initiator] and the [Acceptor]) to come to an agreement about the Document encapsulated
- * within an [DocumentState].
- *
- * In our simple example, the [Acceptor] always accepts a valid Document.
- *
- * These flows have deliberately been implemented by using only the call() method for ease of understanding. In
- * practice we would recommend splitting up the various stages of the flow into sub-routines.
- *
- * All methods called within the [FlowLogic] sub-class need to be annotated with the @Suspendable annotation.
- */
- object DocumentFlow {
- // Helper method to locate the latest Vault version of a LinearState from a possibly out of date StateRef
- inline fun <reified T : LinearState> ServiceHub.latest(ref: StateRef): StateAndRef<T> {
- val linearHeads = vaultService.linearHeadsOfType<T>()
- val original = toStateAndRef<T>(ref)
- return linearHeads.get(original.state.data.linearId)!!
- }
- class Initiator(val document: DocumentState,
- val globoKAS: Party): FlowLogic<StateAndRef<DocumentState>>() {
- /**
- * The progress tracker checkpoints each stage of the flow and outputs the specified messages when each
- * checkpoint is reached in the code. See the 'progressTracker.currentStep' expressions within the call() function.
- */
- companion object {
- object GENERATING_TRANSACTION : ProgressTracker.Step("Generating transaction based on new Document.")
- object VERIFYING_TRANSACTION : ProgressTracker.Step("Verifying contract constraints.")
- object SIGNING_TRANSACTION : ProgressTracker.Step("Signing transaction with our private key.")
- object SENDING_TRANSACTION : ProgressTracker.Step("Sending proposed transaction to recipient for review.")
- fun tracker() = ProgressTracker(
- GENERATING_TRANSACTION,
- VERIFYING_TRANSACTION,
- SIGNING_TRANSACTION,
- SENDING_TRANSACTION
- )
- }
- override val progressTracker = tracker()
- /**
- * The flow logic is encapsulated within the call() method.
- */
- @Suspendable
- override fun call(): StateAndRef<DocumentState> {
- println("Arranco FLOW Initiator")
- // Prep.
- // Obtain a reference to our key pair. Currently, the only key pair used is the one which is registered
- // with the NetWorkMapService. In a future milestone release we'll implement HD key generation so that
- // new keys can be generated for each transaction.
- val keyPair = serviceHub.legalIdentityKey
- // Obtain a reference to the notary we want to use.
- //val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity
- val notary = serviceHub.networkMapCache.getAnyNotary()
- // Create the TransactionBuilder and populate with the new state.
- val tx = TransactionType.General.Builder(notary)
- .withItems(document, Command(DocumentContract.Commands.Create(), listOf(document.company.owningKey)))
- tx.setTime(serviceHub.clock.instant(), Duration.ofSeconds(60))
- // We can automatically sign as there is no untrusted data.
- tx.signWith(serviceHub.legalIdentityKey)
- // Convert to a SignedTransaction that we can send to the notary
- val signedTx = tx.toSignedTransaction(false)
- // Notarise and distribute.
- subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.legalIdentity, globoKAS)))
- // Return the initial state
- return signedTx.tx.outRef<DocumentState>(0)
- // // Stage 1.
- // progressTracker.currentStep = GENERATING_TRANSACTION
- // // Generate an unsigned transaction.
- // val txCommand = Command(DocumentContract.Commands.Create(), document.participants)
- // val unsignedTx = TransactionType.General.Builder(notary).withItems(document, txCommand)
- //
- // // Stage 2.
- // progressTracker.currentStep = VERIFYING_TRANSACTION
- // // Verify that the transaction is valid.
- // unsignedTx.toWireTransaction().toLedgerTransaction(serviceHub).verify()
- //
- // // Stage 3.
- // progressTracker.currentStep = SIGNING_TRANSACTION
- // val partSignedTx = unsignedTx.signWith(keyPair).toSignedTransaction(checkSufficientSignatures = false)
- //
- // // Stage 4.
- // progressTracker.currentStep = SENDING_TRANSACTION
- // // Send the state across the wire to the designated counterparty.
- // // -----------------------
- // // Flow jumps to Acceptor.
- // // -----------------------
- // send(otherParty, partSignedTx)
- //
- // return waitForLedgerCommit(partSignedTx.id)
- }
- }
- // class Acceptor(val otherParty: Party) : FlowLogic<Unit>() {
- // companion object {
- // object RECEIVING_TRANSACTION : ProgressTracker.Step("Receiving proposed transaction from sender.")
- // object VERIFYING_TRANSACTION : ProgressTracker.Step("Verifying signatures and contract constraints.")
- // object SIGNING_TRANSACTION : ProgressTracker.Step("Signing proposed transaction with our private key.")
- // object FINALISING_TRANSACTION : ProgressTracker.Step("Obtaining notary signature and recording transaction.")
- //
- // fun tracker() = ProgressTracker(
- // RECEIVING_TRANSACTION,
- // VERIFYING_TRANSACTION,
- // SIGNING_TRANSACTION,
- // FINALISING_TRANSACTION
- // )
- // }
- //
- // override val progressTracker = tracker()
- //
- // @Suspendable
- // override fun call() {
- // println("Arranco FLOW Acceptor")
- // // Prep.
- // // Obtain a reference to our key pair.
- // val keyPair = serviceHub.legalIdentityKey
- // // Obtain a reference to the notary we want to use and its public key.
- // val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity
- // val notaryPubKey = notary.owningKey
- //
- // // Stage 5.
- // progressTracker.currentStep = RECEIVING_TRANSACTION
- // // All messages come off the wire as UntrustworthyData. You need to 'unwrap' them. This is where you
- // // validate what you have just received.
- // val partSignedTx = receive<SignedTransaction>(otherParty).unwrap { partSignedTx ->
- // // Stage 6.
- // progressTracker.currentStep = VERIFYING_TRANSACTION
- // // Check that the signature of the other party is valid.
- // // Our signature and the notary's signature are allowed to be omitted at this stage as this is only
- // // a partially signed transaction.
- // val wireTx = partSignedTx.verifySignatures(keyPair.public.composite, notaryPubKey)
- // // Run the contract's verify function.
- // // We want to be sure that the agreed-upon Document is valid under the rules of the contract.
- // // To do this we need to run the contract's verify() function.
- // wireTx.toLedgerTransaction(serviceHub).verify()
- // // We've verified the signed transaction and return it.
- // partSignedTx
- // }
- //
- // // Stage 7.
- // progressTracker.currentStep = SIGNING_TRANSACTION
- // // Sign the transaction with our key pair and add it to the transaction.
- // // We now have 'validation consensus'. We still require uniqueness consensus.
- // // Technically validation consensus for this type of agreement implicitly provides uniqueness consensus.
- // val mySig = keyPair.signWithECDSA(partSignedTx.id.bytes)
- // // Add our signature to the transaction.
- // val signedTx = partSignedTx + mySig
- //
- // // Stage 8.
- // progressTracker.currentStep = FINALISING_TRANSACTION
- // // FinalityFlow() notarises the transaction and records it in each party's vault.
- // subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.legalIdentity, otherParty)))
- // }
- // }
- /**
- * Esto siempre se tiene que ejecutar solo en el nodo Collector.
- * Una vez finalizado el flujo se actualiza el documento de cobranza en ambos Vaults.
- */
- class InitCharged(val linearId: String): FlowLogic<SignedTransaction>() {
- companion object {
- object RETRIEVING_DOCUMENT : ProgressTracker.Step("Retrieving the document.")
- object UPDATING_DOCUMENT_FLAG_CHARGED : ProgressTracker.Step("Updating new charged state to the document.")
- object CONSTRUCTING_TRANSACTION : ProgressTracker.Step("Constructing transaction to commit")
- object TIMESTAMPING_TRANSACTION : ProgressTracker.Step("Timestamping transaction.")
- object SIGNING_TRANSACTION : ProgressTracker.Step("Signing transaction with our private key.")
- object NOTARISING_TRANSACTION : ProgressTracker.Step("Signing transaction and notarizing.")
- object RECORDING_TRANSACTION : ProgressTracker.Step("Record transaction in collectors company vault.")
- object SENDING_TO_COMPANY : ProgressTracker.Step("Sending transaction to company.")
- fun tracker() = ProgressTracker(
- RETRIEVING_DOCUMENT,
- UPDATING_DOCUMENT_FLAG_CHARGED,
- CONSTRUCTING_TRANSACTION,
- TIMESTAMPING_TRANSACTION,
- SIGNING_TRANSACTION,
- NOTARISING_TRANSACTION,
- RECORDING_TRANSACTION,
- SENDING_TO_COMPANY
- )
- }
- override val progressTracker = tracker()
- @Suspendable
- override fun call() : SignedTransaction {
- println("***** Arranco FLOW InitCharge *****")
- println(serviceHub.myInfo.legalIdentity.name)
- // Naively, wrapped the whole flow in a try ... catch block so we can
- // push the exceptions back through the web API.
- val myKeyPair = serviceHub.legalIdentityKey
- //val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity
- // Stage 1 - Retrieve the input purchaseOrderState
- progressTracker.currentStep = RETRIEVING_DOCUMENT
- val documentStates = serviceHub.vaultService.unconsumedStates<DocumentState>()
- var docRef : StateRef = StateRef(SecureHash.zeroHash,0)
- println("documentStates = " + documentStates)
- for (c in documentStates) {
- println(c.ref)
- println(c.state.data.linearId)
- println(c.state.data.document.payer)
- if (c.state.data.document.payer == linearId) {
- println("Entro al IF del linearId")
- docRef = c.ref
- }
- }
- println("docRef = " + docRef)
- val documentStateAndRef = serviceHub.latest<DocumentState>(docRef)
- println("documentStateAndRef = " + documentStateAndRef)
- println("***** pass documentStateAndRef *****")
- // Stage 2 - Create the updated output purchase order
- progressTracker.currentStep = UPDATING_DOCUMENT_FLAG_CHARGED
- val newDocumentState = documentStateAndRef.state.data.copy(flagCharged = true)
- println("***** pass Stage2 *****")
- // We have to use the original notary for the new transaction
- val notary = documentStateAndRef.state.notary
- // Stage 3 - Generate an unsigned transaction
- progressTracker.currentStep = CONSTRUCTING_TRANSACTION
- val txBuilder = TransactionType.General.Builder(notary)
- .withItems(
- // Input state.
- documentStateAndRef,
- //Output state.
- newDocumentState,
- // Command.
- Command(
- DocumentContract.Commands.Collect(),
- listOf(serviceHub.myInfo.legalIdentity.owningKey, documentStateAndRef.state.data.company.owningKey))
- )
- println("***** pass Stage3 *****")
- txBuilder.setTime(serviceHub.clock.instant(), Duration.ofSeconds(60))
- // We can sign this transaction immediately as we have already checked all the fields and the decision
- // is ultimately a manual one from the caller.
- txBuilder.signWith(serviceHub.legalIdentityKey)
- // Convert to SignedTransaction we can pass around certain that it cannot be modified.
- val selfSignedTx = txBuilder.toSignedTransaction(false)
- println("***** pass antes del sendAndReceive *****")
- // Send the signed transaction to the company and await their signature to confirm
- val allPartySignedTx = sendAndReceive<DigitalSignature.WithKey>(newDocumentState.company, selfSignedTx).unwrap {
- // Add their signature to our unmodified transaction. To check they signed the same tx.
- println("***** it 1 *****")
- val agreedTx = selfSignedTx + it
- // Receive back their signature and confirm that it is for an unmodified transaction
- // Also that the only missing signature is from teh Notary
- println("***** it 2 *****")
- agreedTx.verifySignatures(notary.owningKey)
- // Recheck the data of the transaction. Note we run toLedgerTransaction on the WireTransaction
- // as we do not have all the signature.
- println("***** it 3 *****")
- agreedTx.tx.toLedgerTransaction(serviceHub).verify()
- // return the SignedTransaction to notarise
- println("***** it 4 *****")
- agreedTx
- }
- // Notarise and distribute the completed transaction.
- println("***** subflow *****")
- subFlow(FinalityFlow(allPartySignedTx, setOf(documentStateAndRef.state.data.company, documentStateAndRef.state.data.collector)))
- return(allPartySignedTx)
- // txBuilder.toWireTransaction().toLedgerTransaction(serviceHub).verify()
- //
- // // Stage 4 - Add a timestamp, as mandated by the contract code
- //// progressTracker.currentStep = TIMESTAMPING_TRANSACTION
- //// val currentTime = serviceHub.clock.instant()
- //// txBuilder.setTime(currentTime, 30.seconds)
- //// println("***** pass Stage4 *****")
- //
- // // Stage 5 - Sign the transaction
- // progressTracker.currentStep = SIGNING_TRANSACTION
- // val sigTx = txBuilder.signWith(myKeyPair).toSignedTransaction(checkSufficientSignatures = false)
- // println("***** pass Stage5 *****")
- //
- // // Stage 6 - Obtain the notary's signature
- //// progressTracker.currentStep = NOTARISING_TRANSACTION
- //// val notarySignature = subFlow(NotaryFlow.Client(sigTx))
- //// val notTx = sigTx + notarySignature
- //// println("***** pass Stage6 *****")
- //
- // // Stage 7 - Record the transaction in our vault
- //// progressTracker.currentStep = RECORDING_TRANSACTION
- //// serviceHub.recordTransactions(listOf(sigTx))
- //// println("***** pass Stage7 *****")
- //
- // // Stage 8 - Send the transaction to the counterparty
- // progressTracker.currentStep = SENDING_TO_COMPANY
- // println("***** justo antes del send *****")
- // println("company = " + documentStateAndRef.state.data.company)
- // println("sigTx = " + sigTx)
- // send(documentStateAndRef.state.data.company, sigTx)
- // println("***** pass Stage8 *****")
- //
- // //return waitForLedgerCommit(sigTx.id)
- // return(sigTx)
- }
- }
- /**
- * Esto finaliza el flujo para indicar que un documento ya a sido cobrado y es guardado en el Vault de la empresa.
- */
- class EndCharged(val source: Party): FlowLogic<Unit>() {
- companion object {
- object RECEIVING_END_TRANSACTION : ProgressTracker.Step("Receiving proposed transaction from sender.")
- object VERIFYING_END_TRANSACTION : ProgressTracker.Step("Verifying signatures and contract constraints.")
- object SIGNING_END_TRANSACTION : ProgressTracker.Step("Signing proposed transaction with our private key.")
- object FINALISING_END_TRANSACTION : ProgressTracker.Step("Obtaining notary signature and recording transaction.")
- fun tracker() = ProgressTracker(
- RECEIVING_END_TRANSACTION,
- VERIFYING_END_TRANSACTION,
- SIGNING_END_TRANSACTION,
- FINALISING_END_TRANSACTION
- )
- }
- override val progressTracker = tracker()
- @Suspendable
- override fun call(): Unit {
- println("Arranco FLOW EndCharged")
- // First we receive the verdict transaction signed by their single key
- val completeTx = receive<SignedTransaction>(source).unwrap {
- // Check the transaction is signed apart from our own key and the notary
- val wtx = it.verifySignatures(serviceHub.myInfo.legalIdentity.owningKey, it.tx.notary!!.owningKey)
- // Check the transaction data is correctly formed
- wtx.toLedgerTransaction(serviceHub).verify()
- // Confirm that this is the expected type of transaction
- require(wtx.commands.single().value is DocumentContract.Commands.Collect) {
- "Transaction must represent a workflow completion"
- }
- // Check the context dependent parts of the transaction as the
- // Contract verify method must not use serviceHub queries.
- val state = wtx.outRef<DocumentState>(0)
- require(state.state.data.company == serviceHub.myInfo.legalIdentity) {
- "Document for collect not one of our original proposals"
- }
- require(state.state.data.collector == source) {
- "This document charged not for send from correct collector"
- }
- it
- }
- // DOCEND 3
- // Having verified the SignedTransaction passed to us we can sign it too
- val ourSignature = serviceHub.legalIdentityKey.signWithECDSA(completeTx.tx.id)
- // Send our signature to the other party.
- send(source, ourSignature)
- // N.B. The FinalityProtocol will be responsible for Notarising the SignedTransaction
- // and broadcasting the result to us.
- // // Prep.
- // // Obtain a reference to our key pair.
- // val keyPair = serviceHub.legalIdentityKey
- // // Obtain a reference to the notary we want to use and its public key.
- // val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity
- // val notaryPubKey = notary.owningKey
- //
- // // Stage 5.
- // progressTracker.currentStep = EndCharged.Companion.RECEIVING_END_TRANSACTION
- // // All messages come off the wire as UntrustworthyData. You need to 'unwrap' them. This is where you
- // // validate what you have just received.
- // val partSignedTx = receive<SignedTransaction>(company).unwrap { partSignedTx ->
- // // Stage 6.
- // progressTracker.currentStep = EndCharged.Companion.VERIFYING_END_TRANSACTION
- // // Check that the signature of the other party is valid.
- // // Our signature and the notary's signature are allowed to be omitted at this stage as this is only
- // // a partially signed transaction.
- // val wireTx = partSignedTx.verifySignatures(keyPair.public.composite, notaryPubKey)
- // // Run the contract's verify function.
- // // We want to be sure that the agreed-upon Document is valid under the rules of the contract.
- // // To do this we need to run the contract's verify() function.
- // wireTx.toLedgerTransaction(serviceHub).verify()
- // // We've verified the signed transaction and return it.
- // partSignedTx
- // }
- //
- // // Stage 7.
- // progressTracker.currentStep = EndCharged.Companion.SIGNING_END_TRANSACTION
- // // Sign the transaction with our key pair and add it to the transaction.
- // // We now have 'validation consensus'. We still require uniqueness consensus.
- // // Technically validation consensus for this type of agreement implicitly provides uniqueness consensus.
- // val mySig = keyPair.signWithECDSA(partSignedTx.id.bytes)
- // // Add our signature to the transaction.
- // val signedTx = partSignedTx + mySig
- //
- // // Stage 8.
- // progressTracker.currentStep = EndCharged.Companion.FINALISING_END_TRANSACTION
- // // FinalityFlow() notarises the transaction and records it in each party's vault.
- // subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.legalIdentity, company)))
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement