mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
Adding createSignature(filteredTransaction) to serviceHub (#1380)
This commit is contained in:
committed by
GitHub
parent
485c2feb83
commit
62c64ace23
@ -7,6 +7,7 @@ import net.corda.core.crypto.SignatureMetadata
|
|||||||
import net.corda.core.crypto.TransactionSignature
|
import net.corda.core.crypto.TransactionSignature
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
import net.corda.core.serialization.SerializeAsToken
|
import net.corda.core.serialization.SerializeAsToken
|
||||||
|
import net.corda.core.transactions.FilteredTransaction
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
@ -171,7 +172,7 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to construct an initial partially signed transaction from a TransactionBuilder
|
* Helper method to construct an initial partially signed transaction from a TransactionBuilder
|
||||||
* using the default identity key contained in the node. The legal Indentity key is used to sign.
|
* using the default identity key contained in the node. The legal identity key is used to sign.
|
||||||
* @param builder The TransactionBuilder to seal with the node's signature.
|
* @param builder The TransactionBuilder to seal with the node's signature.
|
||||||
* Any existing signatures on the builder will be preserved.
|
* Any existing signatures on the builder will be preserved.
|
||||||
* @return Returns a SignedTransaction with the new node signature attached.
|
* @return Returns a SignedTransaction with the new node signature attached.
|
||||||
@ -203,7 +204,9 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to create an additional signature for an existing (partially) [SignedTransaction].
|
* Helper method to create an additional signature for an existing (partially) [SignedTransaction]. Additional
|
||||||
|
* [SignatureMetadata], including the
|
||||||
|
* platform version used during signing and the cryptographic signature scheme use, is added to the signature.
|
||||||
* @param signedTransaction The [SignedTransaction] to which the signature will apply.
|
* @param signedTransaction The [SignedTransaction] to which the signature will apply.
|
||||||
* @param publicKey The [PublicKey] matching to a signing [java.security.PrivateKey] hosted in the node.
|
* @param publicKey The [PublicKey] matching to a signing [java.security.PrivateKey] hosted in the node.
|
||||||
* If the [PublicKey] is actually a [net.corda.core.crypto.CompositeKey] the first leaf key found locally will be used
|
* If the [PublicKey] is actually a [net.corda.core.crypto.CompositeKey] the first leaf key found locally will be used
|
||||||
@ -214,10 +217,12 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
createSignature(signedTransaction, publicKey, SignatureMetadata(myInfo.platformVersion, Crypto.findSignatureScheme(publicKey).schemeNumberID))
|
createSignature(signedTransaction, publicKey, SignatureMetadata(myInfo.platformVersion, Crypto.findSignatureScheme(publicKey).schemeNumberID))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to create an additional signature for an existing (partially) [SignedTransaction]
|
* Helper method to create a signature for an existing (partially) [SignedTransaction]
|
||||||
* using the default identity signing key of the node. The legal identity key is used to sign.
|
* using the default identity signing key of the node. The legal identity key is used to sign. Additional
|
||||||
|
* [SignatureMetadata], including the
|
||||||
|
* platform version used during signing and the cryptographic signature scheme use, is added to the signature.
|
||||||
* @param signedTransaction The SignedTransaction to which the signature will apply.
|
* @param signedTransaction The SignedTransaction to which the signature will apply.
|
||||||
* @return The DigitalSignature.WithKey generated by signing with the internally held identity PrivateKey.
|
* @return the TransactionSignature generated by signing with the internally held identity PrivateKey.
|
||||||
*/
|
*/
|
||||||
fun createSignature(signedTransaction: SignedTransaction): TransactionSignature {
|
fun createSignature(signedTransaction: SignedTransaction): TransactionSignature {
|
||||||
return createSignature(signedTransaction, legalIdentityKey)
|
return createSignature(signedTransaction, legalIdentityKey)
|
||||||
@ -243,6 +248,36 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
*/
|
*/
|
||||||
fun addSignature(signedTransaction: SignedTransaction): SignedTransaction = addSignature(signedTransaction, legalIdentityKey)
|
fun addSignature(signedTransaction: SignedTransaction): SignedTransaction = addSignature(signedTransaction, legalIdentityKey)
|
||||||
|
|
||||||
|
// Helper method to create a signature for a FilteredTransaction.
|
||||||
|
private fun createSignature(filteredTransaction: FilteredTransaction, publicKey: PublicKey, signatureMetadata: SignatureMetadata): TransactionSignature {
|
||||||
|
val signableData = SignableData(filteredTransaction.id, signatureMetadata)
|
||||||
|
return keyManagementService.sign(signableData, publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to create a signature for a FilteredTransaction. Additional [SignatureMetadata], including the
|
||||||
|
* platform version used during signing and the cryptographic signature scheme use, is added to the signature.
|
||||||
|
* @param filteredTransaction the [FilteredTransaction] to which the signature will apply.
|
||||||
|
* @param publicKey The [PublicKey] matching to a signing [java.security.PrivateKey] hosted in the node.
|
||||||
|
* If the [PublicKey] is actually a [net.corda.core.crypto.CompositeKey] the first leaf key found locally will be used
|
||||||
|
* for signing.
|
||||||
|
* @return The [TransactionSignature] generated by signing with the internally held [java.security.PrivateKey].
|
||||||
|
*/
|
||||||
|
fun createSignature(filteredTransaction: FilteredTransaction, publicKey: PublicKey) =
|
||||||
|
createSignature(filteredTransaction, publicKey, SignatureMetadata(myInfo.platformVersion, Crypto.findSignatureScheme(publicKey).schemeNumberID))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to create a signature for a FilteredTransaction
|
||||||
|
* using the default identity signing key of the node. The legal identity key is used to sign. Additional
|
||||||
|
* [SignatureMetadata], including the platform version used during signing and the cryptographic signature scheme use,
|
||||||
|
* is added to the signature.
|
||||||
|
* @param filteredTransaction the FilteredTransaction to which the signature will apply.
|
||||||
|
* @return the [TransactionSignature] generated by signing with the internally held identity [java.security.PrivateKey].
|
||||||
|
*/
|
||||||
|
fun createSignature(filteredTransaction: FilteredTransaction): TransactionSignature {
|
||||||
|
return createSignature(filteredTransaction, legalIdentityKey)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exposes a JDBC connection (session) object using the currently configured database.
|
* Exposes a JDBC connection (session) object using the currently configured database.
|
||||||
* Applications can use this to execute arbitrary SQL queries (native, direct, prepared, callable)
|
* Applications can use this to execute arbitrary SQL queries (native, direct, prepared, callable)
|
||||||
|
@ -139,13 +139,13 @@ class FilteredLeaves(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing merkleized filtered transaction.
|
* Class representing merkleized filtered transaction.
|
||||||
* @param rootHash Merkle tree root hash.
|
* @param id Merkle tree root hash.
|
||||||
* @param filteredLeaves Leaves included in a filtered transaction.
|
* @param filteredLeaves Leaves included in a filtered transaction.
|
||||||
* @param partialMerkleTree Merkle branch needed to verify filteredLeaves.
|
* @param partialMerkleTree Merkle branch needed to verify filteredLeaves.
|
||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
class FilteredTransaction private constructor(
|
class FilteredTransaction private constructor(
|
||||||
val rootHash: SecureHash,
|
val id: SecureHash,
|
||||||
val filteredLeaves: FilteredLeaves,
|
val filteredLeaves: FilteredLeaves,
|
||||||
val partialMerkleTree: PartialMerkleTree
|
val partialMerkleTree: PartialMerkleTree
|
||||||
) {
|
) {
|
||||||
@ -230,13 +230,13 @@ class FilteredTransaction private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs verification of Partial Merkle Branch against [rootHash].
|
* Runs verification of Partial Merkle Branch against [id].
|
||||||
*/
|
*/
|
||||||
@Throws(MerkleTreeException::class)
|
@Throws(MerkleTreeException::class)
|
||||||
fun verify(): Boolean {
|
fun verify(): Boolean {
|
||||||
val hashes: List<SecureHash> = filteredLeaves.availableComponentHashes
|
val hashes: List<SecureHash> = filteredLeaves.availableComponentHashes
|
||||||
if (hashes.isEmpty())
|
if (hashes.isEmpty())
|
||||||
throw MerkleTreeException("Transaction without included leaves.")
|
throw MerkleTreeException("Transaction without included leaves.")
|
||||||
return partialMerkleTree.verify(rootHash, hashes)
|
return partialMerkleTree.verify(id, hashes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,10 @@ UNRELEASED
|
|||||||
|
|
||||||
* ``SerializationCustomization.addToWhitelist()` now accepts multiple classes via varargs.
|
* ``SerializationCustomization.addToWhitelist()` now accepts multiple classes via varargs.
|
||||||
|
|
||||||
|
* Two functions to easily sign a ``FilteredTransaction`` have been added to ``ServiceHub``:
|
||||||
|
``createSignature(filteredTransaction: FilteredTransaction, publicKey: PublicKey)`` and
|
||||||
|
``createSignature(filteredTransaction: FilteredTransaction)`` to sign with the legal identity key.
|
||||||
|
|
||||||
Milestone 14
|
Milestone 14
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ In the Oracle example this step takes place in ``RatesFixFlow`` by overriding ``
|
|||||||
// Direct accsess to included commands, inputs, outputs, attachments etc.
|
// Direct accsess to included commands, inputs, outputs, attachments etc.
|
||||||
val cmds: List<Command> = ftx.filteredLeaves.commands
|
val cmds: List<Command> = ftx.filteredLeaves.commands
|
||||||
val ins: List<StateRef> = ftx.filteredLeaves.inputs
|
val ins: List<StateRef> = ftx.filteredLeaves.inputs
|
||||||
val timestamp: Timestamp? = ftx.filteredLeaves.timestamp
|
val timeWindow: TimeWindow? = ftx.filteredLeaves.timeWindow
|
||||||
...
|
...
|
||||||
|
|
||||||
.. literalinclude:: ../../samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt
|
.. literalinclude:: ../../samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt
|
||||||
|
@ -85,7 +85,7 @@ class BFTNonValidatingNotaryService(override val services: ServiceHubInternal, c
|
|||||||
when (response) {
|
when (response) {
|
||||||
is BFTSMaRt.ClusterResponse.Error -> throw NotaryException(response.error)
|
is BFTSMaRt.ClusterResponse.Error -> throw NotaryException(response.error)
|
||||||
is BFTSMaRt.ClusterResponse.Signatures -> {
|
is BFTSMaRt.ClusterResponse.Signatures -> {
|
||||||
log.debug("All input states of transaction ${stx.rootHash} have been committed")
|
log.debug("All input states of transaction ${stx.id} have been committed")
|
||||||
return response.txSignatures
|
return response.txSignatures
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,16 +139,13 @@ class BFTNonValidatingNotaryService(override val services: ServiceHubInternal, c
|
|||||||
|
|
||||||
fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: Party): BFTSMaRt.ReplicaResponse {
|
fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: Party): BFTSMaRt.ReplicaResponse {
|
||||||
return try {
|
return try {
|
||||||
val id = ftx.rootHash
|
val id = ftx.id
|
||||||
val inputs = ftx.filteredLeaves.inputs
|
val inputs = ftx.filteredLeaves.inputs
|
||||||
|
|
||||||
validateTimeWindow(ftx.filteredLeaves.timeWindow)
|
validateTimeWindow(ftx.filteredLeaves.timeWindow)
|
||||||
commitInputStates(inputs, id, callerIdentity)
|
commitInputStates(inputs, id, callerIdentity)
|
||||||
|
|
||||||
log.debug { "Inputs committed successfully, signing $id" }
|
log.debug { "Inputs committed successfully, signing $id" }
|
||||||
val signableData = SignableData(id, SignatureMetadata(services.myInfo.platformVersion, Crypto.findSignatureScheme(services.notaryIdentityKey).schemeNumberID))
|
BFTSMaRt.ReplicaResponse.Signature(sign(ftx))
|
||||||
val sig = sign(signableData)
|
|
||||||
BFTSMaRt.ReplicaResponse.Signature(sig)
|
|
||||||
} catch (e: NotaryException) {
|
} catch (e: NotaryException) {
|
||||||
log.debug { "Error processing transaction: ${e.error}" }
|
log.debug { "Error processing transaction: ${e.error}" }
|
||||||
BFTSMaRt.ReplicaResponse.Error(e.error)
|
BFTSMaRt.ReplicaResponse.Error(e.error)
|
||||||
|
@ -251,8 +251,8 @@ object BFTSMaRt {
|
|||||||
return services.database.transaction { services.keyManagementService.sign(bytes, services.notaryIdentityKey) }
|
return services.database.transaction { services.keyManagementService.sign(bytes, services.notaryIdentityKey) }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun sign(signableData: SignableData): TransactionSignature {
|
protected fun sign(filteredTransaction: FilteredTransaction): TransactionSignature {
|
||||||
return services.database.transaction { services.keyManagementService.sign(signableData, services.notaryIdentityKey) }
|
return services.database.transaction { services.createSignature(filteredTransaction, services.notaryIdentityKey) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
@ -24,7 +24,7 @@ class NonValidatingNotaryFlow(otherSide: Party, service: TrustedAuthorityNotaryS
|
|||||||
when (it) {
|
when (it) {
|
||||||
is FilteredTransaction -> {
|
is FilteredTransaction -> {
|
||||||
it.verify()
|
it.verify()
|
||||||
TransactionParts(it.rootHash, it.filteredLeaves.inputs, it.filteredLeaves.timeWindow)
|
TransactionParts(it.id, it.filteredLeaves.inputs, it.filteredLeaves.timeWindow)
|
||||||
}
|
}
|
||||||
is NotaryChangeWireTransaction -> TransactionParts(it.id, it.inputs, null)
|
is NotaryChangeWireTransaction -> TransactionParts(it.id, it.inputs, null)
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -175,9 +175,7 @@ object NodeInterestRates {
|
|||||||
// Note that we will happily sign an invalid transaction, as we are only being presented with a filtered
|
// 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
|
// 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.
|
// an invalid transaction the signature is worthless.
|
||||||
val signableData = SignableData(ftx.rootHash, SignatureMetadata(services.myInfo.platformVersion, Crypto.findSignatureScheme(signingKey).schemeNumberID))
|
return services.createSignature(ftx, signingKey)
|
||||||
val signature = services.keyManagementService.sign(signableData, signingKey)
|
|
||||||
return TransactionSignature(signature.bytes, signingKey, signableData.signatureMetadata)
|
|
||||||
}
|
}
|
||||||
// DOCEND 1
|
// DOCEND 1
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user