mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Changed FlowLogic.ourIdentity to return Party and added FlowLogic.ourIdentityAndCert which returns PartyAndCertificate. (#1537)
Updated code base to make use of these instead of chooseIdentity(). Also improved the serialisation of fiber checkpoints so that it doesn't store the entire cert parth of this identity.
This commit is contained in:
parent
8f86068807
commit
8e0b8477af
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -12,6 +12,8 @@
|
||||
<module name="buildSrc_test" target="1.8" />
|
||||
<module name="client_main" target="1.8" />
|
||||
<module name="client_test" target="1.8" />
|
||||
<module name="confidential-identities_main" target="1.8" />
|
||||
<module name="confidential-identities_test" target="1.8" />
|
||||
<module name="corda-project_main" target="1.8" />
|
||||
<module name="corda-project_test" target="1.8" />
|
||||
<module name="corda-webserver_integrationTest" target="1.8" />
|
||||
|
@ -18,8 +18,8 @@ import net.corda.core.utilities.unwrap
|
||||
*/
|
||||
@StartableByRPC
|
||||
@InitiatingFlow
|
||||
class SwapIdentitiesFlow(val otherSide: Party,
|
||||
val revocationEnabled: Boolean,
|
||||
class SwapIdentitiesFlow(private val otherSide: Party,
|
||||
private val revocationEnabled: Boolean,
|
||||
override val progressTracker: ProgressTracker) : FlowLogic<LinkedHashMap<Party, AnonymousParty>>() {
|
||||
constructor(otherSide: Party) : this(otherSide, false, tracker())
|
||||
|
||||
@ -39,7 +39,7 @@ class SwapIdentitiesFlow(val otherSide: Party,
|
||||
@Suspendable
|
||||
override fun call(): LinkedHashMap<Party, AnonymousParty> {
|
||||
progressTracker.currentStep = AWAITING_KEY
|
||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentity, revocationEnabled)
|
||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, revocationEnabled)
|
||||
|
||||
// Special case that if we're both parties, a single identity is generated
|
||||
val identities = LinkedHashMap<Party, AnonymousParty>()
|
||||
@ -49,7 +49,7 @@ class SwapIdentitiesFlow(val otherSide: Party,
|
||||
val anonymousOtherSide = sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity ->
|
||||
validateAndRegisterIdentity(serviceHub.identityService, otherSide, confidentialIdentity)
|
||||
}
|
||||
identities.put(ourIdentity.party, legalIdentityAnonymous.party.anonymise())
|
||||
identities.put(ourIdentity, legalIdentityAnonymous.party.anonymise())
|
||||
identities.put(otherSide, anonymousOtherSide.party.anonymise())
|
||||
}
|
||||
return identities
|
||||
|
@ -16,10 +16,10 @@ class SwapIdentitiesHandler(val otherSide: Party, val revocationEnabled: Boolean
|
||||
override val progressTracker: ProgressTracker = ProgressTracker(SENDING_KEY)
|
||||
|
||||
@Suspendable
|
||||
override fun call(): Unit {
|
||||
override fun call() {
|
||||
val revocationEnabled = false
|
||||
progressTracker.currentStep = SENDING_KEY
|
||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentity, revocationEnabled)
|
||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, revocationEnabled)
|
||||
sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity ->
|
||||
SwapIdentitiesFlow.validateAndRegisterIdentity(serviceHub.identityService, otherSide, confidentialIdentity)
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
|
||||
// Lookup the resolved transactions and use them to map each signed transaction to the list of participants.
|
||||
// Then send to the notary if needed, record locally and distribute.
|
||||
progressTracker.currentStep = NOTARISING
|
||||
val notarisedTxns: List<Pair<SignedTransaction, List<Party>>> = resolveDependenciesOf(transactions)
|
||||
val notarisedTxns: List<Pair<SignedTransaction, Set<Party>>> = resolveDependenciesOf(transactions)
|
||||
.map { (stx, ltx) -> Pair(notariseAndRecord(stx), lookupParties(ltx)) }
|
||||
|
||||
// Each transaction has its own set of recipients, but extra recipients get them all.
|
||||
progressTracker.currentStep = BROADCASTING
|
||||
for ((stx, parties) in notarisedTxns) {
|
||||
val participants = (parties + extraRecipients).filter { it != ourIdentity.party }.toSet()
|
||||
val participants = (parties + extraRecipients).filter { !serviceHub.myInfo.isLegalIdentity(it) }.toSet()
|
||||
if (participants.isNotEmpty()) {
|
||||
broadcastTransaction(stx, participants.toNonEmptySet())
|
||||
}
|
||||
@ -117,12 +117,12 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
|
||||
*
|
||||
* The default implementation throws an exception if an unknown party is encountered.
|
||||
*/
|
||||
open protected fun lookupParties(ltx: LedgerTransaction): List<Party> {
|
||||
open protected fun lookupParties(ltx: LedgerTransaction): Set<Party> {
|
||||
// Calculate who is meant to see the results based on the participants involved.
|
||||
return extractParticipants(ltx).map {
|
||||
serviceHub.identityService.partyFromAnonymous(it)
|
||||
?: throw IllegalArgumentException("Could not resolve well known identity of participant $it")
|
||||
}
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.internal.abbreviate
|
||||
import net.corda.core.messaging.DataFeed
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -58,10 +59,24 @@ abstract class FlowLogic<out T> {
|
||||
fun initiateFlow(party: Party): FlowSession = stateMachine.initiateFlow(party, flowUsedForSessions)
|
||||
|
||||
/**
|
||||
* Specifies our identity in the flow. With node's multiple identities we can choose which one to use for communication.
|
||||
* Defaults to the first one from [NodeInfo.legalIdentitiesAndCerts].
|
||||
* Specifies the identity, with certificate, to use for this flow. This will be one of the multiple identities that
|
||||
* belong to this node.
|
||||
* @see NodeInfo.legalIdentitiesAndCerts
|
||||
*
|
||||
* Note: The current implementation returns the single identity of the node. This will change once multiple identities
|
||||
* is implemented.
|
||||
*/
|
||||
val ourIdentity: PartyAndCertificate get() = stateMachine.ourIdentity
|
||||
val ourIdentityAndCert: PartyAndCertificate get() = stateMachine.ourIdentityAndCert
|
||||
|
||||
/**
|
||||
* Specifies the identity to use for this flow. This will be one of the multiple identities that belong to this node.
|
||||
* This is the same as calling `ourIdentityAndCert.party`.
|
||||
* @see NodeInfo.legalIdentities
|
||||
*
|
||||
* Note: The current implementation returns the single identity of the node. This will change once multiple identities
|
||||
* is implemented.
|
||||
*/
|
||||
val ourIdentity: Party get() = ourIdentityAndCert.party
|
||||
|
||||
/**
|
||||
* Returns a [FlowInfo] object describing the flow [otherParty] is using. With [FlowInfo.flowVersion] it
|
||||
|
@ -16,5 +16,5 @@ class ManualFinalityFlow(transactions: Iterable<SignedTransaction>,
|
||||
recipients: Set<Party>,
|
||||
progressTracker: ProgressTracker) : FinalityFlow(transactions, recipients, progressTracker) {
|
||||
constructor(transaction: SignedTransaction, extraParticipants: Set<Party>) : this(listOf(transaction), extraParticipants, tracker())
|
||||
override fun lookupParties(ltx: LedgerTransaction): List<Party> = emptyList()
|
||||
override fun lookupParties(ltx: LedgerTransaction): Set<Party> = emptySet()
|
||||
}
|
||||
|
@ -50,5 +50,5 @@ interface FlowStateMachine<R> {
|
||||
val id: StateMachineRunId
|
||||
val resultFuture: CordaFuture<R>
|
||||
val flowInitiator: FlowInitiator
|
||||
val ourIdentity: PartyAndCertificate
|
||||
val ourIdentityAndCert: PartyAndCertificate
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ data class NodeInfo(val addresses: List<NetworkHostAndPort>,
|
||||
return _legalIdentities ?: legalIdentitiesAndCerts.map { it.party }.also { _legalIdentities = it }
|
||||
}
|
||||
|
||||
/** Returns true iff [party] is one of the identities of this node. */
|
||||
/** Returns true if [party] is one of the identities of this node, else false. */
|
||||
fun isLegalIdentity(party: Party): Boolean = party in legalIdentities
|
||||
|
||||
fun serviceIdentities(type: ServiceType): List<Party> {
|
||||
|
@ -12,10 +12,10 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.testing.MINI_CORP_KEY
|
||||
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.chooseIdentity
|
||||
import net.corda.testing.chooseIdentityAndCert
|
||||
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.After
|
||||
@ -77,9 +77,7 @@ class CollectSignaturesFlowTests {
|
||||
}
|
||||
|
||||
val stx = subFlow(flow)
|
||||
val ftx = waitForLedgerCommit(stx.id)
|
||||
|
||||
return ftx
|
||||
return waitForLedgerCommit(stx.id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,14 +89,12 @@ class CollectSignaturesFlowTests {
|
||||
val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity
|
||||
|
||||
val myInputKeys = state.participants.map { it.owningKey }
|
||||
val myKeys = myInputKeys + (identities[serviceHub.myInfo.chooseIdentity()] ?: serviceHub.myInfo.chooseIdentity()).owningKey
|
||||
val myKeys = myInputKeys + (identities[ourIdentity] ?: ourIdentity).owningKey
|
||||
val command = Command(DummyContract.Commands.Create(), myInputKeys)
|
||||
val builder = TransactionBuilder(notary).withItems(StateAndContract(state, DUMMY_PROGRAM_ID), command)
|
||||
val ptx = serviceHub.signInitialTransaction(builder)
|
||||
val stx = subFlow(CollectSignaturesFlow(ptx, myKeys))
|
||||
val ftx = subFlow(FinalityFlow(stx)).single()
|
||||
|
||||
return ftx
|
||||
return subFlow(FinalityFlow(stx)).single()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,9 +113,7 @@ class CollectSignaturesFlowTests {
|
||||
val builder = TransactionBuilder(notary).withItems(StateAndContract(state, DUMMY_PROGRAM_ID), command)
|
||||
val ptx = serviceHub.signInitialTransaction(builder)
|
||||
val stx = subFlow(CollectSignaturesFlow(ptx, myInputKeys))
|
||||
val ftx = subFlow(FinalityFlow(stx)).single()
|
||||
|
||||
return ftx
|
||||
return subFlow(FinalityFlow(stx)).single()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,7 @@ data class TradeApprovalContract(val blank: Unit? = null) : Contract {
|
||||
val counterparty: Party,
|
||||
val state: WorkflowState = WorkflowState.NEW,
|
||||
override val linearId: UniqueIdentifier = UniqueIdentifier(tradeId)) : LinearState {
|
||||
val parties: List<Party> get() = listOf(source, counterparty)
|
||||
override val participants: List<AbstractParty> get() = parties
|
||||
override val participants: List<AbstractParty> get() = listOf(source, counterparty)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,29 +95,26 @@ data class TradeApprovalContract(val blank: Unit? = null) : Contract {
|
||||
* The protocol then sends a copy to the other node. We don't require the other party to sign
|
||||
* as their approval/rejection is to follow.
|
||||
*/
|
||||
class SubmitTradeApprovalFlow(val tradeId: String,
|
||||
val counterparty: Party) : FlowLogic<StateAndRef<TradeApprovalContract.State>>() {
|
||||
class SubmitTradeApprovalFlow(private val tradeId: String,
|
||||
private val counterparty: Party) : FlowLogic<StateAndRef<TradeApprovalContract.State>>() {
|
||||
@Suspendable
|
||||
override fun call(): StateAndRef<TradeApprovalContract.State> {
|
||||
// Manufacture an initial state
|
||||
val tradeProposal = TradeApprovalContract.State(
|
||||
tradeId,
|
||||
serviceHub.myInfo.chooseIdentity(),
|
||||
counterparty)
|
||||
val tradeProposal = TradeApprovalContract.State(tradeId, ourIdentity, counterparty)
|
||||
// identify a notary. This might also be done external to the flow
|
||||
val notary = serviceHub.networkMapCache.getAnyNotary()
|
||||
// Create the TransactionBuilder and populate with the new state.
|
||||
val tx = TransactionBuilder(notary)
|
||||
.withItems(StateAndContract(tradeProposal, TRADE_APPROVAL_PROGRAM_ID), Command(TradeApprovalContract.Commands.Issue(), listOf(tradeProposal.source.owningKey)))
|
||||
val tx = TransactionBuilder(notary).withItems(
|
||||
StateAndContract(tradeProposal, TRADE_APPROVAL_PROGRAM_ID),
|
||||
Command(TradeApprovalContract.Commands.Issue(), listOf(tradeProposal.source.owningKey)))
|
||||
tx.setTimeWindow(serviceHub.clock.instant(), 60.seconds)
|
||||
// We can automatically sign as there is no untrusted data.
|
||||
val signedTx = serviceHub.signInitialTransaction(tx)
|
||||
// Notarise and distribute.
|
||||
subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.chooseIdentity(), counterparty)))
|
||||
subFlow(FinalityFlow(signedTx, setOf(ourIdentity, counterparty)))
|
||||
// Return the initial state
|
||||
return signedTx.tx.outRef(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,7 +122,7 @@ class SubmitTradeApprovalFlow(val tradeId: String,
|
||||
* end up with a fully signed copy of the state either as APPROVED, or REJECTED
|
||||
*/
|
||||
@InitiatingFlow
|
||||
class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : FlowLogic<StateAndRef<TradeApprovalContract.State>>() {
|
||||
class SubmitCompletionFlow(private val ref: StateRef, private val verdict: WorkflowState) : FlowLogic<StateAndRef<TradeApprovalContract.State>>() {
|
||||
init {
|
||||
require(verdict in setOf(WorkflowState.APPROVED, WorkflowState.REJECTED)) {
|
||||
"Verdict must be a final state"
|
||||
@ -171,7 +167,7 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow
|
||||
latestRecord,
|
||||
StateAndContract(newState, TRADE_APPROVAL_PROGRAM_ID),
|
||||
Command(TradeApprovalContract.Commands.Completed(),
|
||||
listOf(serviceHub.myInfo.chooseIdentity().owningKey, latestRecord.state.data.source.owningKey)))
|
||||
listOf(ourIdentity.owningKey, latestRecord.state.data.source.owningKey)))
|
||||
tx.setTimeWindow(serviceHub.clock.instant(), 60.seconds)
|
||||
// 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.
|
||||
@ -197,7 +193,7 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow
|
||||
subFlow(FinalityFlow(allPartySignedTx, setOf(latestRecord.state.data.source, latestRecord.state.data.counterparty)))
|
||||
// DOCEND 4
|
||||
// Return back the details of the completed state/transaction.
|
||||
return allPartySignedTx.tx.outRef<TradeApprovalContract.State>(0)
|
||||
return allPartySignedTx.tx.outRef(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,14 +203,14 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow
|
||||
* transaction to the ledger.
|
||||
*/
|
||||
@InitiatedBy(SubmitCompletionFlow::class)
|
||||
class RecordCompletionFlow(val source: Party) : FlowLogic<Unit>() {
|
||||
class RecordCompletionFlow(private val source: Party) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call(): Unit {
|
||||
override fun call() {
|
||||
// DOCSTART 3
|
||||
// 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
|
||||
it.verifySignaturesExcept(serviceHub.myInfo.chooseIdentity().owningKey, it.tx.notary!!.owningKey)
|
||||
it.verifySignaturesExcept(ourIdentity.owningKey, it.tx.notary!!.owningKey)
|
||||
// Check the transaction data is correctly formed
|
||||
val ltx = it.toLedgerTransaction(serviceHub, false)
|
||||
ltx.verify()
|
||||
|
@ -26,7 +26,9 @@ import java.util.*
|
||||
* issuer.
|
||||
*/
|
||||
@StartableByRPC
|
||||
class CashExitFlow(val amount: Amount<Currency>, val issuerRef: OpaqueBytes, progressTracker: ProgressTracker) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
||||
class CashExitFlow(private val amount: Amount<Currency>,
|
||||
private val issuerRef: OpaqueBytes,
|
||||
progressTracker: ProgressTracker) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
||||
constructor(amount: Amount<Currency>, issueRef: OpaqueBytes) : this(amount, issueRef, tracker())
|
||||
constructor(request: ExitRequest) : this(request.amount, request.issueRef, tracker())
|
||||
|
||||
@ -43,8 +45,9 @@ class CashExitFlow(val amount: Amount<Currency>, val issuerRef: OpaqueBytes, pro
|
||||
override fun call(): AbstractCashFlow.Result {
|
||||
progressTracker.currentStep = GENERATING_TX
|
||||
val builder = TransactionBuilder(notary = null as Party?)
|
||||
val issuer = ourIdentity.party.ref(issuerRef)
|
||||
val exitStates = CashSelection.getInstance({serviceHub.jdbcSession().metaData}).unconsumedCashStatesForSpending(serviceHub, amount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
|
||||
val issuer = ourIdentity.ref(issuerRef)
|
||||
val exitStates = CashSelection.getInstance { serviceHub.jdbcSession().metaData }
|
||||
.unconsumedCashStatesForSpending(serviceHub, amount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
|
||||
val signers = try {
|
||||
Cash().generateExit(
|
||||
builder,
|
||||
@ -61,9 +64,7 @@ class CashExitFlow(val amount: Amount<Currency>, val issuerRef: OpaqueBytes, pro
|
||||
// TODO: Is it safe to drop participants we don't know how to contact? Does not knowing how to contact them
|
||||
// count as a reason to fail?
|
||||
val participants: Set<Party> = inputStates
|
||||
.filterIsInstance<Cash.State>()
|
||||
.map { serviceHub.identityService.partyFromAnonymous(it.owner) }
|
||||
.filterNotNull()
|
||||
.mapNotNull { serviceHub.identityService.partyFromAnonymous(it.state.data.owner) }
|
||||
.toSet()
|
||||
// Sign transaction
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
|
@ -25,9 +25,9 @@ import java.util.*
|
||||
* @param notary the notary to set on the output states.
|
||||
*/
|
||||
@StartableByRPC
|
||||
class CashIssueFlow(val amount: Amount<Currency>,
|
||||
val issuerBankPartyRef: OpaqueBytes,
|
||||
val notary: Party,
|
||||
class CashIssueFlow(private val amount: Amount<Currency>,
|
||||
private val issuerBankPartyRef: OpaqueBytes,
|
||||
private val notary: Party,
|
||||
progressTracker: ProgressTracker) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
||||
constructor(amount: Amount<Currency>,
|
||||
issuerBankPartyRef: OpaqueBytes,
|
||||
@ -38,13 +38,13 @@ class CashIssueFlow(val amount: Amount<Currency>,
|
||||
override fun call(): AbstractCashFlow.Result {
|
||||
progressTracker.currentStep = GENERATING_TX
|
||||
val builder = TransactionBuilder(notary)
|
||||
val issuer = ourIdentity.party.ref(issuerBankPartyRef)
|
||||
val signers = Cash().generateIssue(builder, amount.issuedBy(issuer), ourIdentity.party, notary)
|
||||
val issuer = ourIdentity.ref(issuerBankPartyRef)
|
||||
val signers = Cash().generateIssue(builder, amount.issuedBy(issuer), ourIdentity, notary)
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
val tx = serviceHub.signInitialTransaction(builder, signers)
|
||||
progressTracker.currentStep = FINALISING_TX
|
||||
subFlow(FinalityFlow(tx))
|
||||
return Result(tx, ourIdentity.party)
|
||||
val notarised = subFlow(FinalityFlow(tx)).single()
|
||||
return Result(notarised, ourIdentity)
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
|
@ -9,7 +9,6 @@ import net.corda.core.flows.CollectSignaturesFlow
|
||||
import net.corda.core.flows.FinalityFlow
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.SignTransactionFlow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.NodeInfo
|
||||
@ -58,8 +57,8 @@ object TwoPartyDealFlow {
|
||||
@Suspendable override fun call(): SignedTransaction {
|
||||
progressTracker.currentStep = GENERATING_ID
|
||||
val txIdentities = subFlow(SwapIdentitiesFlow(otherParty))
|
||||
val anonymousMe = txIdentities.get(ourIdentity.party) ?: ourIdentity.party.anonymise()
|
||||
val anonymousCounterparty = txIdentities.get(otherParty) ?: otherParty.anonymise()
|
||||
val anonymousMe = txIdentities[ourIdentity] ?: ourIdentity.anonymise()
|
||||
val anonymousCounterparty = txIdentities[otherParty] ?: otherParty.anonymise()
|
||||
progressTracker.currentStep = SENDING_PROPOSAL
|
||||
// Make the first message we'll send to kick off the flow.
|
||||
val hello = Handshake(payload, anonymousMe, anonymousCounterparty)
|
||||
@ -122,7 +121,7 @@ object TwoPartyDealFlow {
|
||||
logger.trace { "Got signatures from other party, verifying ... " }
|
||||
|
||||
progressTracker.currentStep = RECORDING
|
||||
val ftx = subFlow(FinalityFlow(stx, setOf(otherParty, ourIdentity.party))).single()
|
||||
val ftx = subFlow(FinalityFlow(stx, setOf(otherParty, ourIdentity))).single()
|
||||
|
||||
logger.trace { "Recorded transaction." }
|
||||
|
||||
@ -154,13 +153,15 @@ object TwoPartyDealFlow {
|
||||
val wellKnownOtherParty = serviceHub.identityService.partyFromAnonymous(it.primaryIdentity)
|
||||
val wellKnownMe = serviceHub.identityService.partyFromAnonymous(it.secondaryIdentity)
|
||||
require(wellKnownOtherParty == otherParty)
|
||||
require(wellKnownMe == ourIdentity.party)
|
||||
require(wellKnownMe == ourIdentity)
|
||||
validateHandshake(it)
|
||||
}
|
||||
}
|
||||
|
||||
@Suspendable protected abstract fun validateHandshake(handshake: Handshake<U>): Handshake<U>
|
||||
@Suspendable protected abstract fun assembleSharedTX(handshake: Handshake<U>): Triple<TransactionBuilder, List<PublicKey>, List<TransactionSignature>>
|
||||
@Suspendable
|
||||
protected abstract fun validateHandshake(handshake: Handshake<U>): Handshake<U>
|
||||
@Suspendable
|
||||
protected abstract fun assembleSharedTX(handshake: Handshake<U>): Triple<TransactionBuilder, List<PublicKey>, List<TransactionSignature>>
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
@ -173,7 +174,7 @@ object TwoPartyDealFlow {
|
||||
override val payload: AutoOffer,
|
||||
override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() {
|
||||
override val notaryNode: NodeInfo get() =
|
||||
serviceHub.networkMapCache.notaryNodes.filter { it.notaryIdentity == payload.notary }.single()
|
||||
serviceHub.networkMapCache.notaryNodes.single { it.notaryIdentity == payload.notary }
|
||||
|
||||
@Suspendable override fun checkProposal(stx: SignedTransaction) = requireThat {
|
||||
// Add some constraints here.
|
||||
@ -201,7 +202,7 @@ object TwoPartyDealFlow {
|
||||
// We set the transaction's time-window: it may be that none of the contracts need this!
|
||||
// But it can't hurt to have one.
|
||||
ptx.setTimeWindow(serviceHub.clock.instant(), 30.seconds)
|
||||
return Triple(ptx, arrayListOf(deal.participants.single { it == ourIdentity.party as AbstractParty }.owningKey), emptyList())
|
||||
return Triple(ptx, arrayListOf(deal.participants.single { it is Party && serviceHub.myInfo.isLegalIdentity(it) }.owningKey), emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,6 @@
|
||||
package net.corda.finance.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.OwnableState
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.withoutIssuer
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
@ -103,7 +99,9 @@ object TwoPartyTradeFlow {
|
||||
val states: Iterable<ContractState> = (stx.tx.inputs.map { serviceHub.loadState(it).data } + stx.tx.outputs.map { it.data })
|
||||
states.forEach { state ->
|
||||
state.participants.forEach { anon ->
|
||||
require(serviceHub.identityService.partyFromAnonymous(anon) != null) { "Transaction state ${state} involves unknown participant ${anon}" }
|
||||
require(serviceHub.identityService.partyFromAnonymous(anon) != null) {
|
||||
"Transaction state $state involves unknown participant $anon"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,12 +127,13 @@ object TwoPartyTradeFlow {
|
||||
// express flow state machines on top of the messaging layer.
|
||||
}
|
||||
|
||||
open class Buyer(val otherParty: Party,
|
||||
val notary: Party,
|
||||
val acceptablePrice: Amount<Currency>,
|
||||
val typeToBuy: Class<out OwnableState>,
|
||||
val anonymous: Boolean) : FlowLogic<SignedTransaction>() {
|
||||
constructor(otherParty: Party, notary: Party, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>): this(otherParty, notary, acceptablePrice, typeToBuy, true)
|
||||
open class Buyer(private val otherParty: Party,
|
||||
private val notary: Party,
|
||||
private val acceptablePrice: Amount<Currency>,
|
||||
private val typeToBuy: Class<out OwnableState>,
|
||||
private val anonymous: Boolean) : FlowLogic<SignedTransaction>() {
|
||||
constructor(otherParty: Party, notary: Party, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>) :
|
||||
this(otherParty, notary, acceptablePrice, typeToBuy, true)
|
||||
// DOCSTART 2
|
||||
object RECEIVING : ProgressTracker.Step("Waiting for seller trading info")
|
||||
|
||||
@ -161,9 +160,9 @@ object TwoPartyTradeFlow {
|
||||
|
||||
// Create the identity we'll be paying to, and send the counterparty proof we own the identity
|
||||
val buyerAnonymousIdentity = if (anonymous)
|
||||
serviceHub.keyManagementService.freshKeyAndCert(ourIdentity, false)
|
||||
serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, false)
|
||||
else
|
||||
ourIdentity
|
||||
ourIdentityAndCert
|
||||
// Put together a proposed transaction that performs the trade, and sign it.
|
||||
progressTracker.currentStep = SIGNING
|
||||
val (ptx, cashSigningPubKeys) = assembleSharedTX(assetForSale, tradeRequest, buyerAnonymousIdentity)
|
||||
|
@ -11,7 +11,6 @@ import net.corda.testing.BOB
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.aliceBobAndNotary
|
||||
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
|
||||
import net.corda.testing.chooseIdentity
|
||||
import net.corda.testing.contracts.DummyState
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.dummyCommand
|
||||
@ -24,17 +23,20 @@ import kotlin.test.assertEquals
|
||||
*/
|
||||
class LargeTransactionsTest {
|
||||
@StartableByRPC @InitiatingFlow
|
||||
class SendLargeTransactionFlow(val hash1: SecureHash, val hash2: SecureHash, val hash3: SecureHash, val hash4: SecureHash) : FlowLogic<Unit>() {
|
||||
class SendLargeTransactionFlow(private val hash1: SecureHash,
|
||||
private val hash2: SecureHash,
|
||||
private val hash3: SecureHash,
|
||||
private val hash4: SecureHash) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
val tx = TransactionBuilder(notary = DUMMY_NOTARY)
|
||||
.addOutputState(DummyState(), DUMMY_PROGRAM_ID)
|
||||
.addCommand(dummyCommand(serviceHub.myInfo.chooseIdentity().owningKey))
|
||||
.addCommand(dummyCommand(ourIdentity.owningKey))
|
||||
.addAttachment(hash1)
|
||||
.addAttachment(hash2)
|
||||
.addAttachment(hash3)
|
||||
.addAttachment(hash4)
|
||||
val stx = serviceHub.signInitialTransaction(tx, serviceHub.myInfo.chooseIdentity().owningKey)
|
||||
val stx = serviceHub.signInitialTransaction(tx, ourIdentity.owningKey)
|
||||
// Send to the other side and wait for it to trigger resolution from us.
|
||||
val bob = serviceHub.identityService.partyFromX500Name(BOB.name)!!
|
||||
subFlow(SendTransactionFlow(bob, stx))
|
||||
|
@ -140,7 +140,7 @@ class SendMessageFlow(private val message: Message) : FlowLogic<SignedTransactio
|
||||
|
||||
progressTracker.currentStep = GENERATING_TRANSACTION
|
||||
|
||||
val messageState = MessageState(message = message, by = serviceHub.myInfo.chooseIdentity())
|
||||
val messageState = MessageState(message = message, by = ourIdentity)
|
||||
val txCommand = Command(MessageContract.Commands.Send(), messageState.participants.map { it.owningKey })
|
||||
val txBuilder = TransactionBuilder(notary).withItems(StateAndContract(messageState, MESSAGE_CONTRACT_PROGRAM_ID), txCommand)
|
||||
|
||||
|
@ -731,9 +731,8 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist")
|
||||
}
|
||||
|
||||
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator, me: PartyAndCertificate?): FlowStateMachineImpl<T> {
|
||||
check(me == null || me in myInfo.legalIdentitiesAndCerts) { "Attempt to start a flow with legal identity not belonging to this node." }
|
||||
return serverThread.fetchFrom { smm.add(logic, flowInitiator, me) }
|
||||
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator, ourIdentity: Party?): FlowStateMachineImpl<T> {
|
||||
return serverThread.fetchFrom { smm.add(logic, flowInitiator, ourIdentity) }
|
||||
}
|
||||
|
||||
override fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? {
|
||||
|
@ -10,7 +10,6 @@ import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
@ -143,11 +142,11 @@ class CordaRPCOpsImpl(
|
||||
|
||||
private fun <T> startFlow(logicType: Class<out FlowLogic<T>>, args: Array<out Any?>): FlowStateMachineImpl<T> {
|
||||
require(logicType.isAnnotationPresent(StartableByRPC::class.java)) { "${logicType.name} was not designed for RPC" }
|
||||
val me = services.myInfo.legalIdentitiesAndCerts.first() // TODO RPC flows should have mapping user -> identity that should be resolved automatically on starting flow.
|
||||
val rpcContext = getRpcContext()
|
||||
rpcContext.requirePermission(startFlowPermission(logicType))
|
||||
val currentUser = FlowInitiator.RPC(rpcContext.currentUser.username)
|
||||
return services.invokeFlowAsync(logicType, currentUser, me, *args)
|
||||
// TODO RPC flows should have mapping user -> identity that should be resolved automatically on starting flow.
|
||||
return services.invokeFlowAsync(logicType, currentUser, *args)
|
||||
}
|
||||
|
||||
override fun attachmentExists(id: SecureHash): Boolean {
|
||||
|
@ -1,16 +1,12 @@
|
||||
package net.corda.node.services
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.confidential.SwapIdentitiesFlow
|
||||
import net.corda.core.flows.AbstractStateReplacementFlow
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.ReceiveTransactionFlow
|
||||
import net.corda.core.flows.StateReplacementException
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.unwrap
|
||||
|
||||
// TODO: We should have a whitelist of contracts we're willing to accept at all, and reject if the transaction
|
||||
// includes us in any outside that list. Potentially just if it includes any outside that list at all.
|
||||
@ -32,7 +28,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep
|
||||
* and is also in a geographically convenient location we can just automatically approve the change.
|
||||
* TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal
|
||||
*/
|
||||
override fun verifyProposal(stx: SignedTransaction, proposal: AbstractStateReplacementFlow.Proposal<Party>): Unit {
|
||||
override fun verifyProposal(stx: SignedTransaction, proposal: AbstractStateReplacementFlow.Proposal<Party>) {
|
||||
val state = proposal.stateRef
|
||||
val proposedTx = stx.resolveNotaryChangeTransaction(serviceHub)
|
||||
val newNotary = proposal.modification
|
||||
|
@ -6,7 +6,6 @@ import net.corda.core.flows.FlowInitiator
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.messaging.DataFeed
|
||||
@ -118,7 +117,7 @@ interface ServiceHubInternal : ServiceHub {
|
||||
* Starts an already constructed flow. Note that you must be on the server thread to call this method.
|
||||
* @param flowInitiator indicates who started the flow, see: [FlowInitiator].
|
||||
*/
|
||||
fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator, me: PartyAndCertificate? = null): FlowStateMachineImpl<T>
|
||||
fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator, ourIdentity: Party? = null): FlowStateMachineImpl<T>
|
||||
|
||||
/**
|
||||
* Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the flow.
|
||||
@ -131,12 +130,11 @@ interface ServiceHubInternal : ServiceHub {
|
||||
fun <T> invokeFlowAsync(
|
||||
logicType: Class<out FlowLogic<T>>,
|
||||
flowInitiator: FlowInitiator,
|
||||
me: PartyAndCertificate? = null,
|
||||
vararg args: Any?): FlowStateMachineImpl<T> {
|
||||
val logicRef = FlowLogicRefFactoryImpl.createForRPC(logicType, *args)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val logic = FlowLogicRefFactoryImpl.toFlowLogic(logicRef) as FlowLogic<T>
|
||||
return startFlow(logic, flowInitiator, me)
|
||||
return startFlow(logic, flowInitiator, ourIdentity = null)
|
||||
}
|
||||
|
||||
fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>?
|
||||
|
@ -12,9 +12,12 @@ import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.internal.abbreviate
|
||||
import net.corda.core.internal.concurrent.OpenFuture
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.isRegularFile
|
||||
import net.corda.core.internal.staticField
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.node.services.api.FlowAppAuditEvent
|
||||
@ -37,7 +40,9 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
val logic: FlowLogic<R>,
|
||||
scheduler: FiberScheduler,
|
||||
override val flowInitiator: FlowInitiator,
|
||||
override val ourIdentity: PartyAndCertificate) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R> {
|
||||
// Store the Party rather than the full cert path with PartyAndCertificate
|
||||
val ourIdentity: Party) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R> {
|
||||
|
||||
companion object {
|
||||
// Used to work around a small limitation in Quasar.
|
||||
private val QUASAR_UNBLOCKER = Fiber::class.staticField<Any>("SERIALIZER_BLOCKER").value
|
||||
@ -67,6 +72,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
|
||||
// These fields shouldn't be serialised, so they are marked @Transient.
|
||||
@Transient override lateinit var serviceHub: ServiceHubInternal
|
||||
@Transient override lateinit var ourIdentityAndCert: PartyAndCertificate
|
||||
@Transient internal lateinit var database: CordaPersistence
|
||||
@Transient internal lateinit var actionOnSuspend: (FlowIORequest) -> Unit
|
||||
@Transient internal lateinit var actionOnEnd: (Try<R>, Boolean) -> Unit
|
||||
|
@ -3,7 +3,6 @@ package net.corda.node.services.statemachine
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.UnexpectedFlowEndException
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.castIfPossible
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
@ -26,9 +25,7 @@ data class SessionInit(val initiatorSessionId: Long,
|
||||
val initiatingFlowClass: String,
|
||||
val flowVersion: Int,
|
||||
val appName: String,
|
||||
val firstPayload: Any?,
|
||||
// Left as a placeholder for support of multiple identities on a node. For now we choose the first one as a special one.
|
||||
val otherIdentity: PartyAndCertificate? = null) : SessionMessage
|
||||
val firstPayload: Any?) : SessionMessage
|
||||
|
||||
data class SessionConfirm(override val initiatorSessionId: Long,
|
||||
val initiatedSessionId: Long,
|
||||
|
@ -14,7 +14,6 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.ThreadBox
|
||||
import net.corda.core.internal.bufferUntilSubscribed
|
||||
import net.corda.core.internal.castIfPossible
|
||||
@ -371,8 +370,9 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
||||
session.receivedMessages += ReceivedSessionMessage(sender, SessionData(session.ourSessionId, sessionInit.firstPayload))
|
||||
}
|
||||
openSessions[session.ourSessionId] = session
|
||||
val meIdentity = sessionInit.otherIdentity ?: serviceHub.myInfo.legalIdentitiesAndCerts.first()
|
||||
val fiber = createFiber(flow, FlowInitiator.Peer(sender), meIdentity)
|
||||
// TODO Perhaps the session-init will specificy which of our multiple identies to use, which we would have to
|
||||
// double-check is actually ours. However, what if we want to control how our identities gets used?
|
||||
val fiber = createFiber(flow, FlowInitiator.Peer(sender))
|
||||
flowSession.sessionFlow = flow
|
||||
flowSession.stateMachine = fiber
|
||||
fiber.openSessions[Pair(flow, sender)] = session
|
||||
@ -427,15 +427,23 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> createFiber(logic: FlowLogic<T>, flowInitiator: FlowInitiator, me: PartyAndCertificate): FlowStateMachineImpl<T> {
|
||||
val id = StateMachineRunId.createRandom()
|
||||
return FlowStateMachineImpl(id, logic, scheduler, flowInitiator, me).apply { initFiber(this) }
|
||||
private fun <T> createFiber(logic: FlowLogic<T>, flowInitiator: FlowInitiator, ourIdentity: Party? = null): FlowStateMachineImpl<T> {
|
||||
val fsm = FlowStateMachineImpl(
|
||||
StateMachineRunId.createRandom(),
|
||||
logic,
|
||||
scheduler,
|
||||
flowInitiator,
|
||||
ourIdentity ?: serviceHub.myInfo.legalIdentities[0])
|
||||
initFiber(fsm)
|
||||
return fsm
|
||||
}
|
||||
|
||||
private fun initFiber(fiber: FlowStateMachineImpl<*>) {
|
||||
verifyFlowLogicIsSuspendable(fiber.logic)
|
||||
fiber.database = database
|
||||
fiber.serviceHub = serviceHub
|
||||
fiber.ourIdentityAndCert = serviceHub.myInfo.legalIdentitiesAndCerts.find { it.party == fiber.ourIdentity }
|
||||
?: throw IllegalStateException("Identity specified by ${fiber.id} (${fiber.ourIdentity}) is not one of ours!")
|
||||
fiber.actionOnSuspend = { ioRequest ->
|
||||
updateCheckpoint(fiber)
|
||||
// We commit on the fibers transaction that was copied across ThreadLocals during suspend
|
||||
@ -514,11 +522,11 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
||||
*
|
||||
* Note that you must be on the [executor] thread.
|
||||
*/
|
||||
fun <T> add(logic: FlowLogic<T>, flowInitiator: FlowInitiator, me: PartyAndCertificate?): FlowStateMachineImpl<T> {
|
||||
fun <T> add(logic: FlowLogic<T>, flowInitiator: FlowInitiator, ourIdentity: Party? = null): FlowStateMachineImpl<T> {
|
||||
// TODO: Check that logic has @Suspendable on its call method.
|
||||
executor.checkOnThread()
|
||||
val fiber = database.transaction {
|
||||
val fiber = createFiber(logic, flowInitiator, me ?: serviceHub.myInfo.legalIdentitiesAndCerts.first())
|
||||
val fiber = createFiber(logic, flowInitiator, ourIdentity)
|
||||
updateCheckpoint(fiber)
|
||||
fiber
|
||||
}
|
||||
|
@ -545,17 +545,17 @@ class TwoPartyTradeFlowTests {
|
||||
}
|
||||
|
||||
@InitiatingFlow
|
||||
class SellerInitiator(val buyer: Party,
|
||||
val notary: NodeInfo,
|
||||
val assetToSell: StateAndRef<OwnableState>,
|
||||
val price: Amount<Currency>,
|
||||
val anonymous: Boolean) : FlowLogic<SignedTransaction>() {
|
||||
class SellerInitiator(private val buyer: Party,
|
||||
private val notary: NodeInfo,
|
||||
private val assetToSell: StateAndRef<OwnableState>,
|
||||
private val price: Amount<Currency>,
|
||||
private val anonymous: Boolean) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
val myParty = if (anonymous) {
|
||||
serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.chooseIdentityAndCert(), false)
|
||||
val myPartyAndCert = if (anonymous) {
|
||||
serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, false)
|
||||
} else {
|
||||
serviceHub.myInfo.chooseIdentityAndCert()
|
||||
ourIdentityAndCert
|
||||
}
|
||||
send(buyer, TestTx(notary.notaryIdentity, price, anonymous))
|
||||
return subFlow(Seller(
|
||||
@ -563,12 +563,12 @@ class TwoPartyTradeFlowTests {
|
||||
notary,
|
||||
assetToSell,
|
||||
price,
|
||||
myParty))
|
||||
myPartyAndCert))
|
||||
}
|
||||
}
|
||||
|
||||
@InitiatedBy(SellerInitiator::class)
|
||||
class BuyerAcceptor(val seller: Party) : FlowLogic<SignedTransaction>() {
|
||||
class BuyerAcceptor(private val seller: Party) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
val (notary, price, anonymous) = receive<TestTx>(seller).unwrap {
|
||||
|
@ -37,6 +37,7 @@ class ScheduledFlowTests {
|
||||
val PAGE_SIZE = 20
|
||||
val SORTING = Sort(listOf(Sort.SortColumn(SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID), Sort.Direction.DESC)))
|
||||
}
|
||||
|
||||
lateinit var mockNet: MockNetwork
|
||||
lateinit var notaryNode: StartedNode<MockNetwork.MockNode>
|
||||
lateinit var nodeA: StartedNode<MockNetwork.MockNode>
|
||||
@ -59,23 +60,22 @@ class ScheduledFlowTests {
|
||||
override val participants: List<AbstractParty> = listOf(source, destination)
|
||||
}
|
||||
|
||||
class InsertInitialStateFlow(val destination: Party) : FlowLogic<Unit>() {
|
||||
class InsertInitialStateFlow(private val destination: Party) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
val scheduledState = ScheduledState(serviceHub.clock.instant(),
|
||||
serviceHub.myInfo.chooseIdentity(), destination)
|
||||
val scheduledState = ScheduledState(serviceHub.clock.instant(), ourIdentity, destination)
|
||||
|
||||
val notary = serviceHub.networkMapCache.getAnyNotary()
|
||||
val builder = TransactionBuilder(notary)
|
||||
.addOutputState(scheduledState, DUMMY_PROGRAM_ID)
|
||||
.addCommand(dummyCommand(ourIdentity.owningKey))
|
||||
val tx = serviceHub.signInitialTransaction(builder)
|
||||
subFlow(FinalityFlow(tx, setOf(serviceHub.myInfo.chooseIdentity())))
|
||||
subFlow(FinalityFlow(tx, setOf(ourIdentity)))
|
||||
}
|
||||
}
|
||||
|
||||
@SchedulableFlow
|
||||
class ScheduledFlow(val stateRef: StateRef) : FlowLogic<Unit>() {
|
||||
class ScheduledFlow(private val stateRef: StateRef) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
val state = serviceHub.toStateAndRef<ScheduledState>(stateRef)
|
||||
@ -90,7 +90,7 @@ class ScheduledFlowTests {
|
||||
val builder = TransactionBuilder(notary)
|
||||
.addInputState(state)
|
||||
.addOutputState(newStateOutput, DUMMY_PROGRAM_ID)
|
||||
.addCommand(dummyCommand(serviceHub.myInfo.chooseIdentity().owningKey))
|
||||
.addCommand(dummyCommand(ourIdentity.owningKey))
|
||||
val tx = serviceHub.signInitialTransaction(builder)
|
||||
subFlow(FinalityFlow(tx, setOf(scheduledState.source, scheduledState.destination)))
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.testing.DUMMY_BANK_B
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.chooseIdentity
|
||||
import net.corda.testing.driver.poll
|
||||
import java.io.InputStream
|
||||
import java.net.HttpURLConnection
|
||||
@ -118,7 +117,7 @@ class AttachmentDemoFlow(val otherSide: Party, val notary: Party, val hash: Secu
|
||||
// Create a trivial transaction with an output that describes the attachment, and the attachment itself
|
||||
val ptx = TransactionBuilder(notary)
|
||||
.addOutputState(AttachmentContract.State(hash), ATTACHMENT_PROGRAM_ID)
|
||||
.addCommand(AttachmentContract.Command, serviceHub.myInfo.chooseIdentity().owningKey)
|
||||
.addCommand(AttachmentContract.Command, ourIdentity.owningKey)
|
||||
.addAttachment(hash)
|
||||
|
||||
progressTracker.currentStep = SIGNING
|
||||
|
@ -62,7 +62,7 @@ object AutoOfferFlow {
|
||||
}
|
||||
|
||||
private fun <T : AbstractParty> notUs(parties: List<T>): List<T> {
|
||||
return parties.filter { ourIdentity.party != it }
|
||||
return parties.filter { ourIdentity != it }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.testing.chooseIdentity
|
||||
|
||||
@StartableByRPC
|
||||
class DummyIssueAndMove(private val notary: Party, private val counterpartyNode: Party, private val discriminator: Int) : FlowLogic<SignedTransaction>() {
|
||||
@ -27,10 +26,10 @@ class DummyIssueAndMove(private val notary: Party, private val counterpartyNode:
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
// Self issue an asset
|
||||
val state = State(listOf(serviceHub.myInfo.chooseIdentity()), discriminator)
|
||||
val state = State(listOf(ourIdentity), discriminator)
|
||||
val issueTx = serviceHub.signInitialTransaction(TransactionBuilder(notary).apply {
|
||||
addOutputState(state, DO_NOTHING_PROGRAM_ID)
|
||||
addCommand(DummyCommand(),listOf(serviceHub.myInfo.chooseIdentity().owningKey))
|
||||
addCommand(DummyCommand(),listOf(ourIdentity.owningKey))
|
||||
})
|
||||
serviceHub.recordTransactions(issueTx)
|
||||
// Move ownership of the asset to the counterparty
|
||||
@ -38,7 +37,7 @@ class DummyIssueAndMove(private val notary: Party, private val counterpartyNode:
|
||||
return serviceHub.signInitialTransaction(TransactionBuilder(notary).apply {
|
||||
addInputState(issueTx.tx.outRef<ContractState>(0))
|
||||
addOutputState(state.copy(participants = listOf(counterpartyNode)), DO_NOTHING_PROGRAM_ID)
|
||||
addCommand(DummyCommand(),listOf(serviceHub.myInfo.chooseIdentity().owningKey))
|
||||
addCommand(DummyCommand(),listOf(ourIdentity.owningKey))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.finance.flows.TwoPartyDealFlow
|
||||
import net.corda.vega.contracts.IRSState
|
||||
import net.corda.vega.contracts.OGTrade
|
||||
import net.corda.vega.contracts.SwapData
|
||||
|
||||
object IRSTradeFlow {
|
||||
@ -27,9 +26,9 @@ object IRSTradeFlow {
|
||||
val notary = serviceHub.networkMapCache.notaryNodes.first().notaryIdentity
|
||||
val (buyer, seller) =
|
||||
if (swap.buyer.second == ourIdentity.owningKey) {
|
||||
Pair(ourIdentity.party, otherParty)
|
||||
Pair(ourIdentity, otherParty)
|
||||
} else {
|
||||
Pair(otherParty, ourIdentity.party)
|
||||
Pair(otherParty, ourIdentity)
|
||||
}
|
||||
val offer = IRSState(swap, buyer, seller)
|
||||
|
||||
|
@ -21,7 +21,10 @@ import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.finance.flows.TwoPartyDealFlow
|
||||
import net.corda.vega.analytics.*
|
||||
import net.corda.vega.contracts.*
|
||||
import net.corda.vega.contracts.IRSState
|
||||
import net.corda.vega.contracts.PortfolioState
|
||||
import net.corda.vega.contracts.PortfolioValuation
|
||||
import net.corda.vega.contracts.RevisionedState
|
||||
import net.corda.vega.portfolio.Portfolio
|
||||
import net.corda.vega.portfolio.toPortfolio
|
||||
import java.time.LocalDate
|
||||
@ -48,16 +51,16 @@ object SimmFlow {
|
||||
*/
|
||||
@InitiatingFlow
|
||||
@StartableByRPC
|
||||
class Requester(val otherParty: Party,
|
||||
val valuationDate: LocalDate,
|
||||
val existing: StateAndRef<PortfolioState>?)
|
||||
class Requester(private val otherParty: Party,
|
||||
private val valuationDate: LocalDate,
|
||||
private val existing: StateAndRef<PortfolioState>?)
|
||||
: FlowLogic<RevisionedState<PortfolioState.Update>>() {
|
||||
constructor(otherParty: Party, valuationDate: LocalDate) : this(otherParty, valuationDate, null)
|
||||
lateinit var notary: Party
|
||||
|
||||
@Suspendable
|
||||
override fun call(): RevisionedState<PortfolioState.Update> {
|
||||
logger.debug("Calling from: ${ourIdentity.party}. Sending to: $otherParty")
|
||||
logger.debug("Calling from: $ourIdentity. Sending to: $otherParty")
|
||||
require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" }
|
||||
notary = serviceHub.networkMapCache.notaryNodes.first().notaryIdentity
|
||||
|
||||
@ -80,7 +83,7 @@ object SimmFlow {
|
||||
@Suspendable
|
||||
private fun agreePortfolio(portfolio: Portfolio) {
|
||||
logger.info("Agreeing portfolio")
|
||||
val parties = Pair(ourIdentity.party, otherParty)
|
||||
val parties = Pair(ourIdentity, otherParty)
|
||||
val portfolioState = PortfolioState(portfolio.refs, parties, valuationDate)
|
||||
|
||||
send(otherParty, OfferMessage(notary, portfolioState, existing?.ref, valuationDate))
|
||||
|
@ -17,12 +17,12 @@ import java.time.LocalDate
|
||||
object SimmRevaluation {
|
||||
@StartableByRPC
|
||||
@SchedulableFlow
|
||||
class Initiator(val curStateRef: StateRef, val valuationDate: LocalDate) : FlowLogic<Unit>() {
|
||||
class Initiator(private val curStateRef: StateRef, private val valuationDate: LocalDate) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call(): Unit {
|
||||
override fun call() {
|
||||
val stateAndRef = serviceHub.vaultQueryService.queryBy<PortfolioState>(VaultQueryCriteria(stateRefs = listOf(curStateRef))).states.single()
|
||||
val curState = stateAndRef.state.data
|
||||
if (ourIdentity.party == curState.participants[0]) {
|
||||
if (ourIdentity == curState.participants[0]) {
|
||||
val otherParty = serviceHub.identityService.partyFromAnonymous(curState.participants[1])
|
||||
require(otherParty != null) { "Other party must be known by this node" }
|
||||
subFlow(SimmFlow.Requester(otherParty!!, valuationDate, stateAndRef))
|
||||
|
@ -22,10 +22,10 @@ import java.util.*
|
||||
* Flow for the Bank of Corda node to issue some commercial paper to the seller's node, to sell to the buyer.
|
||||
*/
|
||||
@StartableByRPC
|
||||
class CommercialPaperIssueFlow(val amount: Amount<Currency>,
|
||||
val issueRef: OpaqueBytes,
|
||||
val recipient: Party,
|
||||
val notary: Party,
|
||||
class CommercialPaperIssueFlow(private val amount: Amount<Currency>,
|
||||
private val issueRef: OpaqueBytes,
|
||||
private val recipient: Party,
|
||||
private val notary: Party,
|
||||
override val progressTracker: ProgressTracker) : FlowLogic<SignedTransaction>() {
|
||||
constructor(amount: Amount<Currency>, issueRef: OpaqueBytes, recipient: Party, notary: Party) : this(amount, issueRef, recipient, notary, tracker())
|
||||
|
||||
@ -40,7 +40,7 @@ class CommercialPaperIssueFlow(val amount: Amount<Currency>,
|
||||
progressTracker.currentStep = ISSUING
|
||||
|
||||
val issuance: SignedTransaction = run {
|
||||
val tx = CommercialPaper().generateIssue(ourIdentity.party.ref(issueRef), amount `issued by` ourIdentity.party.ref(issueRef),
|
||||
val tx = CommercialPaper().generateIssue(ourIdentity.ref(issueRef), amount `issued by` ourIdentity.ref(issueRef),
|
||||
Instant.now() + 10.days, notary)
|
||||
|
||||
// TODO: Consider moving these two steps below into generateIssue.
|
||||
|
@ -16,8 +16,8 @@ import java.util.*
|
||||
|
||||
@InitiatingFlow
|
||||
@StartableByRPC
|
||||
class SellerFlow(val otherParty: Party,
|
||||
val amount: Amount<Currency>,
|
||||
class SellerFlow(private val otherParty: Party,
|
||||
private val amount: Amount<Currency>,
|
||||
override val progressTracker: ProgressTracker) : FlowLogic<SignedTransaction>() {
|
||||
constructor(otherParty: Party, amount: Amount<Currency>) : this(otherParty, amount, tracker())
|
||||
|
||||
@ -41,7 +41,7 @@ class SellerFlow(val otherParty: Party,
|
||||
progressTracker.currentStep = SELF_ISSUING
|
||||
|
||||
val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0]
|
||||
val cpOwner = serviceHub.keyManagementService.freshKeyAndCert(ourIdentity, false)
|
||||
val cpOwner = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, false)
|
||||
val commercialPaper = serviceHub.vaultQueryService.queryBy(CommercialPaper.State::class.java).states.first()
|
||||
|
||||
progressTracker.currentStep = TRADING
|
||||
|
@ -3,11 +3,10 @@ package net.corda.node.testing
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import net.corda.core.flows.FlowInitiator
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.node.internal.InitiatedFlowFactory
|
||||
import net.corda.node.serialization.NodeClock
|
||||
import net.corda.node.services.api.*
|
||||
@ -79,9 +78,8 @@ open class MockServiceHubInternal(
|
||||
|
||||
override fun <T : SerializeAsToken> cordaService(type: Class<T>): T = throw UnsupportedOperationException()
|
||||
|
||||
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator, me: PartyAndCertificate?): FlowStateMachineImpl<T> {
|
||||
check(me == null || me in myInfo.legalIdentitiesAndCerts) { "Attempt to start a flow with legal identity not belonging to this node." }
|
||||
return smm.executor.fetchFrom { smm.add(logic, flowInitiator, me) }
|
||||
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator, ourIdentity: Party?): FlowStateMachineImpl<T> {
|
||||
return smm.executor.fetchFrom { smm.add(logic, flowInitiator, ourIdentity) }
|
||||
}
|
||||
|
||||
override fun getFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>): InitiatedFlowFactory<*>? = null
|
||||
|
@ -12,7 +12,9 @@ import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
@ -159,4 +161,4 @@ inline fun <reified T : Any> amqpSpecific(reason: String, function: () -> Unit)
|
||||
* TODO: Should be removed after multiple identities are introduced.
|
||||
*/
|
||||
fun NodeInfo.chooseIdentityAndCert(): PartyAndCertificate = legalIdentitiesAndCerts.first()
|
||||
fun NodeInfo.chooseIdentity(): Party = legalIdentitiesAndCerts.first().party
|
||||
fun NodeInfo.chooseIdentity(): Party = chooseIdentityAndCert().party
|
||||
|
Loading…
Reference in New Issue
Block a user