-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split the Issue, Move and Redeem flows into the general and an extra custom flow #47
Open
IgorWolkov
wants to merge
5
commits into
corda:master
Choose a base branch
from
KarazinScalaUsersGroup:issue-move-redeem-extra-flow
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
59b1248
Split the Issue, Move and Redeem flows into the general and an extra …
IgorWolkov ebbee92
To trigger build on CI/CD
przemolb ea7bf1f
Again trying to trigger cicd
przemolb 91f4352
Update IssueToken.kt
przemolb 7165ace
Update IssueToken.kt
przemolb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,19 +12,15 @@ import com.r3.corda.sdk.token.contracts.utilities.withNotary | |
import com.r3.corda.sdk.token.workflow.utilities.addPartyToDistributionList | ||
import net.corda.core.contracts.Amount | ||
import net.corda.core.contracts.TransactionState | ||
import net.corda.core.flows.FinalityFlow | ||
import net.corda.core.flows.FlowLogic | ||
import net.corda.core.flows.FlowSession | ||
import net.corda.core.flows.InitiatedBy | ||
import net.corda.core.flows.InitiatingFlow | ||
import net.corda.core.flows.ReceiveFinalityFlow | ||
import net.corda.core.flows.StartableByRPC | ||
import net.corda.core.contracts.requireThat | ||
import net.corda.core.flows.* | ||
import net.corda.core.identity.AbstractParty | ||
import net.corda.core.identity.Party | ||
import net.corda.core.node.StatesToRecord | ||
import net.corda.core.transactions.SignedTransaction | ||
import net.corda.core.transactions.TransactionBuilder | ||
import net.corda.core.utilities.ProgressTracker | ||
import java.security.PublicKey | ||
|
||
/** | ||
* This flow takes a bunch of parameters and is used to issue a token or an amount of some token on the ledger to | ||
|
@@ -59,11 +55,10 @@ import net.corda.core.utilities.ProgressTracker | |
* TODO: Split into two flows. One for owned tokens and another for owned token amounts. | ||
* TODO: Profile and optimise this flow. | ||
*/ | ||
|
||
object IssueToken { | ||
|
||
@InitiatingFlow | ||
@StartableByRPC | ||
class Initiator<T : TokenType>( | ||
abstract class Primary<T : TokenType>( | ||
val token: T, | ||
val issueTo: AbstractParty, | ||
val notary: Party, | ||
|
@@ -72,26 +67,27 @@ object IssueToken { | |
) : FlowLogic<SignedTransaction>() { | ||
companion object { | ||
object DIST_LIST : ProgressTracker.Step("Adding party to distribution list.") | ||
object EXTRA_FLOW : ProgressTracker.Step("Starting extra flow") | ||
object SIGNING : ProgressTracker.Step("Signing transaction proposal.") | ||
object RECORDING : ProgressTracker.Step("Recording signed transaction.") { | ||
override fun childProgressTracker() = FinalityFlow.tracker() | ||
} | ||
|
||
fun tracker() = ProgressTracker(DIST_LIST, SIGNING, RECORDING) | ||
fun tracker() = ProgressTracker(DIST_LIST, EXTRA_FLOW, SIGNING, RECORDING) | ||
} | ||
|
||
override val progressTracker: ProgressTracker = tracker() | ||
|
||
@Suspendable | ||
override fun call(): SignedTransaction { | ||
// This is the identity which will be used to issue tokens. | ||
// We also need a session for the other side. | ||
val me: Party = ourIdentity | ||
val holderParty = serviceHub.identityService.wellKnownPartyFromAnonymous(issueTo) | ||
?: throw IllegalArgumentException("Called IssueToken flow with anonymous party that node doesn't know about. " + | ||
"Make sure that RequestConfidentialIdentity flow is called before.") | ||
val holderSession = if (session == null) initiateFlow(holderParty) else session | ||
abstract fun transactionExtra(me: Party, | ||
holderParty: Party, | ||
holderSession: FlowSession, | ||
builder: TransactionBuilder): List<PublicKey> | ||
|
||
open fun issue(me: Party, | ||
holderParty: Party, | ||
holderSession: FlowSession, | ||
builder: TransactionBuilder): Unit { | ||
// Create the issued token. We add this to the commands for grouping. | ||
val issuedToken: IssuedTokenType<T> = token issuedBy me | ||
|
||
|
@@ -119,32 +115,96 @@ object IssueToken { | |
|
||
// Create the transaction. | ||
val transactionState: TransactionState<AbstractToken> = heldToken withNotary notary | ||
val utx: TransactionBuilder = TransactionBuilder(notary = notary).apply { | ||
|
||
builder.apply { | ||
addCommand(data = IssueTokenCommand(issuedToken), keys = listOf(me.owningKey)) | ||
addOutputState(state = transactionState) | ||
} | ||
} | ||
|
||
@Suspendable | ||
override fun call(): SignedTransaction { | ||
// This is the identity which will be used to issue tokens. | ||
// We also need a session for the other side. | ||
val me: Party = ourIdentity | ||
val holderParty = serviceHub.identityService.wellKnownPartyFromAnonymous(issueTo) | ||
?: throw IllegalArgumentException("Called IssueToken flow with anonymous party that node doesn't know about. " + | ||
"Make sure that RequestConfidentialIdentity flow is called before.") | ||
val holderSession = if (session == null) initiateFlow(holderParty) else session | ||
|
||
val builder = TransactionBuilder(notary = notary) | ||
issue(me, holderParty, holderSession, builder) | ||
|
||
progressTracker.currentStep = EXTRA_FLOW | ||
val extraKeys = transactionExtra(me, holderParty, holderSession, builder) | ||
|
||
progressTracker.currentStep = SIGNING | ||
// Sign the transaction. Only Concrete Parties should be used here. | ||
val stx: SignedTransaction = serviceHub.signInitialTransaction(utx) | ||
val ptx: SignedTransaction = serviceHub.signInitialTransaction(builder, listOf(me.owningKey)) | ||
progressTracker.currentStep = RECORDING | ||
// Can issue to yourself, but finality flow doesn't take a session then. | ||
val sessions = if (me == holderParty) emptyList() else listOf(holderSession) | ||
|
||
val stx = ptx + | ||
if (!serviceHub.myInfo.isLegalIdentity(holderSession.counterparty)) { | ||
subFlow(CollectSignatureFlow(ptx, holderSession, extraKeys)) | ||
} else { | ||
listOf() | ||
} | ||
|
||
return subFlow(FinalityFlow(transaction = stx, | ||
progressTracker = RECORDING.childProgressTracker(), | ||
sessions = sessions | ||
)) | ||
} | ||
} | ||
|
||
@InitiatedBy(Initiator::class) | ||
class Responder(val otherSession: FlowSession) : FlowLogic<Unit>() { | ||
abstract class Secondary(val otherSession: FlowSession) : FlowLogic<Unit>() { | ||
|
||
@Suspendable | ||
abstract fun checkTransaction(stx: SignedTransaction) | ||
|
||
@Suspendable | ||
override fun call(): Unit { | ||
// We must do this check because FinalityFlow does not send locally and we want to be able to issue to ourselves. | ||
if (!serviceHub.myInfo.isLegalIdentity(otherSession.counterparty)) { | ||
|
||
val signTransactionFlow = object : SignTransactionFlow(otherSession) { | ||
override fun checkTransaction(stx: SignedTransaction) = [email protected](stx) | ||
} | ||
|
||
val txId = subFlow(signTransactionFlow).id | ||
|
||
// Resolve the issuance transaction. | ||
subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, statesToRecord = StatesToRecord.ONLY_RELEVANT)) | ||
subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, | ||
statesToRecord = StatesToRecord.ONLY_RELEVANT, expectedTxId = txId)) | ||
} | ||
} | ||
} | ||
|
||
@InitiatingFlow | ||
@StartableByRPC | ||
class Initiator<T : TokenType>( | ||
token: T, | ||
issueTo: AbstractParty, | ||
notary: Party, | ||
amount: Amount<T>? = null, | ||
session: FlowSession? = null | ||
) : Primary<T>(token, issueTo, notary, amount, session) { | ||
|
||
@Suspendable | ||
override fun transactionExtra(me: Party, | ||
holderParty: Party, | ||
holderSession: FlowSession, | ||
builder: TransactionBuilder): List<PublicKey> { | ||
return listOf() | ||
} | ||
} | ||
|
||
@InitiatedBy(Initiator::class) | ||
class Responder(otherSession: FlowSession) : Secondary(otherSession) { | ||
|
||
@Suspendable | ||
override fun checkTransaction(stx: SignedTransaction) = requireThat { } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,74 +5,137 @@ import com.r3.corda.sdk.token.contracts.types.TokenType | |
import com.r3.corda.sdk.token.workflow.selection.TokenSelection | ||
import com.r3.corda.sdk.token.workflow.selection.generateMoveNonFungible | ||
import net.corda.core.contracts.Amount | ||
import net.corda.core.flows.FinalityFlow | ||
import net.corda.core.flows.FlowLogic | ||
import net.corda.core.flows.FlowSession | ||
import net.corda.core.flows.InitiatedBy | ||
import net.corda.core.flows.InitiatingFlow | ||
import net.corda.core.flows.ReceiveFinalityFlow | ||
import net.corda.core.flows.StartableByRPC | ||
import net.corda.core.contracts.requireThat | ||
import net.corda.core.flows.* | ||
import net.corda.core.identity.AbstractParty | ||
import net.corda.core.identity.Party | ||
import net.corda.core.node.StatesToRecord | ||
import net.corda.core.transactions.SignedTransaction | ||
import net.corda.core.transactions.TransactionBuilder | ||
import net.corda.core.utilities.ProgressTracker | ||
import java.security.PublicKey | ||
|
||
object MoveToken { | ||
|
||
@InitiatingFlow | ||
@StartableByRPC | ||
class Initiator<T : TokenType>( | ||
abstract class Primary<T : TokenType>( | ||
val ownedToken: T, | ||
val holder: AbstractParty, | ||
val amount: Amount<T>? = null, | ||
val session: FlowSession? = null | ||
) : FlowLogic<SignedTransaction>() { | ||
companion object { | ||
object GENERATE_MOVE : ProgressTracker.Step("Generating tokens move.") | ||
object EXTRA_FLOW : ProgressTracker.Step("Starting extra flow") | ||
object SIGNING : ProgressTracker.Step("Signing transaction proposal.") | ||
object RECORDING : ProgressTracker.Step("Recording signed transaction.") { | ||
override fun childProgressTracker() = FinalityFlow.tracker() | ||
} | ||
|
||
fun tracker() = ProgressTracker(GENERATE_MOVE, SIGNING, RECORDING) | ||
fun tracker() = ProgressTracker(GENERATE_MOVE, EXTRA_FLOW, SIGNING, RECORDING) | ||
} | ||
|
||
override val progressTracker: ProgressTracker = tracker() | ||
|
||
@Suspendable | ||
abstract fun transactionExtra(me: Party, | ||
holderParty: Party, | ||
holderSession: FlowSession, | ||
builder: TransactionBuilder): List<PublicKey> | ||
|
||
@Suspendable | ||
open fun move(holderParty: Party, | ||
holderSession: FlowSession): Pair<TransactionBuilder, List<PublicKey>> { | ||
|
||
return if (amount == null) { | ||
generateMoveNonFungible(serviceHub.vaultService, ownedToken, holder) | ||
} else { | ||
val tokenSelection = TokenSelection(serviceHub) | ||
tokenSelection.generateMove(TransactionBuilder(), amount, holder) | ||
} | ||
} | ||
|
||
@Suspendable | ||
override fun call(): SignedTransaction { | ||
val me: Party = ourIdentity | ||
val holderParty = serviceHub.identityService.wellKnownPartyFromAnonymous(holder) | ||
?: throw IllegalArgumentException("Called MoveToken flow with anonymous party that node doesn't know about. " + | ||
"Make sure that RequestConfidentialIdentity flow is called before.") | ||
val holderSession = if (session == null) initiateFlow(holderParty) else session | ||
|
||
progressTracker.currentStep = GENERATE_MOVE | ||
val (builder, keys) = if (amount == null) { | ||
generateMoveNonFungible(serviceHub.vaultService, ownedToken, holder) | ||
} else { | ||
val tokenSelection = TokenSelection(serviceHub) | ||
tokenSelection.generateMove(TransactionBuilder(), amount, holder) | ||
} | ||
val (builder, keys) = move(holderParty, holderSession) | ||
|
||
progressTracker.currentStep = EXTRA_FLOW | ||
val extraKeys = transactionExtra(me, holderParty, holderSession, builder) | ||
|
||
progressTracker.currentStep = SIGNING | ||
// WARNING: At present, the recipient will not be signed up to updates from the token maintainer. | ||
val stx: SignedTransaction = serviceHub.signInitialTransaction(builder, keys) | ||
val ptx: SignedTransaction = serviceHub.signInitialTransaction(builder, keys) | ||
progressTracker.currentStep = RECORDING | ||
val sessions = if (ourIdentity == holderParty) emptyList() else listOf(holderSession) | ||
|
||
val stx = ptx + | ||
if (!serviceHub.myInfo.isLegalIdentity(holderSession.counterparty)) { | ||
subFlow(CollectSignatureFlow(ptx, holderSession, extraKeys)) | ||
} else { | ||
listOf() | ||
} | ||
|
||
return subFlow(FinalityFlow(transaction = stx, sessions = sessions)) | ||
} | ||
} | ||
|
||
// TODO Don't really need it anymore as it calls only finality flow | ||
@InitiatedBy(Initiator::class) | ||
class Responder(val otherSession: FlowSession) : FlowLogic<Unit>() { | ||
abstract class Secondary(val otherSession: FlowSession) : FlowLogic<Unit>() { | ||
|
||
@Suspendable | ||
abstract fun checkTransaction(stx: SignedTransaction) | ||
|
||
@Suspendable | ||
override fun call(): Unit { | ||
// Resolve the issuance transaction. | ||
if (!serviceHub.myInfo.isLegalIdentity(otherSession.counterparty)) { | ||
subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, statesToRecord = StatesToRecord.ONLY_RELEVANT)) | ||
|
||
val parties = serviceHub.identityService.wellKnownPartyFromAnonymous(otherSession.counterparty) | ||
?: throw IllegalArgumentException("Called MoveToken flow with anonymous party that node doesn't know about. " + | ||
"Make sure that RequestConfidentialIdentity flow is called before.") | ||
|
||
parties | ||
|
||
val signTransactionFlow = object : SignTransactionFlow(otherSession) { | ||
override fun checkTransaction(stx: SignedTransaction) = [email protected](stx) | ||
} | ||
|
||
val txId = subFlow(signTransactionFlow).id | ||
|
||
// Resolve the issuance transaction. | ||
subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, | ||
statesToRecord = StatesToRecord.ONLY_RELEVANT, expectedTxId = txId)) | ||
} | ||
} | ||
} | ||
|
||
@InitiatingFlow | ||
@StartableByRPC | ||
class Initiator<T : TokenType>( | ||
ownedToken: T, | ||
holder: AbstractParty, | ||
amount: Amount<T>? = null, | ||
session: FlowSession? = null | ||
) : Primary<T>(ownedToken, holder, amount, session) { | ||
|
||
@Suspendable | ||
override fun transactionExtra(me: Party, | ||
holderParty: Party, | ||
holderSession: FlowSession, | ||
builder: TransactionBuilder): List<PublicKey> { | ||
return listOf() | ||
} | ||
} | ||
|
||
@InitiatedBy(Initiator::class) | ||
class Responder(otherSession: FlowSession) : Secondary(otherSession) { | ||
|
||
@Suspendable | ||
override fun checkTransaction(stx: SignedTransaction) = requireThat { } | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try not to use * imports