mirror of
https://github.com/corda/corda.git
synced 2024-12-19 21:17:58 +00:00
First cut at removing PrivateKey leakage from KeyManagementService
Fixup after rebase Restore original key property names Fixup after rebase Undo extra import that IntelliJ keeps erroneously adding. Add comments and fix docs for transaction signing. Fixes after rebase More fixes after rebase Address PR requests Address PR requests
This commit is contained in:
parent
ccbe76eb84
commit
05a97b11f3
@ -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…
Reference in New Issue
Block a user