mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
Encrypted transaction signatures and dependencies stored
This commit is contained in:
parent
bba864d86d
commit
c7cc817386
@ -27,6 +27,7 @@ class MigrationNamedCacheFactory(private val metricRegistry: MetricRegistry?,
|
||||
"DBTransactionStorage_transactions" -> caffeine.maximumWeight(
|
||||
nodeConfiguration?.transactionCacheSizeBytes ?: NodeConfiguration.defaultTransactionCacheSize
|
||||
)
|
||||
"DBTransactionStorage_encrypted_transactions" -> caffeine.maximumSize(defaultCacheSize)
|
||||
"PersistentIdentityService_keyToPartyAndCert" -> caffeine.maximumSize(defaultCacheSize)
|
||||
"PersistentIdentityService_nameToParty" -> caffeine.maximumSize(defaultCacheSize)
|
||||
"PersistentIdentityService_keyToParty" -> caffeine.maximumSize(defaultCacheSize)
|
||||
|
@ -130,7 +130,6 @@ object VaultMigrationSchema
|
||||
object VaultMigrationSchemaV1 : MappedSchema(schemaFamily = VaultMigrationSchema.javaClass, version = 1,
|
||||
mappedTypes = listOf(
|
||||
DBTransactionStorage.DBTransaction::class.java,
|
||||
DBTransactionStorage.DBEncryptedTransaction::class.java,
|
||||
PersistentIdentityService.PersistentPublicKeyHashToCertificate::class.java,
|
||||
PersistentIdentityService.PersistentPublicKeyHashToParty::class.java,
|
||||
BasicHSMKeyManagementService.PersistentKey::class.java,
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.node.services.persistence
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Weigher
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
@ -77,7 +76,26 @@ class DBTransactionStorage(private val database: CordaPersistence, cacheFactory:
|
||||
val status: TransactionStatus,
|
||||
|
||||
@Column(name = "timestamp", nullable = false)
|
||||
val timestamp: Instant
|
||||
val timestamp: Instant,
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name="${NODE_DATABASE_PREFIX}encrypted_transactions_dependencies",
|
||||
joinColumns = [JoinColumn(name = "tx_id", referencedColumnName = "tx_id")],
|
||||
foreignKey = ForeignKey(name = "FK__dependencies__encrytpedtx")
|
||||
)
|
||||
@Column(name="dependency")
|
||||
val dependencies: List<String>,
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name="${NODE_DATABASE_PREFIX}encrypted_transactions_signatures",
|
||||
joinColumns = [JoinColumn(name = "tx_id", referencedColumnName = "tx_id")],
|
||||
foreignKey = ForeignKey(name = "FK__signers__encrytpedtx")
|
||||
)
|
||||
@Lob
|
||||
@Column(name="signature")
|
||||
val signatures: List<ByteArray>
|
||||
)
|
||||
|
||||
enum class TransactionStatus {
|
||||
@ -176,8 +194,8 @@ class DBTransactionStorage(private val database: CordaPersistence, cacheFactory:
|
||||
EncryptedTransaction(
|
||||
SecureHash.parse(it.txId),
|
||||
it.transaction,
|
||||
emptySet(),
|
||||
emptyList()
|
||||
it.dependencies.map { hashString -> SecureHash.parse(hashString) }.toSet(),
|
||||
it.signatures.map { signature -> signature.deserialize<TransactionSignature>() }
|
||||
),
|
||||
it.status
|
||||
)
|
||||
@ -188,7 +206,9 @@ class DBTransactionStorage(private val database: CordaPersistence, cacheFactory:
|
||||
stateMachineRunId = FlowStateMachineImpl.currentStateMachine()?.id?.uuid?.toString(),
|
||||
transaction = value.encryptedBytes,
|
||||
status = value.status,
|
||||
timestamp = clock.instant()
|
||||
timestamp = clock.instant(),
|
||||
dependencies = value.dependencies.map { it.toHexString() },
|
||||
signatures = value.signatures.map { it.serialize().bytes }
|
||||
)
|
||||
},
|
||||
persistentEntityClass = DBEncryptedTransaction::class.java
|
||||
@ -431,14 +451,18 @@ class DBTransactionStorage(private val database: CordaPersistence, cacheFactory:
|
||||
private data class TxCacheEncryptedValue(
|
||||
val id: SecureHash,
|
||||
val encryptedBytes: ByteArray,
|
||||
val status: TransactionStatus
|
||||
val status: TransactionStatus,
|
||||
val dependencies: Set<SecureHash>,
|
||||
val signatures: List<TransactionSignature>
|
||||
) {
|
||||
constructor(encryptedTransaction: EncryptedTransaction, status: TransactionStatus) : this(
|
||||
encryptedTransaction.id,
|
||||
encryptedTransaction.encryptedBytes,
|
||||
status)
|
||||
status,
|
||||
encryptedTransaction.dependencies,
|
||||
encryptedTransaction.sigs)
|
||||
|
||||
fun toEncryptedTx() = EncryptedTransaction(id, encryptedBytes, emptySet(), emptyList())
|
||||
fun toEncryptedTx() = EncryptedTransaction(id, encryptedBytes, dependencies, signatures)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
@ -42,7 +42,7 @@ open class DefaultNamedCacheFactory protected constructor(private val metricRegi
|
||||
name == "SerializationScheme_attachmentClassloader" -> caffeine
|
||||
name == "HibernateConfiguration_sessionFactories" -> caffeine.maximumSize(database.mappedSchemaCacheSize)
|
||||
name == "DBTransactionStorage_transactions" -> caffeine.maximumWeight(transactionCacheSizeBytes)
|
||||
name == "DBTransactionStorage_encrypted_transactions" -> caffeine.maximumWeight(transactionCacheSizeBytes)
|
||||
name == "DBTransactionStorage_encrypted_transactions" -> caffeine.maximumSize(defaultCacheSize)
|
||||
name == "NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(attachmentContentCacheSizeBytes)
|
||||
name == "NodeAttachmentService_contractAttachmentVersions" -> caffeine.maximumSize(defaultCacheSize)
|
||||
name == "PersistentIdentityService_keyToPartyAndCert" -> caffeine.maximumSize(defaultCacheSize)
|
||||
|
@ -38,4 +38,6 @@
|
||||
|
||||
<include file="migration/node-core.changelog-v21.xml"/>
|
||||
|
||||
<include file="migration/node-core.changelog-v22-encryption.xml"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
@ -24,7 +24,32 @@
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="encrypted_transactions_add_primary_key">
|
||||
<addPrimaryKey columnNames="tx_id" constraintName="node_encrypted_transactions_pkey" tableName="node_encrypted_transactions"
|
||||
clustered="false"/>
|
||||
<addPrimaryKey columnNames="tx_id" constraintName="node_encrypted_transactions_pkey" tableName="node_encrypted_transactions"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
<changeSet author="R3.Corda" id="create_encrypted_transactions_dependencies">
|
||||
<createTable tableName="node_encrypted_transactions_dependencies">
|
||||
<column name="tx_id" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="dependency" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addForeignKeyConstraint baseColumnNames="tx_id" baseTableName="node_encrypted_transactions_dependencies"
|
||||
constraintName="FK__dependencies__encrytpedtx"
|
||||
referencedColumnNames="tx_id" referencedTableName="node_encrypted_transactions"/>
|
||||
</changeSet>
|
||||
<changeSet author="R3.Corda" id="create_encrypted_transactions_signatures">
|
||||
<createTable tableName="node_encrypted_transactions_signatures">
|
||||
<column name="tx_id" type="NVARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="signature" type="blob">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addForeignKeyConstraint baseColumnNames="tx_id" baseTableName="node_encrypted_transactions_signatures"
|
||||
constraintName="FK__signers__encrytpedtx"
|
||||
referencedColumnNames="tx_id" referencedTableName="node_encrypted_transactions"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
|
@ -5,8 +5,11 @@ import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.SignableData
|
||||
import net.corda.core.crypto.SignatureMetadata
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.internal.dependencies
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.deserialize
|
||||
@ -430,18 +433,36 @@ class DBTransactionStorageTests {
|
||||
encryptionCipher.init(Cipher.ENCRYPT_MODE, key, iv)
|
||||
|
||||
val encryptedTxBytes = encryptionCipher.doFinal(transaction.serialize(context = contextToUse().withEncoding(CordaSerializationEncoding.SNAPPY)).bytes)
|
||||
val encryptedTx = EncryptedTransaction(transaction.id, encryptedTxBytes, emptySet(), emptyList())
|
||||
|
||||
// let's sign with 2 keys to ensure we can store multiple sigs
|
||||
val enclaveKeyPairs = (0..1).map {
|
||||
Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256")
|
||||
}
|
||||
|
||||
val signatures = enclaveKeyPairs.map {
|
||||
val signatureMetadata = SignatureMetadata(
|
||||
platformVersion = 1,
|
||||
schemeNumberID = Crypto.findSignatureScheme(it.public).schemeNumberID
|
||||
)
|
||||
val signableData = SignableData(transaction.id, signatureMetadata)
|
||||
it.sign(signableData)
|
||||
}
|
||||
|
||||
val encryptedTx = EncryptedTransaction(transaction.id, encryptedTxBytes, transaction.dependencies, signatures)
|
||||
|
||||
transactionStorage.addVerifiedEncryptedTransaction(encryptedTx)
|
||||
|
||||
val storedTx = transactionStorage.getEncryptedTransaction(transaction.id)
|
||||
|
||||
val decryptionCipher = Cipher.getInstance(cipherTransformation)
|
||||
decryptionCipher.init(Cipher.DECRYPT_MODE, key, iv)
|
||||
|
||||
assertNotNull(storedTx, "Could not find stored encrypted message")
|
||||
val storedTx = transactionStorage.getEncryptedTransaction(transaction.id) ?:
|
||||
throw IllegalStateException("Could not find stored encrypted message")
|
||||
|
||||
val decryptedTx = decryptionCipher.doFinal(storedTx!!.encryptedBytes).deserialize<SignedTransaction>(context = contextToUse())
|
||||
val decryptedTx = decryptionCipher.doFinal(storedTx.encryptedBytes).deserialize<SignedTransaction>(context = contextToUse())
|
||||
|
||||
assertEquals(transaction.dependencies, storedTx.dependencies)
|
||||
assertEquals(signatures.toSet(), storedTx.sigs.toSet())
|
||||
|
||||
assertEquals(decryptedTx, transaction)
|
||||
|
||||
@ -465,7 +486,7 @@ class DBTransactionStorageTests {
|
||||
|
||||
private fun newTransaction(): SignedTransaction {
|
||||
val wtx = createWireTransaction(
|
||||
inputs = listOf(StateRef(SecureHash.randomSHA256(), 0)),
|
||||
inputs = listOf(StateRef(SecureHash.randomSHA256(), 0), StateRef(SecureHash.randomSHA256(), 0)),
|
||||
attachments = emptyList(),
|
||||
outputs = emptyList(),
|
||||
commands = listOf(dummyCommand()),
|
||||
|
Loading…
Reference in New Issue
Block a user