mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
First cut at removing PrivateKey leakage from KeyManagementService
Fixup after rebase Restore original key property names Fixup after rebase Undo extra import that IntelliJ keeps erroneously adding. Add comments and fix docs for transaction signing. Fixes after rebase More fixes after rebase Address PR requests Address PR requests
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
package net.corda.core.node
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import java.security.KeyPair
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.time.Clock
|
||||
|
||||
/**
|
||||
@ -82,23 +83,107 @@ interface ServiceHub : ServicesForResolution {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper property to shorten code for fetching the Node's KeyPair associated with the
|
||||
* public legalIdentity Party from the key management service.
|
||||
* Helper property to shorten code for fetching the the [PublicKey] portion of the
|
||||
* Node's primary signing identity.
|
||||
* Typical use is during signing in flows and for unit test signing.
|
||||
*
|
||||
* TODO: legalIdentity can now be composed of multiple keys, should we return a list of keyPairs here? Right now
|
||||
* the logic assumes the legal identity has a composite key with only one node
|
||||
* When this [PublicKey] is passed into the signing methods below, or on the KeyManagementService
|
||||
* the matching [PrivateKey] will be looked up internally and used to sign.
|
||||
* If the key is actually a CompositeKey, the first leaf key hosted on this node
|
||||
* will be used to create the signature.
|
||||
*/
|
||||
val legalIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.legalIdentity.owningKey.keys)
|
||||
val legalIdentityKey: PublicKey get() = this.myInfo.legalIdentity.owningKey
|
||||
|
||||
/**
|
||||
* Helper property to shorten code for fetching the Node's KeyPair associated with the
|
||||
* public notaryIdentity Party from the key management service. It is assumed that this is only
|
||||
* used in contexts where the Node knows it is hosting a Notary Service. Otherwise, it will throw
|
||||
* an IllegalArgumentException.
|
||||
* Helper property to shorten code for fetching the the [PublicKey] portion of the
|
||||
* Node's Notary signing identity. It is required that the Node hosts a notary service,
|
||||
* otherwise an IllegalArgumentException will be thrown.
|
||||
* Typical use is during signing in flows and for unit test signing.
|
||||
*
|
||||
* TODO: same problem as with legalIdentityKey.
|
||||
* When this [PublicKey] is passed into the signing methods below, or on the KeyManagementService
|
||||
* the matching [PrivateKey] will be looked up internally and used to sign.
|
||||
* If the key is actually a [CompositeKey], the first leaf key hosted on this node
|
||||
* will be used to create the signature.
|
||||
*/
|
||||
val notaryIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.notaryIdentity.owningKey.keys)
|
||||
}
|
||||
val notaryIdentityKey: PublicKey get() = this.myInfo.notaryIdentity.owningKey
|
||||
|
||||
/**
|
||||
* Helper method to construct an initial partially signed transaction from a [TransactionBuilder]
|
||||
* using keys stored inside the node.
|
||||
* @param builder The [TransactionBuilder] to seal with the node's signature.
|
||||
* Any existing signatures on the builder will be preserved.
|
||||
* @param publicKey The [PublicKey] matched to the internal [PrivateKey] to use in signing this transaction.
|
||||
* If the passed in key is actually a CompositeKey the code searches for the first child key hosted within this node
|
||||
* to sign with.
|
||||
* @return Returns a SignedTransaction with the new node signature attached.
|
||||
*/
|
||||
fun signInitialTransaction(builder: TransactionBuilder, publicKey: PublicKey): SignedTransaction {
|
||||
val sig = keyManagementService.sign(builder.toWireTransaction().id.bytes, publicKey)
|
||||
builder.addSignatureUnchecked(sig)
|
||||
return builder.toSignedTransaction(false)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to construct an initial partially signed transaction from a TransactionBuilder
|
||||
* using the default identity key contained in the node.
|
||||
* @param builder The TransactionBuilder to seal with the node's signature.
|
||||
* Any existing signatures on the builder will be preserved.
|
||||
* @return Returns a SignedTransaction with the new node signature attached.
|
||||
*/
|
||||
fun signInitialTransaction(builder: TransactionBuilder): SignedTransaction = signInitialTransaction(builder, legalIdentityKey)
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to construct an initial partially signed transaction from a [TransactionBuilder]
|
||||
* using a set of keys all held in this node.
|
||||
* @param builder The [TransactionBuilder] to seal with the node's signature.
|
||||
* Any existing signatures on the builder will be preserved.
|
||||
* @param signingPubKeys A list of [PublicKeys] used to lookup the matching [PrivateKey] and sign.
|
||||
* @throws IllegalArgumentException is thrown if any keys are unavailable locally.
|
||||
* @return Returns a [SignedTransaction] with the new node signature attached.
|
||||
*/
|
||||
fun signInitialTransaction(builder: TransactionBuilder, signingPubKeys: List<PublicKey>): SignedTransaction {
|
||||
var stx: SignedTransaction? = null
|
||||
for (pubKey in signingPubKeys) {
|
||||
stx = if (stx == null) {
|
||||
signInitialTransaction(builder, pubKey)
|
||||
} else {
|
||||
addSignature(stx, pubKey)
|
||||
}
|
||||
}
|
||||
return stx!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create an additional signature for an existing (partially) [SignedTransaction].
|
||||
* @param signedTransaction The [SignedTransaction] to which the signature will apply.
|
||||
* @param publicKey The [PublicKey] matching to a signing [PrivateKey] hosted in the node.
|
||||
* If the [PublicKey] is actually a [CompositeKey] the first leaf key found locally will be used for signing.
|
||||
* @return The [DigitalSignature.WithKey] generated by signing with the internally held [PrivateKey].
|
||||
*/
|
||||
fun createSignature(signedTransaction: SignedTransaction, publicKey: PublicKey): DigitalSignature.WithKey = keyManagementService.sign(signedTransaction.id.bytes, publicKey)
|
||||
|
||||
/**
|
||||
* Helper method to create an additional signature for an existing (partially) SignedTransaction
|
||||
* using the default identity signing key of the node.
|
||||
* @param signedTransaction The SignedTransaction to which the signature will apply.
|
||||
* @return The DigitalSignature.WithKey generated by signing with the internally held identity PrivateKey.
|
||||
*/
|
||||
fun createSignature(signedTransaction: SignedTransaction): DigitalSignature.WithKey = createSignature(signedTransaction, legalIdentityKey)
|
||||
|
||||
/**
|
||||
* Helper method to append an additional signature to an existing (partially) [SignedTransaction].
|
||||
* @param signedTransaction The [SignedTransaction] to which the signature will be added.
|
||||
* @param publicKey The [PublicKey] matching to a signing [PrivateKey] hosted in the node.
|
||||
* If the [PublicKey] is actually a [CompositeKey] the first leaf key found locally will be used for signing.
|
||||
* @return A new [SignedTransaction] with the addition of the new signature.
|
||||
*/
|
||||
fun addSignature(signedTransaction: SignedTransaction, publicKey: PublicKey): SignedTransaction = signedTransaction + createSignature(signedTransaction, publicKey)
|
||||
|
||||
/**
|
||||
* Helper method to ap-pend an additional signature for an existing (partially) [SignedTransaction]
|
||||
* using the default identity signing key of the node.
|
||||
* @param signedTransaction The [SignedTransaction] to which the signature will be added.
|
||||
* @return A new [SignedTransaction] with the addition of the new signature.
|
||||
*/
|
||||
fun addSignature(signedTransaction: SignedTransaction): SignedTransaction = addSignature(signedTransaction, legalIdentityKey)
|
||||
}
|
@ -3,9 +3,8 @@ package net.corda.core.node.services
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
@ -20,8 +19,6 @@ import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import rx.Observable
|
||||
import java.io.InputStream
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
@ -373,32 +370,32 @@ class StatesNotAvailableException(override val message: String?, override val ca
|
||||
/**
|
||||
* The KMS is responsible for storing and using private keys to sign things. An implementation of this may, for example,
|
||||
* call out to a hardware security module that enforces various auditing and frequency-of-use requirements.
|
||||
*
|
||||
* The current interface is obviously not usable for those use cases: this is just where we'd put a real signing
|
||||
* interface if/when one is developed.
|
||||
*/
|
||||
|
||||
interface KeyManagementService {
|
||||
/** Returns a snapshot of the current pubkey->privkey mapping. */
|
||||
val keys: Map<PublicKey, PrivateKey>
|
||||
/**
|
||||
* Returns a snapshot of the current signing [PublicKey]s.
|
||||
* For each of these keys a [PrivateKey] is available, that can be used later for signing.
|
||||
*/
|
||||
val keys: Set<PublicKey>
|
||||
|
||||
@Throws(IllegalStateException::class)
|
||||
fun toPrivate(publicKey: PublicKey) = keys[publicKey] ?: throw IllegalStateException("No private key known for requested public key ${publicKey.toStringShort()}")
|
||||
/**
|
||||
* Generates a new random [KeyPair] and adds it to the internal key storage. Returns the public part of the pair.
|
||||
*/
|
||||
@Suspendable
|
||||
fun freshKey(): PublicKey
|
||||
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun toKeyPair(publicKey: PublicKey): KeyPair {
|
||||
when (publicKey) {
|
||||
is CompositeKey -> throw IllegalArgumentException("Got CompositeKey when single PublicKey expected.")
|
||||
else -> return KeyPair(publicKey, toPrivate(publicKey))
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the first [KeyPair] matching any of the [publicKeys] */
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun toKeyPair(publicKeys: Iterable<PublicKey>) = publicKeys.first { keys.contains(it) }.let { toKeyPair(it) }
|
||||
|
||||
/** Generates a new random key and adds it to the exposed map. */
|
||||
fun freshKey(): KeyPair
|
||||
/** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data.
|
||||
* @param bytes The data to sign over using the chosen key.
|
||||
* @param publicKey The [PublicKey] partner to an internally held [PrivateKey], either derived from the node's primary identity,
|
||||
* or previously generated via the [freshKey] method.
|
||||
* If the [PublicKey] is actually a [CompositeKey] the first leaf signing key hosted by the node is used.
|
||||
* @throws IllegalArgumentException if the input key is not a member of [keys].
|
||||
* TODO A full [KeyManagementService] implementation needs to record activity to the [AuditService] and to limit signing to
|
||||
* appropriately authorised contexts and initiating users.
|
||||
*/
|
||||
@Suspendable
|
||||
fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey
|
||||
}
|
||||
|
||||
// TODO: Move to a more appropriate location
|
||||
|
@ -3,14 +3,12 @@ package net.corda.core.transactions
|
||||
import net.corda.core.contracts.AttachmentResolutionException
|
||||
import net.corda.core.contracts.NamedByHash
|
||||
import net.corda.core.contracts.TransactionResolutionException
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.util.*
|
||||
@ -146,14 +144,5 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class, SignatureException::class)
|
||||
fun toLedgerTransaction(services: ServiceHub) = verifySignatures().toLedgerTransaction(services)
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of signing the transaction.
|
||||
*
|
||||
* @param keyPair the signer's public/private key pair.
|
||||
*
|
||||
* @return a digital signature of the transaction.
|
||||
*/
|
||||
fun signWithECDSA(keyPair: KeyPair) = keyPair.sign(this.id.bytes)
|
||||
|
||||
override fun toString(): String = "${javaClass.simpleName}(id=$id)"
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.AbstractParty
|
||||
@ -188,8 +189,7 @@ abstract class AbstractStateReplacementFlow {
|
||||
}
|
||||
|
||||
private fun sign(stx: SignedTransaction): DigitalSignature.WithKey {
|
||||
val myKey = serviceHub.legalIdentityKey
|
||||
return myKey.sign(stx.id)
|
||||
return serviceHub.createSignature(stx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.corda.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.crypto.toBase58String
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
@ -201,7 +203,7 @@ abstract class SignTransactionFlow(val otherParty: Party,
|
||||
|
||||
// Sign and send back our signature to the Initiator.
|
||||
progressTracker.currentStep = SIGNING
|
||||
val mySignature = serviceHub.legalIdentityKey.sign(checkedProposal.id)
|
||||
val mySignature = serviceHub.createSignature(checkedProposal)
|
||||
send(otherParty, mySignature)
|
||||
|
||||
// Return the fully signed transaction once it has been committed.
|
||||
|
@ -59,9 +59,8 @@ class ContractUpgradeFlow<OldState : ContractState, out NewState : ContractState
|
||||
}
|
||||
|
||||
override fun assembleTx(): Pair<SignedTransaction, Iterable<AbstractParty>> {
|
||||
val stx = assembleBareTx(originalState, modification)
|
||||
.signWith(serviceHub.legalIdentityKey)
|
||||
.toSignedTransaction(false)
|
||||
val baseTx = assembleBareTx(originalState, modification)
|
||||
val stx = serviceHub.signInitialTransaction(baseTx)
|
||||
return stx to originalState.state.data.participants
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +40,7 @@ class NotaryChangeFlow<out T : ContractState>(
|
||||
participants = resolveEncumbrances(tx)
|
||||
}
|
||||
|
||||
val myKey = serviceHub.legalIdentityKey
|
||||
tx.signWith(myKey)
|
||||
|
||||
val stx = tx.toSignedTransaction(false)
|
||||
val stx = serviceHub.signInitialTransaction(tx)
|
||||
|
||||
return Pair(stx, participants)
|
||||
}
|
||||
|
@ -3,7 +3,10 @@ package net.corda.flows
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.Timestamp
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
@ -144,8 +147,7 @@ object NotaryFlow {
|
||||
}
|
||||
|
||||
private fun sign(bits: ByteArray): DigitalSignature.WithKey {
|
||||
val mySigningKey = serviceHub.notaryIdentityKey
|
||||
return mySigningKey.sign(bits)
|
||||
return serviceHub.keyManagementService.sign(bits, serviceHub.notaryIdentityKey)
|
||||
}
|
||||
|
||||
private fun notaryException(txId: SecureHash, e: UniquenessException): NotaryException {
|
||||
|
@ -17,7 +17,6 @@ import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.core.utilities.unwrap
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
@ -48,7 +47,7 @@ object TwoPartyDealFlow {
|
||||
abstract val payload: Any
|
||||
abstract val notaryNode: NodeInfo
|
||||
abstract val otherParty: Party
|
||||
abstract val myKeyPair: KeyPair
|
||||
abstract val myKey: PublicKey
|
||||
|
||||
@Suspendable override fun call(): SignedTransaction {
|
||||
progressTracker.currentStep = SENDING_PROPOSAL
|
||||
@ -138,12 +137,7 @@ object TwoPartyDealFlow {
|
||||
|
||||
private fun signWithOurKeys(signingPubKeys: List<PublicKey>, ptx: TransactionBuilder): SignedTransaction {
|
||||
// Now sign the transaction with whatever keys we need to move the cash.
|
||||
for (publicKey in signingPubKeys.expandedCompositeKeys) {
|
||||
val privateKey = serviceHub.keyManagementService.toPrivate(publicKey)
|
||||
ptx.signWith(KeyPair(publicKey, privateKey))
|
||||
}
|
||||
|
||||
return ptx.toSignedTransaction(checkSufficientSignatures = false)
|
||||
return serviceHub.signInitialTransaction(ptx, signingPubKeys)
|
||||
}
|
||||
|
||||
@Suspendable protected abstract fun validateHandshake(handshake: Handshake<U>): Handshake<U>
|
||||
@ -158,7 +152,7 @@ object TwoPartyDealFlow {
|
||||
*/
|
||||
open class Instigator(override val otherParty: Party,
|
||||
override val payload: AutoOffer,
|
||||
override val myKeyPair: KeyPair,
|
||||
override val myKey: PublicKey,
|
||||
override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() {
|
||||
|
||||
override val notaryNode: NodeInfo get() =
|
||||
|
@ -29,7 +29,7 @@ object TxKeyFlowUtilities {
|
||||
*/
|
||||
@Suspendable
|
||||
fun provideKey(flow: FlowLogic<*>, otherSide: Party): PublicKey {
|
||||
val key = flow.serviceHub.keyManagementService.freshKey().public
|
||||
val key = flow.serviceHub.keyManagementService.freshKey()
|
||||
// TODO: Generate and sign certificate for the key, once we have signing support for composite keys
|
||||
// (in this case the legal identity key)
|
||||
flow.send(otherSide, ProvidedTransactionKey(key, null))
|
||||
|
@ -90,7 +90,7 @@ class CollectSignaturesFlowTests {
|
||||
|
||||
val command = Command(DummyContract.Commands.Create(), state.participants.map { it.owningKey })
|
||||
val builder = TransactionType.General.Builder(notary = notary).withItems(state, command)
|
||||
val ptx = builder.signWith(serviceHub.legalIdentityKey).toSignedTransaction(false)
|
||||
val ptx = serviceHub.signInitialTransaction(builder)
|
||||
val stx = subFlow(CollectSignaturesFlow(ptx))
|
||||
val ftx = subFlow(FinalityFlow(stx)).single()
|
||||
|
||||
@ -110,7 +110,7 @@ class CollectSignaturesFlowTests {
|
||||
val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity
|
||||
val command = Command(DummyContract.Commands.Create(), state.participants.map { it.owningKey })
|
||||
val builder = TransactionType.General.Builder(notary = notary).withItems(state, command)
|
||||
val ptx = builder.signWith(serviceHub.legalIdentityKey).toSignedTransaction(false)
|
||||
val ptx = serviceHub.signInitialTransaction(builder)
|
||||
val stx = subFlow(CollectSignaturesFlow(ptx))
|
||||
val ftx = subFlow(FinalityFlow(stx)).single()
|
||||
|
||||
@ -154,7 +154,7 @@ class CollectSignaturesFlowTests {
|
||||
@Test
|
||||
fun `no need to collect any signatures`() {
|
||||
val onePartyDummyContract = DummyContract.generateInitial(1337, notary, a.info.legalIdentity.ref(1))
|
||||
val ptx = onePartyDummyContract.signWith(a.services.legalIdentityKey).toSignedTransaction(false)
|
||||
val ptx = a.services.signInitialTransaction(onePartyDummyContract)
|
||||
val flow = a.services.startFlow(CollectSignaturesFlow(ptx))
|
||||
mockNet.runNetwork()
|
||||
val result = flow.resultFuture.getOrThrow()
|
||||
@ -180,8 +180,9 @@ class CollectSignaturesFlowTests {
|
||||
a.info.legalIdentity.ref(1),
|
||||
b.info.legalIdentity.ref(2),
|
||||
b.info.legalIdentity.ref(3))
|
||||
val ptx = twoPartyDummyContract.signWith(a.services.legalIdentityKey).signWith(b.services.legalIdentityKey).toSignedTransaction(false)
|
||||
val flow = a.services.startFlow(CollectSignaturesFlow(ptx))
|
||||
val signedByA = a.services.signInitialTransaction(twoPartyDummyContract)
|
||||
val signedByBoth = b.services.addSignature(signedByA)
|
||||
val flow = a.services.startFlow(CollectSignaturesFlow(signedByBoth))
|
||||
mockNet.runNetwork()
|
||||
val result = flow.resultFuture.getOrThrow()
|
||||
println(result.tx)
|
||||
|
@ -58,9 +58,8 @@ class ContractUpgradeFlowTest {
|
||||
fun `2 parties contract upgrade`() {
|
||||
// Create dummy contract.
|
||||
val twoPartyDummyContract = DummyContract.generateInitial(0, notary, a.info.legalIdentity.ref(1), b.info.legalIdentity.ref(1))
|
||||
val stx = twoPartyDummyContract.signWith(a.services.legalIdentityKey)
|
||||
.signWith(b.services.legalIdentityKey)
|
||||
.toSignedTransaction()
|
||||
val signedByA = a.services.signInitialTransaction(twoPartyDummyContract)
|
||||
val stx = b.services.addSignature(signedByA)
|
||||
|
||||
a.services.startFlow(FinalityFlow(stx, setOf(a.info.legalIdentity, b.info.legalIdentity)))
|
||||
mockNet.runNetwork()
|
||||
@ -120,9 +119,8 @@ class ContractUpgradeFlowTest {
|
||||
rpcDriver {
|
||||
// Create dummy contract.
|
||||
val twoPartyDummyContract = DummyContract.generateInitial(0, notary, a.info.legalIdentity.ref(1), b.info.legalIdentity.ref(1))
|
||||
val stx = twoPartyDummyContract.signWith(a.services.legalIdentityKey)
|
||||
.signWith(b.services.legalIdentityKey)
|
||||
.toSignedTransaction()
|
||||
val signedByA = a.services.signInitialTransaction(twoPartyDummyContract)
|
||||
val stx = b.services.addSignature(signedByA)
|
||||
|
||||
val user = rpcTestUser.copy(permissions = setOf(
|
||||
startFlowPermission<FinalityInvoker>(),
|
||||
|
Reference in New Issue
Block a user