-
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
WIP/NOMERGE External signing enhancements #209
base: master
Are you sure you want to change the base?
Changes from all commits
340ea9c
d3eec6b
c4e9fec
b0c4d13
cdc9bef
babe100
5b68519
4a7681b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,19 @@ | ||
package com.r3.corda.lib.tokens.contracts | ||
|
||
import com.r3.corda.lib.tokens.contracts.commands.IssueTokenCommand | ||
import com.r3.corda.lib.tokens.contracts.commands.MoveTokenCommand | ||
import com.r3.corda.lib.tokens.contracts.commands.RedeemTokenCommand | ||
import com.r3.corda.lib.tokens.contracts.commands.TokenCommand | ||
import com.r3.corda.lib.tokens.contracts.states.AbstractToken | ||
import com.r3.corda.lib.tokens.contracts.states.FungibleToken | ||
import com.r3.corda.lib.tokens.contracts.types.IssuedTokenType | ||
import com.r3.corda.lib.tokens.contracts.utilities.sumTokenStatesOrZero | ||
import net.corda.core.contracts.* | ||
import net.corda.core.crypto.SecureHash | ||
import net.corda.core.crypto.toStringShort | ||
import net.corda.core.internal.uncheckedCast | ||
import net.corda.core.transactions.LedgerTransaction | ||
import net.corda.core.contracts.DescribableContract | ||
import java.security.PublicKey | ||
|
||
/** | ||
|
@@ -22,7 +29,7 @@ import java.security.PublicKey | |
* to call the super method to handle the existing commands. | ||
* 3. Add a method to handle the new command in the new sub-class contract. | ||
*/ | ||
open class FungibleTokenContract : AbstractTokenContract<FungibleToken>() { | ||
open class FungibleTokenContract : AbstractTokenContract<FungibleToken>(), DescribableContract { | ||
override val accepts: Class<FungibleToken> get() = uncheckedCast(FungibleToken::class.java) | ||
|
||
companion object { | ||
|
@@ -65,8 +72,11 @@ open class FungibleTokenContract : AbstractTokenContract<FungibleToken>() { | |
inputs: List<IndexedState<FungibleToken>>, | ||
outputs: List<IndexedState<FungibleToken>>, | ||
attachments: List<Attachment>, | ||
references: List<StateAndRef<ContractState>> | ||
references: List<StateAndRef<ContractState>>, | ||
summary: List<String> | ||
) { | ||
val ourSummary = describeTransaction(inputs.map{ it.state}, outputs.map { it.state }, moveCommands.map { it.value }, attachments.map { it.id }) | ||
require(ourSummary == summary) { "The summary generated by the contract: '${ourSummary}' does not match the summary present in the tx: '${summary}'" } | ||
// Commands are grouped by Token Type, so we just need a token reference. | ||
val issuedToken: IssuedTokenType = moveCommands.first().value.token | ||
// There must be inputs and outputs present. | ||
|
@@ -138,4 +148,34 @@ open class FungibleTokenContract : AbstractTokenContract<FungibleToken>() { | |
} | ||
} | ||
} | ||
|
||
override fun describeTransaction( | ||
inputs: List<TransactionState<ContractState>>, | ||
outputs: List<TransactionState<ContractState>>, | ||
commands: List<CommandData>, | ||
attachments: List<SecureHash>): List<String> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are references not needed? |
||
return when(commands.first()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what if this throws on empty list? add edge cases There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we check only first? what if we have more command data? |
||
//verify the type jar presence and correctness | ||
// Issuances should only contain one issue command. | ||
is IssueTokenCommand -> listOf("") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should it be implemented too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or at least some todo |
||
// Moves may contain more than one move command. | ||
is MoveTokenCommand -> constructMoveDescription(inputs, outputs) | ||
// Redeems must only contain one redeem command. | ||
is RedeemTokenCommand -> listOf("I AM A REDEPMPTION SONG)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😂 |
||
else -> emptyList() | ||
} | ||
} | ||
|
||
|
||
private fun constructMoveDescription(inputs: List<TransactionState<ContractState>>, outputs: List<TransactionState<ContractState>>): List<String> { | ||
val moveFrom = inputs.first().asFungibleToken().holder.owningKey | ||
val moveTo = (outputs.map { it.asFungibleToken().holder }).firstOrNull { p -> p.owningKey != moveFrom }?.owningKey ?: throw IllegalArgumentException("") | ||
val amountToMove = outputs.filter { p -> p.asFungibleToken().holder.owningKey != moveFrom }.first().asFungibleToken().amount | ||
amountToMove.displayTokenSize | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what these lines do? |
||
amountToMove.quantity | ||
return listOf("Move ${amountToMove.toDecimal()} ${amountToMove.token.tokenType.tokenIdentifier} from key: ${moveFrom.toStringShort()} to key: ${moveTo.toStringShort()}") | ||
} | ||
|
||
private fun TransactionState<ContractState>.asFungibleToken() = this.data as FungibleToken | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,14 +22,17 @@ import net.corda.core.transactions.SignedTransaction | |
* @param participantSessions sessions with the participants of move transaction | ||
* @param observerSessions optional sessions with the observer nodes, to witch the transaction will be broadcasted | ||
* @param queryCriteria additional criteria for token selection | ||
* @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external | ||
* service is required to obtain them, to prevent blocking other work | ||
*/ | ||
class ConfidentialMoveNonFungibleTokensFlow | ||
@JvmOverloads | ||
constructor( | ||
val partyAndToken: PartyAndToken, | ||
val participantSessions: List<FlowSession>, | ||
val observerSessions: List<FlowSession> = emptyList(), | ||
val queryCriteria: QueryCriteria? = null | ||
val queryCriteria: QueryCriteria? = null, | ||
val haltForExternalSigning: Boolean = false | ||
) : FlowLogic<SignedTransaction>() { | ||
@Suspendable | ||
override fun call(): SignedTransaction { | ||
|
@@ -38,6 +41,6 @@ constructor( | |
participantSessions.forEach { it.send(TransactionRole.PARTICIPANT) } | ||
observerSessions.forEach { it.send(TransactionRole.OBSERVER) } | ||
val confidentialOutput = subFlow(ConfidentialTokensFlow(listOf(output), participantSessions)).single() | ||
return subFlow(MoveTokensFlow(input, confidentialOutput, participantSessions, observerSessions)) | ||
return subFlow(MoveTokensFlow(listOf(input), listOf(confidentialOutput), participantSessions, observerSessions, haltForExternalSigning)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't need to change it to listOf(input) etc |
||
} | ||
} |
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.
Redeem doesn't need summary? It should be signed by token holder too