mirror of
https://github.com/corda/corda.git
synced 2025-04-07 19:34:41 +00:00
Merge pull request #699 from corda/mnesbit-keymanagementservice-improvements
Do not expose PrivateKeys from KeyManagementService
This commit is contained in:
commit
d288fcc979
@ -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>(),
|
||||
|
@ -32,7 +32,6 @@ UNRELEASED
|
||||
* ``FlowLogic.getCounterpartyMarker`` is no longer used and been deprecated for removal. If you were using this to
|
||||
manage multiple independent message streams with the same party in the same flow then use sub-flows instead.
|
||||
|
||||
|
||||
* There are major changes to the ``Party`` class as part of confidential identities:
|
||||
|
||||
* ``Party`` has moved to the ``net.corda.core.identity`` package; there is a deprecated class in its place for
|
||||
@ -44,6 +43,25 @@ UNRELEASED
|
||||
* Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the
|
||||
name. As a result all node legal names must now be structured as X.500 distinguished names.
|
||||
|
||||
* There are major changes to the ``KeyManagementService`` and transaction signing in flows:
|
||||
|
||||
* ``ServiceHub.legalIdentityKey`` no longer returns a ``KeyPair`` it instead returns just the ``PublicKey`` portion of this pair.
|
||||
The ``ServiceHub.notaryIdentityKey`` has changed similarly.
|
||||
* The ``KeyManagementService`` now provides no mechanism to request the node's ``PrivateKey`` objects directly.
|
||||
Instead signature creation occurs in the ``KeyManagementService.sign``, with the ``PublicKey`` used to indicate
|
||||
which of the node's multiple keys to use. This lookup also works for ``CompositeKey`` scenarios
|
||||
and the service will search for a leaf key hosted on the node.
|
||||
* The ``KeyManagementService.freshKey`` method now returns only the ``PublicKey`` portion of the newly generated ``KeyPair``
|
||||
with the ``PrivateKey kept internally to the service.
|
||||
* Flows which used to acquire a node's ``KeyPair``, typically via ``ServiceHub.legalIdentityKey``,
|
||||
should instead use the helper methods on ``ServiceHub``. In particular to freeze a ``TransactionBuilder`` and
|
||||
generate an initial partially signed ``SignedTransaction`` the flow should use ``ServiceHub.signInitialTransaction``.
|
||||
Flows generating additional party signatures should use ``ServiceHub.createSignature``. Each of these methods is
|
||||
provided with two signatures. One version that signs with the default node key, the other which allows key slection
|
||||
by passing in the ``PublicKey`` partner of the desired signing key.
|
||||
* The original ``KeyPair`` signing methods have been left on the ``TransactionBuilder`` and ``SignedTransaction``, but
|
||||
should only be used as part of unit testing.
|
||||
|
||||
* The ``InitiatingFlow`` annotation also has an integer ``version`` property which assigns the initiating flow a version
|
||||
number, defaulting to 1 if it's specified. The flow version is included in the flow session request and the counterparty
|
||||
will only respond and start their own flow if the version number matches to the one they've registered with. At some
|
||||
|
@ -8,7 +8,6 @@ import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
@ -206,11 +205,9 @@ class ForeignExchangeFlow(val tradeId: String,
|
||||
builder.withItems(*theirStates.outputs.toTypedArray())
|
||||
|
||||
// We have already validated their response and trust our own data
|
||||
// so we can sign
|
||||
builder.signWith(serviceHub.legalIdentityKey)
|
||||
// create a signed transaction, but pass false as parameter, because we know it is not fully signed
|
||||
val signedTransaction = builder.toSignedTransaction(checkSufficientSignatures = false)
|
||||
return signedTransaction
|
||||
// so we can sign. Note the returned SignedTransaction is still not fully signed
|
||||
// and would not pass full verification yet.
|
||||
return serviceHub.signInitialTransaction(builder)
|
||||
}
|
||||
// DOCEND 3
|
||||
}
|
||||
@ -260,7 +257,7 @@ class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic<Unit>() {
|
||||
}
|
||||
|
||||
// assuming we have completed state and business level validation we can sign the trade
|
||||
val ourSignature = serviceHub.legalIdentityKey.sign(proposedTrade.id)
|
||||
val ourSignature = serviceHub.createSignature(proposedTrade)
|
||||
|
||||
// send the other side our signature.
|
||||
send(source, ourSignature)
|
||||
|
@ -5,7 +5,6 @@ import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.containsAny
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
@ -135,9 +134,7 @@ class SubmitTradeApprovalFlow(val tradeId: String,
|
||||
.withItems(tradeProposal, Command(TradeApprovalContract.Commands.Issue(), listOf(tradeProposal.source.owningKey)))
|
||||
tx.setTime(serviceHub.clock.instant(), Duration.ofSeconds(60))
|
||||
// We can automatically sign as there is no untrusted data.
|
||||
tx.signWith(serviceHub.legalIdentityKey)
|
||||
// Convert to a SignedTransaction that we can send to the notary
|
||||
val signedTx = tx.toSignedTransaction(false)
|
||||
val signedTx = serviceHub.signInitialTransaction(tx)
|
||||
// Notarise and distribute.
|
||||
subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.legalIdentity, counterparty)))
|
||||
// Return the initial state
|
||||
@ -199,9 +196,9 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow
|
||||
tx.setTime(serviceHub.clock.instant(), Duration.ofSeconds(60))
|
||||
// We can sign this transaction immediately as we have already checked all the fields and the decision
|
||||
// is ultimately a manual one from the caller.
|
||||
tx.signWith(serviceHub.legalIdentityKey)
|
||||
// Convert to SignedTransaction we can pass around certain that it cannot be modified.
|
||||
val selfSignedTx = tx.toSignedTransaction(false)
|
||||
// As a SignedTransaction we can pass the data around certain that it cannot be modified,
|
||||
// although we do require further signatures to complete the process.
|
||||
val selfSignedTx = serviceHub.signInitialTransaction(tx)
|
||||
//DOCEND 2
|
||||
// Send the signed transaction to the originator and await their signature to confirm
|
||||
val allPartySignedTx = sendAndReceive<DigitalSignature.WithKey>(newState.source, selfSignedTx).unwrap {
|
||||
@ -257,7 +254,7 @@ class RecordCompletionFlow(val source: Party) : FlowLogic<Unit>() {
|
||||
}
|
||||
// DOCEND 3
|
||||
// Having verified the SignedTransaction passed to us we can sign it too
|
||||
val ourSignature = serviceHub.legalIdentityKey.sign(completeTx.tx.id)
|
||||
val ourSignature = serviceHub.createSignature(completeTx)
|
||||
// Send our signature to the other party.
|
||||
send(source, ourSignature)
|
||||
// N.B. The FinalityProtocol will be responsible for Notarising the SignedTransaction
|
||||
|
@ -8,7 +8,6 @@ import net.corda.core.toFuture
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.services.network.NetworkMapService
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.node.utilities.transaction
|
||||
|
@ -131,7 +131,7 @@ each side.
|
||||
val notaryNode: NodeInfo,
|
||||
val assetToSell: StateAndRef<OwnableState>,
|
||||
val price: Amount<Currency>,
|
||||
val myKeyPair: KeyPair,
|
||||
val myKey: PublicKey,
|
||||
override val progressTracker: ProgressTracker = Seller.tracker()) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
@ -160,7 +160,8 @@ Going through the data needed to become a seller, we have:
|
||||
information on notaries.
|
||||
- ``assetToSell: StateAndRef<OwnableState>`` - a pointer to the ledger entry that represents the thing being sold.
|
||||
- ``price: Amount<Currency>`` - the agreed on price that the asset is being sold for (without an issuer constraint).
|
||||
- ``myKeyPair: KeyPair`` - the key pair that controls the asset being sold. It will be used to sign the transaction.
|
||||
- ``myKey: PublicKey`` - the PublicKey part of the node's internal KeyPair that controls the asset being sold.
|
||||
The matching PrivateKey stored in the KeyManagementService will be used to sign the transaction.
|
||||
|
||||
And for the buyer:
|
||||
|
||||
@ -439,7 +440,7 @@ to create a simple seller starter flow that has the annotation we need:
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0]
|
||||
val cpOwnerKey: KeyPair = serviceHub.legalIdentityKey
|
||||
val cpOwnerKey: PublicKey = serviceHub.legalIdentityKey
|
||||
return subFlow(TwoPartyTradeFlow.Seller(otherParty, notary, assetToSell, price, cpOwnerKey))
|
||||
}
|
||||
}
|
||||
|
@ -55,10 +55,9 @@ resolving the attachment references to the attachments. Commands with valid sign
|
||||
When constructing a new transaction from scratch, you use ``TransactionBuilder``, which is a mutable transaction that
|
||||
can be signed once its construction is complete. This builder class should be used to create the initial transaction representation
|
||||
(before signature, before verification). It is intended to be passed around code that may edit it by adding new states/commands.
|
||||
Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from multiple parties.
|
||||
It is typical for contract classes to expose helper methods that can contribute to a ``TransactionBuilder``. Once a transaction
|
||||
has been constructed using the builders ``toWireTransaction`` or ``toSignedTransaction`` function, it shared with other
|
||||
participants using the :doc:`key-concepts-flow-framework`.
|
||||
Then once the states and commands are right then an initial DigitalSignature.WithKey can be added to freeze the transaction data.
|
||||
Typically, the signInitialTransaction method on the flow's serviceHub object will be used to look up the default node identity PrivateKey,
|
||||
sign the transaction and return a partially signed SignedTransaction. This can then be distributed to other participants using the :doc:`key-concepts-flow-framework`.
|
||||
|
||||
Here's an example of building a transaction that creates an issuance of bananas (note that bananas are not a real
|
||||
contract type in the library):
|
||||
@ -69,10 +68,9 @@ contract type in the library):
|
||||
|
||||
val notaryToUse: Party = ...
|
||||
val txb = TransactionBuilder(notary = notaryToUse).withItems(BananaState(Amount(20, Bananas), fromCountry = "Elbonia"))
|
||||
txb.signWith(myKey)
|
||||
txb.setTime(Instant.now(), notaryToUse, 30.seconds)
|
||||
// We must disable the check for sufficient signatures, because this transaction is not yet notarised.
|
||||
val stx = txb.toSignedTransaction(checkSufficientSignatures = false)
|
||||
// Carry out the initial signing of the transaction and creation of a (partial) SignedTransation.
|
||||
val stx = serviceHub.signInitialTransaction(txb)
|
||||
// Alternatively, let's just check it verifies pretending it was fully signed. To do this, we get
|
||||
// a WireTransaction, which is what the SignedTransaction wraps. Thus by verifying that directly we
|
||||
// skip signature checking.
|
||||
|
@ -65,12 +65,12 @@ PersistentKeyManagementService and E2ETestKeyManagementService
|
||||
Typical usage of these services is to locate an appropriate
|
||||
``PrivateKey`` to complete and sign a verified transaction as part of a
|
||||
flow. The normal node legal identifier keys are typically accessed via
|
||||
helper extension methods on the ``ServiceHub``, but these ultimately
|
||||
fetch the keys from the ``KeyManagementService``. The
|
||||
helper extension methods on the ``ServiceHub``, but these ultimately delegate
|
||||
signing to internal ``PrivateKeys`` from the ``KeyManagementService``. The
|
||||
``KeyManagementService`` interface also allows other keys to be
|
||||
generated if anonymous keys are needed in a flow. Note that this
|
||||
interface works at the level of individual ``PublicKey``/``PrivateKey``
|
||||
pairs, but the signing authority will be represented by a
|
||||
interface works at the level of individual ``PublicKey`` and internally
|
||||
matched ``PrivateKey` pairs, but the signing authority may be represented by a
|
||||
``CompositeKey`` on the ``NodeInfo`` to allow key clustering and
|
||||
threshold schemes.
|
||||
|
||||
|
@ -168,11 +168,12 @@ Let's see what parameters we pass to the constructor of this oracle.
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
class Oracle(val identity: Party, private val signingKey: KeyPair, val clock: Clock) = TODO()
|
||||
class Oracle(val identity: Party, private val signingKey: PublicKey, val clock: Clock) = TODO()
|
||||
|
||||
Here we see the oracle needs to have its own identity, so it can check which transaction commands it is expected to
|
||||
sign for, and also needs a pair of signing keys with which it signs transactions. The clock is used for the deadline
|
||||
functionality which we will not discuss further here.
|
||||
sign for, and also needs the PublicKey portion of its signing key. Later this PublicKey will be passed to the KeyManagementService
|
||||
to identify the internal PrivateKey used for transaction signing.
|
||||
The clock is used for the deadline functionality which we will not discuss further here.
|
||||
|
||||
Assuming you have a data source and can query it, it should be very easy to implement your ``query`` method and the
|
||||
parameter and ``CommandData`` classes.
|
||||
|
@ -704,10 +704,10 @@ from the ledger). Finally, we add a Redeem command that should be signed by the
|
||||
versions with a more complete way to express issuer constraints.
|
||||
|
||||
A ``TransactionBuilder`` is not by itself ready to be used anywhere, so first, we must convert it to something that
|
||||
is recognised by the network. The most important next step is for the participating entities to sign it using the
|
||||
``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
|
||||
signature inside the ``TransactionBuilder``. Once all parties have signed, you can call ``TransactionBuilder.toSignedTransaction()``
|
||||
to get a ``SignedTransaction`` object.
|
||||
is recognised by the network. The most important next step is for the participating entities to sign it. Typically,
|
||||
an initiating flow will create an initial partially signed ``SignedTransaction`` by calling the ``serviceHub.signInitialTransaction`` method.
|
||||
Then the frozen ``SignedTransaction`` can be passed to other nodes by the flow, these can sign using ``serviceHub.createSignature`` and distribute.
|
||||
The ``CollectSignaturesFlow`` provides a generic implementation of this process that can be used as a ``subFlow`` .
|
||||
|
||||
You can see how transactions flow through the different stages of construction by examining the commercial paper
|
||||
unit tests.
|
||||
|
@ -63,9 +63,8 @@ We then sign the transaction, build and record it to our transaction storage:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
val mySigningKey: KeyPair = serviceHub.legalIdentityKey
|
||||
builder.signWith(mySigningKey)
|
||||
val issueTransaction = builder.toSignedTransaction()
|
||||
val mySigningKey: PublicKey = serviceHub.legalIdentityKey
|
||||
val issueTransaction = serviceHub.signInitialTransaction(issueTransaction, mySigningKey)
|
||||
serviceHub.recordTransactions(issueTransaction)
|
||||
|
||||
The transaction is recorded and we now have a state (asset) in possession that we can transfer to someone else. Note
|
||||
@ -97,9 +96,9 @@ Again we sign the transaction, and build it:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
moveTransactionBuilder.signWith(mySigningKey)
|
||||
// We build it without checking if all signatures are present, because we know that the notary signature is missing
|
||||
val moveTransaction = builder.toSignedTransaction(checkSufficientSignatures = false)
|
||||
// We build it and add our default identity signature without checking if all signatures are present,
|
||||
// Note we know that the notary signature is missing, so thie SignedTransaction is still partial.
|
||||
val moveTransaction = serviceHub.signInitialTransaction(moveTransactionBuilder)
|
||||
|
||||
Next we need to obtain a signature from the notary for the transaction to be valid. Prior to signing, the notary will
|
||||
commit our old (input) state so it cannot be used again.
|
||||
|
@ -24,17 +24,15 @@ fun ServiceHub.fillWithSomeTestDeals(dealIds: List<String>,
|
||||
revisions: Int? = 0,
|
||||
participants: List<AbstractParty> = emptyList()) : Vault<DealState> {
|
||||
val freshKey = keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
val recipient = AnonymousParty(freshPublicKey)
|
||||
val recipient = AnonymousParty(freshKey)
|
||||
|
||||
val transactions: List<SignedTransaction> = dealIds.map {
|
||||
// Issue a deal state
|
||||
val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyDealContract.State(ref = it, participants = participants.plus(recipient)))
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
return@map dummyIssue.toSignedTransaction()
|
||||
return@map signInitialTransaction(dummyIssue)
|
||||
}
|
||||
|
||||
recordTransactions(transactions)
|
||||
@ -52,18 +50,16 @@ fun ServiceHub.fillWithSomeTestLinearStates(numberToCreate: Int,
|
||||
uid: UniqueIdentifier = UniqueIdentifier(),
|
||||
participants: List<AbstractParty> = emptyList()) : Vault<LinearState> {
|
||||
val freshKey = keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
val recipient = AnonymousParty(freshPublicKey)
|
||||
val recipient = AnonymousParty(freshKey)
|
||||
|
||||
val transactions: List<SignedTransaction> = (1..numberToCreate).map {
|
||||
// Issue a Linear state
|
||||
val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(linearId = uid, participants = participants.plus(recipient)))
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}
|
||||
|
||||
return@map dummyIssue.toSignedTransaction(true)
|
||||
return@map signInitialTransaction(dummyIssue)
|
||||
}
|
||||
|
||||
recordTransactions(transactions)
|
||||
|
@ -44,9 +44,6 @@ class CashExitFlow(val amount: Amount<Currency>, val issueRef: OpaqueBytes, prog
|
||||
} catch (e: InsufficientBalanceException) {
|
||||
throw CashException("Exiting more cash than exists", e)
|
||||
}
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
val myKey = serviceHub.legalIdentityKey
|
||||
builder.signWith(myKey)
|
||||
|
||||
// Work out who the owners of the burnt states were
|
||||
val inputStatesNullable = serviceHub.vaultService.statesForRefs(builder.inputStates())
|
||||
@ -63,9 +60,11 @@ class CashExitFlow(val amount: Amount<Currency>, val issueRef: OpaqueBytes, prog
|
||||
.map { serviceHub.identityService.partyFromAnonymous(it.owner) }
|
||||
.filterNotNull()
|
||||
.toSet()
|
||||
// Sign transaction
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
val tx = serviceHub.signInitialTransaction(builder)
|
||||
|
||||
// Commit the transaction
|
||||
val tx = builder.toSignedTransaction(checkSufficientSignatures = false)
|
||||
progressTracker.currentStep = FINALISING_TX
|
||||
finaliseTx(participants, tx, "Unable to notarise exit")
|
||||
return tx
|
||||
|
@ -40,9 +40,7 @@ class CashIssueFlow(val amount: Amount<Currency>,
|
||||
// TODO: Get a transaction key, don't just re-use the owning key
|
||||
Cash().generateIssue(builder, amount.issuedBy(issuer), recipient, notary)
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
val myKey = serviceHub.legalIdentityKey
|
||||
builder.signWith(myKey)
|
||||
val tx = builder.toSignedTransaction()
|
||||
val tx = serviceHub.signInitialTransaction(builder)
|
||||
progressTracker.currentStep = FINALISING_TX
|
||||
subFlow(FinalityFlow(tx))
|
||||
return tx
|
||||
|
@ -4,14 +4,11 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.InsufficientBalanceException
|
||||
import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.crypto.expandedCompositeKeys
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -47,13 +44,9 @@ open class CashPaymentFlow(
|
||||
}
|
||||
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
keysForSigning.expandedCompositeKeys.forEach {
|
||||
val key = serviceHub.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}")
|
||||
builder.signWith(KeyPair(it, key))
|
||||
}
|
||||
val tx = serviceHub.signInitialTransaction(spendTX, keysForSigning)
|
||||
|
||||
progressTracker.currentStep = FINALISING_TX
|
||||
val tx = spendTX.toSignedTransaction(checkSufficientSignatures = false)
|
||||
finaliseTx(setOf(recipient), tx, "Unable to notarise spend")
|
||||
return tx
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.contracts.asset.sumCashBy
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.expandedCompositeKeys
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
@ -19,7 +17,6 @@ import net.corda.core.transactions.WireTransaction
|
||||
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
|
||||
import java.util.*
|
||||
|
||||
@ -68,7 +65,7 @@ object TwoPartyTradeFlow {
|
||||
val notaryNode: NodeInfo,
|
||||
val assetToSell: StateAndRef<OwnableState>,
|
||||
val price: Amount<Currency>,
|
||||
val myKeyPair: KeyPair,
|
||||
val myKey: PublicKey,
|
||||
override val progressTracker: ProgressTracker = Seller.tracker()) : FlowLogic<SignedTransaction>() {
|
||||
|
||||
companion object {
|
||||
@ -102,9 +99,8 @@ object TwoPartyTradeFlow {
|
||||
private fun receiveAndCheckProposedTransaction(): SignedTransaction {
|
||||
progressTracker.currentStep = AWAITING_PROPOSAL
|
||||
|
||||
val myPublicKey = myKeyPair.public
|
||||
// Make the first message we'll send to kick off the flow.
|
||||
val hello = SellerTradeInfo(assetToSell, price, myPublicKey)
|
||||
val hello = SellerTradeInfo(assetToSell, price, myKey)
|
||||
// What we get back from the other side is a transaction that *might* be valid and acceptable to us,
|
||||
// but we must check it out thoroughly before we sign!
|
||||
val untrustedSTX = sendAndReceive<SignedTransaction>(otherParty, hello)
|
||||
@ -112,14 +108,14 @@ object TwoPartyTradeFlow {
|
||||
progressTracker.currentStep = VERIFYING
|
||||
return untrustedSTX.unwrap {
|
||||
// Check that the tx proposed by the buyer is valid.
|
||||
val wtx: WireTransaction = it.verifySignatures(myPublicKey, notaryNode.notaryIdentity.owningKey)
|
||||
val wtx: WireTransaction = it.verifySignatures(myKey, notaryNode.notaryIdentity.owningKey)
|
||||
logger.trace { "Received partially signed transaction: ${it.id}" }
|
||||
|
||||
// Download and check all the things that this transaction depends on and verify it is contract-valid,
|
||||
// even though it is missing signatures.
|
||||
subFlow(ResolveTransactionsFlow(wtx, otherParty))
|
||||
|
||||
if (wtx.outputs.map { it.data }.sumCashBy(AnonymousParty(myPublicKey)).withoutIssuer() != price)
|
||||
if (wtx.outputs.map { it.data }.sumCashBy(AnonymousParty(myKey)).withoutIssuer() != price)
|
||||
throw FlowException("Transaction is not sending us the right amount of cash")
|
||||
|
||||
it
|
||||
@ -141,7 +137,7 @@ object TwoPartyTradeFlow {
|
||||
|
||||
open fun calculateOurSignature(partialTX: SignedTransaction): DigitalSignature.WithKey {
|
||||
progressTracker.currentStep = SIGNING
|
||||
return myKeyPair.sign(partialTX.id)
|
||||
return serviceHub.createSignature(partialTX, myKey)
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,12 +203,7 @@ object TwoPartyTradeFlow {
|
||||
|
||||
private fun signWithOurKeys(cashSigningPubKeys: List<PublicKey>, ptx: TransactionBuilder): SignedTransaction {
|
||||
// Now sign the transaction with whatever keys we need to move the cash.
|
||||
for (publicKey in cashSigningPubKeys.expandedCompositeKeys) {
|
||||
val privateKey = serviceHub.keyManagementService.toPrivate(publicKey)
|
||||
ptx.signWith(KeyPair(publicKey, privateKey))
|
||||
}
|
||||
|
||||
return ptx.toSignedTransaction(checkSufficientSignatures = false)
|
||||
return serviceHub.signInitialTransaction(ptx, cashSigningPubKeys)
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
@ -229,8 +220,8 @@ object TwoPartyTradeFlow {
|
||||
// we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
|
||||
// reveal who the owner actually is. The key management service is expected to derive a unique key from some
|
||||
// initial seed in order to provide privacy protection.
|
||||
val freshPublicKey = serviceHub.keyManagementService.freshKey().public
|
||||
val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(AnonymousParty(freshPublicKey))
|
||||
val freshKey = serviceHub.keyManagementService.freshKey()
|
||||
val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(AnonymousParty(freshKey))
|
||||
tx.addOutputState(state, tradeRequest.assetForSale.state.notary)
|
||||
tx.addCommand(command, tradeRequest.assetForSale.state.data.owner.owningKey)
|
||||
|
||||
|
@ -23,7 +23,6 @@ import net.corda.node.utilities.transaction
|
||||
import net.corda.testing.node.NodeBasedTest
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -43,25 +42,21 @@ class BFTNotaryServiceTests : NodeBasedTest() {
|
||||
val alice = startNode(ALICE.name).getOrThrow()
|
||||
|
||||
val notaryParty = alice.netMapCache.getNotary(notaryCommonName)!!
|
||||
val notaryNodeKeyPair = with(masterNode) { database.transaction { services.notaryIdentityKey } }
|
||||
val aliceKey = with(alice) { database.transaction { services.legalIdentityKey } }
|
||||
|
||||
val inputState = issueState(alice, notaryParty, notaryNodeKeyPair)
|
||||
val inputState = issueState(alice, notaryParty)
|
||||
|
||||
val firstSpendTx = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||
signWith(aliceKey)
|
||||
toSignedTransaction(false)
|
||||
}
|
||||
val firstTxBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState)
|
||||
val firstSpendTx = alice.services.signInitialTransaction(firstTxBuilder)
|
||||
|
||||
val firstSpend = alice.services.startFlow(NotaryFlow.Client(firstSpendTx))
|
||||
firstSpend.resultFuture.getOrThrow()
|
||||
|
||||
val secondSpendTx = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||
val secondSpendBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||
val dummyState = DummyContract.SingleOwnerState(0, alice.info.legalIdentity)
|
||||
addOutputState(dummyState)
|
||||
signWith(aliceKey)
|
||||
toSignedTransaction(false)
|
||||
this
|
||||
}
|
||||
val secondSpendTx = alice.services.signInitialTransaction(secondSpendBuilder)
|
||||
val secondSpend = alice.services.startFlow(NotaryFlow.Client(secondSpendTx))
|
||||
|
||||
val ex = assertFailsWith(NotaryException::class) { secondSpend.resultFuture.getOrThrow() }
|
||||
@ -69,14 +64,12 @@ class BFTNotaryServiceTests : NodeBasedTest() {
|
||||
assertEquals(error.txId, secondSpendTx.id)
|
||||
}
|
||||
|
||||
private fun issueState(node: AbstractNode, notary: Party, notaryKey: KeyPair): StateAndRef<*> {
|
||||
private fun issueState(node: AbstractNode, notary: Party): StateAndRef<*> {
|
||||
return node.database.transaction {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||
tx.signWith(node.services.legalIdentityKey)
|
||||
tx.signWith(notaryKey)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||
val stx = node.services.signInitialTransaction(builder)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||
StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ import net.corda.node.utilities.transaction
|
||||
import net.corda.testing.node.NodeBasedTest
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -33,24 +32,21 @@ class RaftNotaryServiceTests : NodeBasedTest() {
|
||||
).getOrThrow()
|
||||
|
||||
val notaryParty = alice.netMapCache.getNotary(notaryName)!!
|
||||
val notaryNodeKeyPair = with(masterNode) { database.transaction { services.notaryIdentityKey } }
|
||||
val aliceKey = with(alice) { database.transaction { services.legalIdentityKey } }
|
||||
|
||||
val inputState = issueState(alice, notaryParty, notaryNodeKeyPair)
|
||||
val inputState = issueState(alice, notaryParty)
|
||||
|
||||
val firstTxBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState)
|
||||
val firstSpendTx = alice.services.signInitialTransaction(firstTxBuilder)
|
||||
|
||||
val firstSpendTx = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||
signWith(aliceKey)
|
||||
toSignedTransaction(false)
|
||||
}
|
||||
val firstSpend = alice.services.startFlow(NotaryFlow.Client(firstSpendTx))
|
||||
firstSpend.resultFuture.getOrThrow()
|
||||
|
||||
val secondSpendTx = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||
val secondSpendBuilder = TransactionType.General.Builder(notaryParty).withItems(inputState).run {
|
||||
val dummyState = DummyContract.SingleOwnerState(0, alice.info.legalIdentity)
|
||||
addOutputState(dummyState)
|
||||
signWith(aliceKey)
|
||||
toSignedTransaction(false)
|
||||
this
|
||||
}
|
||||
val secondSpendTx = alice.services.signInitialTransaction(secondSpendBuilder)
|
||||
val secondSpend = alice.services.startFlow(NotaryFlow.Client(secondSpendTx))
|
||||
|
||||
val ex = assertFailsWith(NotaryException::class) { secondSpend.resultFuture.getOrThrow() }
|
||||
@ -58,14 +54,12 @@ class RaftNotaryServiceTests : NodeBasedTest() {
|
||||
assertEquals(error.txId, secondSpendTx.id)
|
||||
}
|
||||
|
||||
private fun issueState(node: AbstractNode, notary: Party, notaryKey: KeyPair): StateAndRef<*> {
|
||||
private fun issueState(node: AbstractNode, notary: Party): StateAndRef<*> {
|
||||
return node.database.transaction {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||
tx.signWith(node.services.legalIdentityKey)
|
||||
tx.signWith(notaryKey)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||
val stx = node.services.signInitialTransaction(builder)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||
StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0))
|
||||
}
|
||||
}
|
||||
}
|
@ -70,7 +70,7 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
||||
val nodeInfo = NodeInfo(net.myAddress, Party(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion)
|
||||
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
||||
val request = RegistrationRequest(registration.toWire(identity.private), net.myAddress)
|
||||
val request = RegistrationRequest(registration.toWire(keyService, identity.public), net.myAddress)
|
||||
return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress)
|
||||
}
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
|
||||
val reg = NodeRegistration(info, instant.toEpochMilli(), ADD, expires)
|
||||
val legalIdentityKey = obtainLegalIdentityKey()
|
||||
val request = NetworkMapService.RegistrationRequest(reg.toWire(legalIdentityKey.private), net.myAddress)
|
||||
val request = NetworkMapService.RegistrationRequest(reg.toWire(keyManagement, legalIdentityKey.public), net.myAddress)
|
||||
return net.sendRequest(NetworkMapService.REGISTER_TOPIC, request, networkMapAddress)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
package net.corda.node.services.keys
|
||||
|
||||
import net.corda.core.ThreadBox
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import java.security.KeyPair
|
||||
@ -38,13 +41,26 @@ class E2ETestKeyManagementService(initialKeys: Set<KeyPair>) : SingletonSerializ
|
||||
}
|
||||
|
||||
// Accessing this map clones it.
|
||||
override val keys: Map<PublicKey, PrivateKey> get() = mutex.locked { HashMap(keys) }
|
||||
override val keys: Set<PublicKey> get() = mutex.locked { keys.keys }
|
||||
|
||||
override fun freshKey(): KeyPair {
|
||||
override fun freshKey(): PublicKey {
|
||||
val keyPair = generateKeyPair()
|
||||
mutex.locked {
|
||||
keys[keyPair.public] = keyPair.private
|
||||
}
|
||||
return keyPair
|
||||
return keyPair.public
|
||||
}
|
||||
|
||||
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
|
||||
return mutex.locked {
|
||||
val pk = publicKey.keys.first { keys.containsKey(it) }
|
||||
KeyPair(pk, keys[pk]!!)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
|
||||
val keyPair = getSigningKeyPair(publicKey)
|
||||
val signature = keyPair.sign(bytes)
|
||||
return signature
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package net.corda.node.services.keys
|
||||
|
||||
import net.corda.core.ThreadBox
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.node.utilities.*
|
||||
@ -10,7 +13,6 @@ import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A persistent re-implementation of [E2ETestKeyManagementService] to support node re-start.
|
||||
@ -50,13 +52,27 @@ class PersistentKeyManagementService(initialKeys: Set<KeyPair>) : SingletonSeria
|
||||
}
|
||||
}
|
||||
|
||||
override val keys: Map<PublicKey, PrivateKey> get() = mutex.locked { HashMap(keys) }
|
||||
override val keys: Set<PublicKey> get() = mutex.locked { keys.keys }
|
||||
|
||||
override fun freshKey(): KeyPair {
|
||||
override fun freshKey(): PublicKey {
|
||||
val keyPair = generateKeyPair()
|
||||
mutex.locked {
|
||||
keys[keyPair.public] = keyPair.private
|
||||
}
|
||||
return keyPair
|
||||
return keyPair.public
|
||||
}
|
||||
|
||||
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
|
||||
return mutex.locked {
|
||||
val pk = publicKey.keys.first { keys.containsKey(it) }
|
||||
KeyPair(pk, keys[pk]!!)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
|
||||
val keyPair = getSigningKeyPair(publicKey)
|
||||
val signature = keyPair.sign(bytes)
|
||||
return signature
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.random63BitValue
|
||||
@ -31,7 +32,7 @@ import net.corda.node.services.network.NetworkMapService.Companion.SUBSCRIPTION_
|
||||
import net.corda.node.utilities.AddOrRemove
|
||||
import net.corda.node.utilities.AddOrRemove.ADD
|
||||
import net.corda.node.utilities.AddOrRemove.REMOVE
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.time.Instant
|
||||
import java.time.Period
|
||||
@ -322,9 +323,9 @@ data class NodeRegistration(val node: NodeInfo, val serial: Long, val type: AddO
|
||||
/**
|
||||
* Build a node registration in wire format.
|
||||
*/
|
||||
fun toWire(privateKey: PrivateKey): WireNodeRegistration {
|
||||
fun toWire(keyManager: KeyManagementService, publicKey: PublicKey): WireNodeRegistration {
|
||||
val regSerialized = this.serialize()
|
||||
val regSig = privateKey.sign(regSerialized.bytes, node.legalIdentity.owningKey)
|
||||
val regSig = keyManager.sign(regSerialized.bytes, publicKey)
|
||||
|
||||
return WireNodeRegistration(regSerialized, regSig)
|
||||
}
|
||||
|
@ -9,7 +9,10 @@ import bftsmart.tom.server.defaultservices.DefaultReplier
|
||||
import bftsmart.tom.util.Extractor
|
||||
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.sign
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.TimestampChecker
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
@ -198,8 +201,7 @@ object BFTSMaRt {
|
||||
}
|
||||
|
||||
protected fun sign(bytes: ByteArray): DigitalSignature.WithKey {
|
||||
val mySigningKey = db.transaction { services.notaryIdentityKey }
|
||||
return mySigningKey.sign(bytes)
|
||||
return db.transaction { services.keyManagementService.sign(bytes, services.notaryIdentityKey) }
|
||||
}
|
||||
|
||||
// TODO:
|
||||
|
@ -243,7 +243,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
|
||||
}
|
||||
|
||||
override fun notifyAll(txns: Iterable<WireTransaction>) {
|
||||
val ourKeys = services.keyManagementService.keys.keys
|
||||
val ourKeys = services.keyManagementService.keys
|
||||
val netDelta = txns.fold(Vault.NoUpdate) { netDelta, txn -> netDelta + makeUpdate(txn, ourKeys) }
|
||||
if (netDelta != Vault.NoUpdate) {
|
||||
recordUpdate(netDelta)
|
||||
|
@ -5,21 +5,24 @@ import net.corda.contracts.CommercialPaper
|
||||
import net.corda.contracts.asset.*
|
||||
import net.corda.contracts.testing.fillWithSomeTestCash
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.days
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowStateMachine
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.map
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.rootCause
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
@ -87,8 +90,6 @@ class TwoPartyTradeFlowTests {
|
||||
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||
val aliceKey = aliceNode.services.legalIdentityKey
|
||||
val notaryKey = notaryNode.services.notaryIdentityKey
|
||||
|
||||
aliceNode.disableDBCloseOnStop()
|
||||
bobNode.disableDBCloseOnStop()
|
||||
@ -102,7 +103,7 @@ class TwoPartyTradeFlowTests {
|
||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, MEGA_CORP_PUBKEY)
|
||||
|
||||
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode,
|
||||
"alice's paper".outputStateAndRef())
|
||||
@ -133,8 +134,6 @@ class TwoPartyTradeFlowTests {
|
||||
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||
val aliceKey = aliceNode.services.legalIdentityKey
|
||||
val notaryKey = notaryNode.services.notaryIdentityKey
|
||||
|
||||
aliceNode.disableDBCloseOnStop()
|
||||
bobNode.disableDBCloseOnStop()
|
||||
@ -149,7 +148,7 @@ class TwoPartyTradeFlowTests {
|
||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, MEGA_CORP_PUBKEY)
|
||||
|
||||
val cashLockId = UUID.randomUUID()
|
||||
bobNode.database.transaction {
|
||||
@ -184,8 +183,6 @@ class TwoPartyTradeFlowTests {
|
||||
var bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||
aliceNode.disableDBCloseOnStop()
|
||||
bobNode.disableDBCloseOnStop()
|
||||
val aliceKey = aliceNode.services.legalIdentityKey
|
||||
val notaryKey = notaryNode.services.notaryIdentityKey
|
||||
|
||||
val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.PeerHandle
|
||||
val networkMapAddr = notaryNode.info.address
|
||||
@ -199,7 +196,7 @@ class TwoPartyTradeFlowTests {
|
||||
fillUpForSeller(false, aliceNode.info.legalIdentity,
|
||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, MEGA_CORP_PUBKEY)
|
||||
val aliceFuture = runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef()).sellerResult
|
||||
|
||||
// Everything is on this thread so we can now step through the flow one step at a time.
|
||||
@ -302,8 +299,6 @@ class TwoPartyTradeFlowTests {
|
||||
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||
val aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name)
|
||||
val bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name)
|
||||
val alice = aliceNode.info.legalIdentity
|
||||
val aliceKey = aliceNode.services.legalIdentityKey
|
||||
|
||||
ledger(aliceNode.services) {
|
||||
|
||||
@ -319,16 +314,15 @@ class TwoPartyTradeFlowTests {
|
||||
}
|
||||
|
||||
val extraKey = bobNode.keyManagement.freshKey()
|
||||
val extraPublicKey = extraKey.public
|
||||
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(extraPublicKey),
|
||||
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(extraKey),
|
||||
DUMMY_CASH_ISSUER.party,
|
||||
notaryNode.info.notaryIdentity).second
|
||||
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, bobNode.services.legalIdentityKey, extraKey)
|
||||
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, extraKey, DUMMY_CASH_ISSUER_KEY.public, MEGA_CORP_PUBKEY)
|
||||
val alicesFakePaper = aliceNode.database.transaction {
|
||||
fillUpForSeller(false, alice,
|
||||
fillUpForSeller(false, aliceNode.info.legalIdentity,
|
||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey)
|
||||
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, MEGA_CORP_PUBKEY)
|
||||
|
||||
net.runNetwork() // Clear network map registration messages
|
||||
|
||||
@ -404,7 +398,6 @@ class TwoPartyTradeFlowTests {
|
||||
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||
val aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name)
|
||||
val bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name)
|
||||
val aliceKey = aliceNode.services.legalIdentityKey
|
||||
|
||||
ledger(aliceNode.services) {
|
||||
|
||||
@ -419,18 +412,18 @@ class TwoPartyTradeFlowTests {
|
||||
attachment(ByteArrayInputStream(stream.toByteArray()))
|
||||
}
|
||||
|
||||
val bobsKey = bobNode.keyManagement.freshKey().public
|
||||
val bobsKey = bobNode.keyManagement.freshKey()
|
||||
val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(bobsKey),
|
||||
DUMMY_CASH_ISSUER.party,
|
||||
notaryNode.info.notaryIdentity).second
|
||||
insertFakeTransactions(bobsFakeCash, bobNode, notaryNode)
|
||||
insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, DUMMY_CASH_ISSUER_KEY.public, MEGA_CORP_PUBKEY)
|
||||
|
||||
val alicesFakePaper = aliceNode.database.transaction {
|
||||
fillUpForSeller(false, aliceNode.info.legalIdentity,
|
||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, MEGA_CORP_PUBKEY)
|
||||
|
||||
net.runNetwork() // Clear network map registration messages
|
||||
|
||||
@ -524,21 +517,19 @@ class TwoPartyTradeFlowTests {
|
||||
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||
val alice = aliceNode.info.legalIdentity
|
||||
val aliceKey = aliceNode.services.legalIdentityKey
|
||||
val bob = bobNode.info.legalIdentity
|
||||
val bobKey = bobNode.services.legalIdentityKey
|
||||
val issuer = MEGA_CORP.ref(1, 2, 3)
|
||||
|
||||
val bobsBadCash = fillUpForBuyer(bobError, bob, DUMMY_CASH_ISSUER.party,
|
||||
notaryNode.info.notaryIdentity).second
|
||||
val bobsBadCash = bobNode.database.transaction {
|
||||
fillUpForBuyer(bobError, bobNode.info.legalIdentity, DUMMY_CASH_ISSUER.party,
|
||||
notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
val alicesFakePaper = aliceNode.database.transaction {
|
||||
fillUpForSeller(aliceError, alice,
|
||||
fillUpForSeller(aliceError, aliceNode.info.legalIdentity,
|
||||
1200.DOLLARS `issued by` issuer, null, notaryNode.info.notaryIdentity).second
|
||||
}
|
||||
|
||||
insertFakeTransactions(bobsBadCash, bobNode, notaryNode, bobKey)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey)
|
||||
insertFakeTransactions(bobsBadCash, bobNode, notaryNode, DUMMY_CASH_ISSUER_KEY.public, MEGA_CORP_PUBKEY)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, MEGA_CORP_PUBKEY)
|
||||
|
||||
net.runNetwork() // Clear network map registration messages
|
||||
|
||||
@ -563,8 +554,25 @@ class TwoPartyTradeFlowTests {
|
||||
wtxToSign: List<WireTransaction>,
|
||||
node: AbstractNode,
|
||||
notaryNode: MockNetwork.MockNode,
|
||||
vararg extraKeys: KeyPair): Map<SecureHash, SignedTransaction> {
|
||||
val signed: List<SignedTransaction> = signAll(wtxToSign, extraKeys.toList() + notaryNode.services.notaryIdentityKey + DUMMY_CASH_ISSUER_KEY)
|
||||
vararg extraKeys: PublicKey): Map<SecureHash, SignedTransaction> {
|
||||
|
||||
val signed = wtxToSign.map {
|
||||
val bits = it.serialize()
|
||||
val id = it.id
|
||||
val sigs = mutableListOf<DigitalSignature.WithKey>()
|
||||
sigs.add(node.services.keyManagementService.sign(id.bytes, node.services.legalIdentityKey))
|
||||
sigs.add(notaryNode.services.keyManagementService.sign(id.bytes, notaryNode.services.notaryIdentityKey))
|
||||
for (extraKey in extraKeys) {
|
||||
if (extraKey == DUMMY_CASH_ISSUER_KEY.public) {
|
||||
sigs.add(DUMMY_CASH_ISSUER_KEY.sign(id.bytes))
|
||||
} else if (extraKey == MEGA_CORP_PUBKEY) {
|
||||
sigs.add(MEGA_CORP_KEY.sign(id.bytes))
|
||||
} else {
|
||||
sigs.add(node.services.keyManagementService.sign(id.bytes, extraKey))
|
||||
}
|
||||
}
|
||||
SignedTransaction(bits, sigs)
|
||||
}
|
||||
return node.database.transaction {
|
||||
node.services.recordTransactions(signed)
|
||||
val validatedTransactions = node.services.storageService.validatedTransactions
|
||||
|
@ -133,9 +133,7 @@ class NotaryChangeTests {
|
||||
addOutputState(stateC, notary)
|
||||
addOutputState(stateB, notary, encumbrance = 1) // Encumbered by stateC
|
||||
}
|
||||
val nodeKey = node.services.legalIdentityKey
|
||||
tx.signWith(nodeKey)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val stx = node.services.signInitialTransaction(tx)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
return tx.toWireTransaction()
|
||||
}
|
||||
@ -151,11 +149,8 @@ class NotaryChangeTests {
|
||||
|
||||
fun issueState(node: AbstractNode, notaryNode: AbstractNode): StateAndRef<*> {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
||||
val nodeKey = node.services.legalIdentityKey
|
||||
tx.signWith(nodeKey)
|
||||
val notaryKeyPair = notaryNode.services.notaryIdentityKey
|
||||
tx.signWith(notaryKeyPair)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val signedByNode = node.services.signInitialTransaction(tx)
|
||||
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||
}
|
||||
@ -164,13 +159,9 @@ fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode, notaryNode: A
|
||||
val state = TransactionState(DummyContract.MultiOwnerState(0,
|
||||
listOf(nodeA.info.legalIdentity, nodeB.info.legalIdentity)), notaryNode.info.notaryIdentity)
|
||||
val tx = TransactionType.NotaryChange.Builder(notaryNode.info.notaryIdentity).withItems(state)
|
||||
val nodeAKey = nodeA.services.legalIdentityKey
|
||||
val nodeBKey = nodeB.services.legalIdentityKey
|
||||
tx.signWith(nodeAKey)
|
||||
tx.signWith(nodeBKey)
|
||||
val notaryKeyPair = notaryNode.services.notaryIdentityKey
|
||||
tx.signWith(notaryKeyPair)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val signedByA = nodeA.services.signInitialTransaction(tx)
|
||||
val signedByAB = nodeB.services.addSignature(signedByA)
|
||||
val stx = notaryNode.services.addSignature(signedByAB, notaryNode.services.notaryIdentityKey)
|
||||
nodeA.services.recordTransactions(listOf(stx))
|
||||
nodeB.services.recordTransactions(listOf(stx))
|
||||
val stateAndRef = StateAndRef(state, StateRef(stx.id, 0))
|
||||
@ -180,9 +171,7 @@ fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode, notaryNode: A
|
||||
fun issueInvalidState(node: AbstractNode, notary: Party): StateAndRef<*> {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0))
|
||||
tx.setTime(Instant.now(), 30.seconds)
|
||||
val nodeKey = node.services.legalIdentityKey
|
||||
tx.signWith(nodeKey)
|
||||
val stx = tx.toSignedTransaction(false)
|
||||
val stx = node.services.signInitialTransaction(tx)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||
}
|
||||
|
@ -271,11 +271,11 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
apply {
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val state = TestState(FlowLogicRefFactoryImpl.createForRPC(TestFlowLogic::class.java, increment), instant)
|
||||
val usefulTX = TransactionType.General.Builder(null).apply {
|
||||
val builder = TransactionType.General.Builder(null).apply {
|
||||
addOutputState(state, DUMMY_NOTARY)
|
||||
addCommand(Command(), freshKey.public)
|
||||
signWith(freshKey)
|
||||
}.toSignedTransaction()
|
||||
addCommand(Command(), freshKey)
|
||||
}
|
||||
val usefulTX = services.signInitialTransaction(builder, freshKey)
|
||||
val txHash = usefulTX.id
|
||||
|
||||
services.recordTransactions(usefulTX)
|
||||
|
@ -62,8 +62,8 @@ class ScheduledFlowTests {
|
||||
|
||||
val notary = serviceHub.networkMapCache.getAnyNotary()
|
||||
val builder = TransactionType.General.Builder(notary)
|
||||
val tx = builder.withItems(scheduledState).
|
||||
signWith(serviceHub.legalIdentityKey).toSignedTransaction(false)
|
||||
builder.withItems(scheduledState)
|
||||
val tx = serviceHub.signInitialTransaction(builder)
|
||||
subFlow(FinalityFlow(tx, setOf(serviceHub.myInfo.legalIdentity)))
|
||||
}
|
||||
}
|
||||
@ -82,8 +82,8 @@ class ScheduledFlowTests {
|
||||
val notary = state.state.notary
|
||||
val newStateOutput = scheduledState.copy(processed = true)
|
||||
val builder = TransactionType.General.Builder(notary)
|
||||
val tx = builder.withItems(state, newStateOutput).
|
||||
signWith(serviceHub.legalIdentityKey).toSignedTransaction(false)
|
||||
builder.withItems(state, newStateOutput)
|
||||
val tx = serviceHub.signInitialTransaction(builder)
|
||||
subFlow(FinalityFlow(tx, setOf(scheduledState.source, scheduledState.destination)))
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
|
||||
}
|
||||
val expires = Instant.now() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
|
||||
val nodeRegistration = NodeRegistration(info, distinctSerial, addOrRemove, expires)
|
||||
val request = RegistrationRequest(nodeRegistration.toWire(services.legalIdentityKey.private), info.address)
|
||||
val request = RegistrationRequest(nodeRegistration.toWire(services.keyManagementService, services.legalIdentityKey), info.address)
|
||||
val response = services.networkService.sendRequest<RegistrationResponse>(REGISTER_TOPIC, request, mapServiceNode.info.address)
|
||||
network.runNetwork()
|
||||
return response
|
||||
|
@ -46,9 +46,7 @@ class DataVendingServiceTests {
|
||||
Cash().generateIssue(ptx, Amount(100, Issued(deposit, USD)), beneficiary, DUMMY_NOTARY)
|
||||
|
||||
// Complete the cash transaction, and then manually relay it
|
||||
val registerKey = registerNode.services.legalIdentityKey
|
||||
ptx.signWith(registerKey)
|
||||
val tx = ptx.toSignedTransaction()
|
||||
val tx = registerNode.services.signInitialTransaction(ptx)
|
||||
vaultServiceNode.database.transaction {
|
||||
assertThat(vaultServiceNode.services.vaultService.unconsumedStates<Cash.State>()).isEmpty()
|
||||
|
||||
@ -76,9 +74,7 @@ class DataVendingServiceTests {
|
||||
Cash().generateIssue(ptx, Amount(100, Issued(deposit, USD)), beneficiary, DUMMY_NOTARY)
|
||||
|
||||
// The transaction tries issuing MEGA_CORP cash, but we aren't the issuer, so it's invalid
|
||||
val registerKey = registerNode.services.legalIdentityKey
|
||||
ptx.signWith(registerKey)
|
||||
val tx = ptx.toSignedTransaction(false)
|
||||
val tx = registerNode.services.signInitialTransaction(ptx)
|
||||
vaultServiceNode.database.transaction {
|
||||
assertThat(vaultServiceNode.services.vaultService.unconsumedStates<Cash.State>()).isEmpty()
|
||||
|
||||
|
@ -560,8 +560,7 @@ class FlowFrameworkTests {
|
||||
fun `wait for transaction`() {
|
||||
val ptx = TransactionBuilder(notary = notary1.info.notaryIdentity)
|
||||
ptx.addOutputState(DummyState())
|
||||
ptx.signWith(node1.services.legalIdentityKey)
|
||||
val stx = ptx.toSignedTransaction()
|
||||
val stx = node1.services.signInitialTransaction(ptx)
|
||||
|
||||
val committerFiber = node1
|
||||
.initiateSingleShotFlow(WaitingFlows.Waiter::class) { WaitingFlows.Committer(it) }
|
||||
@ -575,8 +574,7 @@ class FlowFrameworkTests {
|
||||
fun `committer throws exception before calling the finality flow`() {
|
||||
val ptx = TransactionBuilder(notary = notary1.info.notaryIdentity)
|
||||
ptx.addOutputState(DummyState())
|
||||
ptx.signWith(node1.services.legalIdentityKey)
|
||||
val stx = ptx.toSignedTransaction()
|
||||
val stx = node1.services.signInitialTransaction(ptx)
|
||||
|
||||
node1.registerServiceFlow(WaitingFlows.Waiter::class) {
|
||||
WaitingFlows.Committer(it) { throw Exception("Error") }
|
||||
|
@ -6,7 +6,6 @@ import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.seconds
|
||||
@ -21,7 +20,6 @@ import net.corda.testing.node.MockNetwork
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
@ -31,7 +29,6 @@ class NotaryServiceTests {
|
||||
lateinit var net: MockNetwork
|
||||
lateinit var notaryNode: MockNetwork.MockNode
|
||||
lateinit var clientNode: MockNetwork.MockNode
|
||||
lateinit var clientKeyPair: KeyPair
|
||||
|
||||
@Before fun setup() {
|
||||
net = MockNetwork()
|
||||
@ -39,7 +36,6 @@ class NotaryServiceTests {
|
||||
legalName = DUMMY_NOTARY.name,
|
||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)))
|
||||
clientNode = net.createNode(networkMapAddress = notaryNode.info.address)
|
||||
clientKeyPair = clientNode.keyManagement.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single())
|
||||
net.runNetwork() // Clear network map registration messages
|
||||
}
|
||||
|
||||
@ -48,8 +44,7 @@ class NotaryServiceTests {
|
||||
val inputState = issueState(clientNode)
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
tx.setTime(Instant.now(), 30.seconds)
|
||||
tx.signWith(clientKeyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val future = runNotaryClient(stx)
|
||||
@ -61,8 +56,7 @@ class NotaryServiceTests {
|
||||
val stx = run {
|
||||
val inputState = issueState(clientNode)
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
tx.signWith(clientKeyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val future = runNotaryClient(stx)
|
||||
@ -75,8 +69,7 @@ class NotaryServiceTests {
|
||||
val inputState = issueState(clientNode)
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
tx.setTime(Instant.now().plusSeconds(3600), 30.seconds)
|
||||
tx.signWith(clientKeyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val future = runNotaryClient(stx)
|
||||
@ -89,8 +82,7 @@ class NotaryServiceTests {
|
||||
val stx = run {
|
||||
val inputState = issueState(clientNode)
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
tx.signWith(clientKeyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val firstAttempt = NotaryFlow.Client(stx)
|
||||
@ -107,14 +99,12 @@ class NotaryServiceTests {
|
||||
val inputState = issueState(clientNode)
|
||||
val stx = run {
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
tx.signWith(clientKeyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
val stx2 = run {
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
tx.addInputState(issueState(clientNode))
|
||||
tx.signWith(clientKeyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val firstSpend = NotaryFlow.Client(stx)
|
||||
@ -139,11 +129,8 @@ class NotaryServiceTests {
|
||||
|
||||
fun issueState(node: AbstractNode): StateAndRef<*> {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
||||
val nodeKey = node.services.legalIdentityKey
|
||||
tx.signWith(nodeKey)
|
||||
val notaryKeyPair = notaryNode.services.notaryIdentityKey
|
||||
tx.signWith(notaryKeyPair)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val signedByNode = node.services.signInitialTransaction(tx)
|
||||
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package net.corda.node.services.transactions
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -42,9 +41,7 @@ class ValidatingNotaryServiceTests {
|
||||
val stx = run {
|
||||
val inputState = issueInvalidState(clientNode, notaryNode.info.notaryIdentity)
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||
val keyPair = clientNode.services.keyManagementService.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single())
|
||||
tx.signWith(keyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val future = runClient(stx)
|
||||
@ -60,9 +57,7 @@ class ValidatingNotaryServiceTests {
|
||||
|
||||
val command = Command(DummyContract.Commands.Move(), expectedMissingKey)
|
||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState, command)
|
||||
val keyPair = clientNode.services.keyManagementService.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single())
|
||||
tx.signWith(keyPair)
|
||||
tx.toSignedTransaction(false)
|
||||
clientNode.services.signInitialTransaction(tx)
|
||||
}
|
||||
|
||||
val ex = assertFailsWith(NotaryException::class) {
|
||||
@ -85,11 +80,8 @@ class ValidatingNotaryServiceTests {
|
||||
|
||||
fun issueState(node: AbstractNode): StateAndRef<*> {
|
||||
val tx = DummyContract.generateInitial(Random().nextInt(), notaryNode.info.notaryIdentity, node.info.legalIdentity.ref(0))
|
||||
val nodeKey = node.services.legalIdentityKey
|
||||
tx.signWith(nodeKey)
|
||||
val notaryKeyPair = notaryNode.services.notaryIdentityKey
|
||||
tx.signWith(notaryKeyPair)
|
||||
val stx = tx.toSignedTransaction()
|
||||
val signedByNode = node.services.signInitialTransaction(tx)
|
||||
val stx = notaryNode.services.addSignature(signedByNode, notaryNode.services.notaryIdentityKey)
|
||||
node.services.recordTransactions(listOf(stx))
|
||||
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ class NodeVaultServiceTest {
|
||||
fun addNoteToTransaction() {
|
||||
database.transaction {
|
||||
|
||||
val freshKey = services.legalIdentityKey.public
|
||||
val freshKey = services.legalIdentityKey
|
||||
|
||||
// Issue a txn to Send us some Money
|
||||
val usefulTX = TransactionType.General.Builder(null).apply {
|
||||
|
@ -91,9 +91,8 @@ class VaultWithCashTest {
|
||||
database.transaction {
|
||||
// A tx that sends us money.
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
val usefulTX = TransactionType.General.Builder(null).apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), AnonymousParty(freshPublicKey), DUMMY_NOTARY)
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), AnonymousParty(freshKey), DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
|
||||
@ -101,11 +100,11 @@ class VaultWithCashTest {
|
||||
services.recordTransactions(usefulTX)
|
||||
|
||||
// A tx that spends our money.
|
||||
val spendTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
val spendTXBuilder = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 80.DOLLARS, BOB)
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val spendTX = services.signInitialTransaction(spendTXBuilder, freshKey)
|
||||
|
||||
assertEquals(100.DOLLARS, vault.cashBalances[USD])
|
||||
|
||||
@ -129,14 +128,13 @@ class VaultWithCashTest {
|
||||
@Test
|
||||
fun `issue and attempt double spend`() {
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
|
||||
database.transaction {
|
||||
// A tx that sends us money.
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 10, 10, Random(0L),
|
||||
issuedBy = MEGA_CORP.ref(1),
|
||||
issuerKey = MEGA_CORP_KEY,
|
||||
ownedBy = AnonymousParty(freshPublicKey))
|
||||
ownedBy = AnonymousParty(freshKey))
|
||||
println("Cash balance: ${vault.cashBalances[USD]}")
|
||||
|
||||
assertThat(vault.unconsumedStates<Cash.State>()).hasSize(10)
|
||||
@ -149,12 +147,12 @@ class VaultWithCashTest {
|
||||
backgroundExecutor.submit {
|
||||
database.transaction {
|
||||
try {
|
||||
val txn1 =
|
||||
val txn1Builder =
|
||||
TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 60.DOLLARS, BOB)
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val txn1 = services.signInitialTransaction(txn1Builder, freshKey)
|
||||
println("txn1: ${txn1.id} spent ${((txn1.tx.outputs[0].data) as Cash.State).amount}")
|
||||
println("""txn1 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
@ -181,12 +179,12 @@ class VaultWithCashTest {
|
||||
backgroundExecutor.submit {
|
||||
database.transaction {
|
||||
try {
|
||||
val txn2 =
|
||||
val txn2Builder =
|
||||
TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 80.DOLLARS, BOB)
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val txn2 = services.signInitialTransaction(txn2Builder, freshKey)
|
||||
println("txn2: ${txn2.id} spent ${((txn2.tx.outputs[0].data) as Cash.State).amount}")
|
||||
println("""txn2 states:
|
||||
UNCONSUMED: ${vault.unconsumedStates<Cash.State>().count()} : ${vault.unconsumedStates<Cash.State>()},
|
||||
@ -221,17 +219,16 @@ class VaultWithCashTest {
|
||||
fun `branching LinearStates fails to verify`() {
|
||||
database.transaction {
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
val freshIdentity = AnonymousParty(freshPublicKey)
|
||||
val freshIdentity = AnonymousParty(freshKey)
|
||||
val linearId = UniqueIdentifier()
|
||||
|
||||
// Issue a linear state
|
||||
val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
val dummyIssueBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val dummyIssue = services.signInitialTransaction(dummyIssueBuilder)
|
||||
|
||||
assertThatThrownBy {
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
@ -243,17 +240,16 @@ class VaultWithCashTest {
|
||||
fun `sequencing LinearStates works`() {
|
||||
database.transaction {
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
val freshIdentity = AnonymousParty(freshPublicKey)
|
||||
val freshIdentity = AnonymousParty(freshKey)
|
||||
|
||||
val linearId = UniqueIdentifier()
|
||||
|
||||
// Issue a linear state
|
||||
val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
val dummyIssueBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply {
|
||||
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val dummyIssue = services.signInitialTransaction(dummyIssueBuilder, services.legalIdentityKey)
|
||||
|
||||
dummyIssue.toLedgerTransaction(services).verify()
|
||||
|
||||
@ -278,9 +274,8 @@ class VaultWithCashTest {
|
||||
fun `spending cash in vault of mixed state types works`() {
|
||||
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
database.transaction {
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L), ownedBy = AnonymousParty(freshPublicKey))
|
||||
services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L), ownedBy = AnonymousParty(freshKey))
|
||||
services.fillWithSomeTestCash(100.SWISS_FRANCS, DUMMY_NOTARY, 2, 2, Random(0L))
|
||||
services.fillWithSomeTestCash(100.POUNDS, DUMMY_NOTARY, 1, 1, Random(0L))
|
||||
val cash = vault.unconsumedStates<Cash.State>()
|
||||
@ -293,11 +288,11 @@ class VaultWithCashTest {
|
||||
|
||||
database.transaction {
|
||||
// A tx that spends our money.
|
||||
val spendTX = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
val spendTXBuilder = TransactionType.General.Builder(DUMMY_NOTARY).apply {
|
||||
vault.generateSpend(this, 80.DOLLARS, BOB)
|
||||
signWith(freshKey)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction()
|
||||
}
|
||||
val spendTX = services.signInitialTransaction(spendTXBuilder, freshKey)
|
||||
services.recordTransactions(spendTX)
|
||||
|
||||
val consumedStates = vault.consumedStates<ContractState>()
|
||||
@ -312,8 +307,7 @@ class VaultWithCashTest {
|
||||
fun `consuming multiple contract state types in same transaction`() {
|
||||
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val freshPublicKey = freshKey.public
|
||||
val freshIdentity = AnonymousParty(freshPublicKey)
|
||||
val freshIdentity = AnonymousParty(freshKey)
|
||||
database.transaction {
|
||||
|
||||
services.fillWithSomeTestDeals(listOf("123", "456", "789"))
|
||||
|
@ -15,6 +15,7 @@ import net.corda.core.math.Interpolator
|
||||
import net.corda.core.math.InterpolatorFactory
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.PluginServiceHub
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.FilteredTransaction
|
||||
@ -32,6 +33,8 @@ import java.io.InputStream
|
||||
import java.math.BigDecimal
|
||||
import java.security.KeyPair
|
||||
import java.time.Clock
|
||||
import java.security.PublicKey
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
@ -68,8 +71,8 @@ object NodeInterestRates {
|
||||
val oracle: Oracle by lazy {
|
||||
val myNodeInfo = services.myInfo
|
||||
val myIdentity = myNodeInfo.serviceIdentities(type).first()
|
||||
val mySigningKey = services.keyManagementService.toKeyPair(myIdentity.owningKey.keys)
|
||||
Oracle(myIdentity, mySigningKey, services.clock)
|
||||
val mySigningKey = myIdentity.owningKey.keys.first { services.keyManagementService.keys.contains(it) }
|
||||
Oracle(myIdentity, mySigningKey, services)
|
||||
}
|
||||
|
||||
init {
|
||||
@ -129,7 +132,7 @@ object NodeInterestRates {
|
||||
* The oracle will try to interpolate the missing value of a tenor for the given fix name and date.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class Oracle(val identity: Party, private val signingKey: KeyPair, val clock: Clock) {
|
||||
class Oracle(val identity: Party, private val signingKey: PublicKey, val services: ServiceHub) {
|
||||
private object Table : JDBCHashedTable("demo_interest_rate_fixes") {
|
||||
val name = varchar("index_name", length = 255)
|
||||
val forDay = localDate("for_day")
|
||||
@ -168,7 +171,7 @@ object NodeInterestRates {
|
||||
|
||||
// Make this the last bit of initialisation logic so fully constructed when entered into instances map
|
||||
init {
|
||||
require(signingKey.public in identity.owningKey.keys)
|
||||
require(signingKey in identity.owningKey.keys)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,7 +182,7 @@ object NodeInterestRates {
|
||||
@Suspendable
|
||||
fun query(queries: List<FixOf>, deadline: Instant): List<Fix> {
|
||||
require(queries.isNotEmpty())
|
||||
return mutex.readWithDeadline(clock, deadline) {
|
||||
return mutex.readWithDeadline(services.clock, deadline) {
|
||||
val answers: List<Fix?> = queries.map { container[it] }
|
||||
val firstNull = answers.indexOf(null)
|
||||
if (firstNull != -1) {
|
||||
@ -225,7 +228,8 @@ object NodeInterestRates {
|
||||
// Note that we will happily sign an invalid transaction, as we are only being presented with a filtered
|
||||
// version so we can't resolve or check it ourselves. However, that doesn't matter much, as if we sign
|
||||
// an invalid transaction the signature is worthless.
|
||||
return signingKey.sign(ftx.rootHash.bytes, identity)
|
||||
val signature = services.keyManagementService.sign(ftx.rootHash.bytes, signingKey)
|
||||
return DigitalSignature.LegallyIdentifiable(identity, signature.bytes)
|
||||
}
|
||||
// DOCEND 1
|
||||
}
|
||||
|
@ -2,10 +2,10 @@ package net.corda.irs.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.DealState
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.PluginServiceHub
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
|
@ -3,7 +3,6 @@ package net.corda.irs.flows
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.TransientProperty
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.toBase58String
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
@ -20,7 +19,6 @@ import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.flows.TwoPartyDealFlow
|
||||
import java.math.BigDecimal
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
|
||||
object FixingFlow {
|
||||
@ -115,10 +113,9 @@ object FixingFlow {
|
||||
StateAndRef(state, payload.ref)
|
||||
}
|
||||
|
||||
override val myKeyPair: KeyPair get() {
|
||||
val myPublicKey = serviceHub.myInfo.legalIdentity.owningKey
|
||||
val myKeys = dealToFix.state.data.parties.single { it.owningKey == myPublicKey }.owningKey.keys
|
||||
return serviceHub.keyManagementService.toKeyPair(myKeys)
|
||||
override val myKey: PublicKey get() {
|
||||
dealToFix.state.data.parties.single { it.owningKey == serviceHub.myInfo.legalIdentity.owningKey }
|
||||
return serviceHub.legalIdentityKey
|
||||
}
|
||||
|
||||
override val notaryNode: NodeInfo get() {
|
||||
|
@ -13,6 +13,7 @@ import net.corda.core.flatMap
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowStateMachine
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.map
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
@ -27,7 +28,7 @@ import net.corda.node.utilities.transaction
|
||||
import net.corda.testing.initiateSingleShotFlow
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||
import net.corda.testing.node.MockIdentityService
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
|
||||
@ -127,9 +128,9 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
@InitiatingFlow
|
||||
class StartDealFlow(val otherParty: Party,
|
||||
val payload: AutoOffer,
|
||||
val myKeyPair: KeyPair) : FlowLogic<SignedTransaction>() {
|
||||
val myKey: PublicKey) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction = subFlow(Instigator(otherParty, payload, myKeyPair))
|
||||
override fun call(): SignedTransaction = subFlow(Instigator(otherParty, payload, myKey))
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -7,10 +7,9 @@ import net.corda.contracts.asset.`owned by`
|
||||
import net.corda.core.bd
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.MerkleTreeException
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.ALICE
|
||||
@ -25,6 +24,7 @@ import net.corda.testing.ALICE_PUBKEY
|
||||
import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_KEY
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
@ -34,7 +34,6 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.Closeable
|
||||
import java.math.BigDecimal
|
||||
import java.time.Clock
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
@ -52,7 +51,8 @@ class NodeInterestRatesTest {
|
||||
val DUMMY_CASH_ISSUER_KEY = generateKeyPair()
|
||||
val DUMMY_CASH_ISSUER = Party(X500Name("CN=Cash issuer,O=R3,OU=corda,L=London,C=UK"), DUMMY_CASH_ISSUER_KEY.public)
|
||||
|
||||
val clock = Clock.systemUTC()
|
||||
val dummyServices = MockServices(DUMMY_CASH_ISSUER_KEY, MEGA_CORP_KEY)
|
||||
val clock get() = dummyServices.clock
|
||||
lateinit var oracle: NodeInterestRates.Oracle
|
||||
lateinit var dataSource: Closeable
|
||||
lateinit var database: Database
|
||||
@ -72,7 +72,7 @@ class NodeInterestRatesTest {
|
||||
dataSource = dataSourceAndDatabase.first
|
||||
database = dataSourceAndDatabase.second
|
||||
database.transaction {
|
||||
oracle = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY, clock).apply { knownFixes = TEST_DATA }
|
||||
oracle = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY.public, dummyServices).apply { knownFixes = TEST_DATA }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,18 +13,16 @@ class DummyIssueAndMove(private val notary: Party, private val counterpartyNode:
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
val random = Random()
|
||||
val myKeyPair = serviceHub.legalIdentityKey
|
||||
// Self issue an asset
|
||||
val issueTx = DummyContract.generateInitial(random.nextInt(), notary, serviceHub.myInfo.legalIdentity.ref(0)).apply {
|
||||
signWith(myKeyPair)
|
||||
}
|
||||
serviceHub.recordTransactions(issueTx.toSignedTransaction())
|
||||
val issueTxBuilder = DummyContract.generateInitial(random.nextInt(), notary, serviceHub.myInfo.legalIdentity.ref(0))
|
||||
val issueTx = serviceHub.signInitialTransaction(issueTxBuilder)
|
||||
serviceHub.recordTransactions(issueTx)
|
||||
// Move ownership of the asset to the counterparty
|
||||
val asset = issueTx.toWireTransaction().outRef<DummyContract.SingleOwnerState>(0)
|
||||
val moveTx = DummyContract.move(asset, counterpartyNode).apply {
|
||||
signWith(myKeyPair)
|
||||
}
|
||||
val counterPartyKey = counterpartyNode.owningKey
|
||||
val asset = issueTx.tx.outRef<DummyContract.SingleOwnerState>(0)
|
||||
val moveTxBuilder = DummyContract.move(asset, counterpartyNode)
|
||||
val moveTx = serviceHub.signInitialTransaction(moveTxBuilder)
|
||||
// We don't check signatures because we know that the notary's signature is missing
|
||||
return moveTx.toSignedTransaction(checkSufficientSignatures = false)
|
||||
return moveTx
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,8 @@ object StateRevisionFlow {
|
||||
val state = originalState.state.data
|
||||
val tx = state.generateRevision(originalState.state.notary, originalState, modification)
|
||||
tx.setTime(serviceHub.clock.instant(), 30.seconds)
|
||||
tx.signWith(serviceHub.legalIdentityKey)
|
||||
|
||||
val stx = tx.toSignedTransaction(false)
|
||||
val stx = serviceHub.signInitialTransaction(tx)
|
||||
return Pair(stx, state.participants)
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,13 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.contracts.CommercialPaper
|
||||
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.days
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.seconds
|
||||
|
@ -47,7 +47,11 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
* A singleton utility that only provides a mock identity, key and storage service. However, this is sufficient for
|
||||
* building chains of transactions and verifying them. It isn't sufficient for testing flows however.
|
||||
*/
|
||||
open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
|
||||
open class MockServices(vararg val keys: KeyPair) : ServiceHub {
|
||||
constructor() : this(generateKeyPair())
|
||||
|
||||
val key: KeyPair get() = keys.first()
|
||||
|
||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) {
|
||||
txs.forEach {
|
||||
storageService.stateMachineRecordedTransactionMapping.addMapping(StateMachineRunId.createRandom(), it.id)
|
||||
@ -59,7 +63,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
|
||||
|
||||
override val storageService: TxWritableStorageService = MockStorageService()
|
||||
override val identityService: MockIdentityService = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
||||
override val keyManagementService: MockKeyManagementService = MockKeyManagementService(key)
|
||||
override val keyManagementService: KeyManagementService = MockKeyManagementService(*keys)
|
||||
|
||||
override val vaultService: VaultService get() = throw UnsupportedOperationException()
|
||||
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
|
||||
@ -106,14 +110,27 @@ class MockIdentityService(val identities: List<Party>,
|
||||
|
||||
|
||||
class MockKeyManagementService(vararg initialKeys: KeyPair) : SingletonSerializeAsToken(), KeyManagementService {
|
||||
override val keys: MutableMap<PublicKey, PrivateKey> = initialKeys.associateByTo(HashMap(), { it.public }, { it.private })
|
||||
private val keyStore: MutableMap<PublicKey, PrivateKey> = initialKeys.associateByTo(HashMap(), { it.public }, { it.private })
|
||||
|
||||
override val keys: Set<PublicKey> get() = keyStore.keys
|
||||
|
||||
val nextKeys = LinkedList<KeyPair>()
|
||||
|
||||
override fun freshKey(): KeyPair {
|
||||
override fun freshKey(): PublicKey {
|
||||
val k = nextKeys.poll() ?: generateKeyPair()
|
||||
keys[k.public] = k.private
|
||||
return k
|
||||
keyStore[k.public] = k.private
|
||||
return k.public
|
||||
}
|
||||
|
||||
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
|
||||
val pk = publicKey.keys.first { keyStore.containsKey(it) }
|
||||
return KeyPair(pk, keyStore[pk]!!)
|
||||
}
|
||||
|
||||
override fun sign(bytes: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey {
|
||||
val keyPair = getSigningKeyPair(publicKey)
|
||||
val signature = keyPair.sign(bytes)
|
||||
return signature
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,18 +6,19 @@ import com.google.common.util.concurrent.SettableFuture
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.testing.MOCK_VERSION_INFO
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.node.services.RPCUserServiceImpl
|
||||
import net.corda.node.services.api.MonitoringService
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.keys.E2ETestKeyManagementService
|
||||
import net.corda.node.services.messaging.ArtemisMessagingServer
|
||||
import net.corda.node.services.messaging.NodeMessagingClient
|
||||
import net.corda.node.services.network.InMemoryNetworkMapCache
|
||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.node.utilities.transaction
|
||||
import net.corda.testing.MOCK_VERSION_INFO
|
||||
import net.corda.testing.freeLocalHostAndPort
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import java.io.Closeable
|
||||
import java.security.KeyPair
|
||||
@ -34,6 +35,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL
|
||||
val userService = RPCUserServiceImpl(config.rpcUsers)
|
||||
val monitoringService = MonitoringService(MetricRegistry())
|
||||
val identity: KeyPair = generateKeyPair()
|
||||
val keyService: KeyManagementService = E2ETestKeyManagementService(setOf(identity))
|
||||
val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1)
|
||||
val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService)
|
||||
val networkMapRegistrationFuture: SettableFuture<Unit> = SettableFuture.create<Unit>()
|
||||
|
Loading…
x
Reference in New Issue
Block a user