Encrypted transaction signatures and dependencies stored

This commit is contained in:
adam.houston 2022-03-14 15:20:23 +00:00
parent bba864d86d
commit c7cc817386
7 changed files with 90 additions and 18 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -38,4 +38,6 @@
<include file="migration/node-core.changelog-v21.xml"/>
<include file="migration/node-core.changelog-v22-encryption.xml"/>
</databaseChangeLog>

View File

@ -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>

View File

@ -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()),