From 7d1d2297e72ecf8ea16fb2c5bd5e2edbe9dfd48b Mon Sep 17 00:00:00 2001 From: Jose Coll Date: Thu, 20 Jul 2023 09:55:44 +0100 Subject: [PATCH] ENT-10289 Ensure Sender and Receiver Distribution records share the same timestamp (#7437) --- .../DBTransactionStorageLedgerRecovery.kt | 17 +++++++++++------ .../DBTransactionStorageLedgerRecoveryTests.kt | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecovery.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecovery.kt index ae1c066ab2..0d00344742 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecovery.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecovery.kt @@ -141,8 +141,9 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence, override fun addSenderTransactionRecoveryMetadata(id: SecureHash, metadata: TransactionMetadata): ByteArray { return database.transaction { - metadata.distributionList.peersToStatesToRecord.map { (peer, _) -> - val senderDistributionRecord = DBSenderDistributionRecord(PersistentKey(Key(clock.instant())), + val senderRecordingTimestamp = clock.instant() + metadata.distributionList.peersToStatesToRecord.forEach { (peer, _) -> + val senderDistributionRecord = DBSenderDistributionRecord(PersistentKey(Key(senderRecordingTimestamp)), id.toString(), partyInfoCache.getPartyIdByCordaX500Name(peer), metadata.distributionList.senderStatesToRecord) @@ -150,15 +151,16 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence, } val hashedPeersToStatesToRecord = metadata.distributionList.peersToStatesToRecord.map { (peer, statesToRecord) -> partyInfoCache.getPartyIdByCordaX500Name(peer) to statesToRecord }.toMap() - val hashedDistributionList = HashedDistributionList(metadata.distributionList.senderStatesToRecord, hashedPeersToStatesToRecord) + val hashedDistributionList = HashedDistributionList(metadata.distributionList.senderStatesToRecord, hashedPeersToStatesToRecord, senderRecordingTimestamp) cryptoService.encrypt(hashedDistributionList.serialize()) } } override fun addReceiverTransactionRecoveryMetadata(id: SecureHash, sender: CordaX500Name, receiver: CordaX500Name, receiverStatesToRecord: StatesToRecord, encryptedDistributionList: ByteArray) { + val senderRecordedTimestamp = HashedDistributionList.deserialize(cryptoService.decrypt(encryptedDistributionList)).senderRecordedTimestamp database.transaction { val receiverDistributionRecord = - DBReceiverDistributionRecord(Key(clock.instant()), + DBReceiverDistributionRecord(Key(senderRecordedTimestamp), id, partyInfoCache.getPartyIdByCordaX500Name(sender), encryptedDistributionList, @@ -320,7 +322,8 @@ enum class DistributionRecordType { @CordaSerializable data class HashedDistributionList( val senderStatesToRecord: StatesToRecord, - val peerHashToStatesToRecord: Map + val peerHashToStatesToRecord: Map, + val senderRecordedTimestamp: Instant ) { fun serialize(): ByteArray { val baos = ByteArrayOutputStream() @@ -333,6 +336,7 @@ data class HashedDistributionList( out.writeLong(entry.key) out.writeByte(entry.value.ordinal) } + out.writeLong(senderRecordedTimestamp.toEpochMilli()) out.flush() return baos.toByteArray() } @@ -349,7 +353,8 @@ data class HashedDistributionList( repeat (numPeerHashToStatesToRecords) { peerHashToStatesToRecord[input.readLong()] = StatesToRecord.values()[input.readByte().toInt()] } - return HashedDistributionList(senderStatesToRecord, peerHashToStatesToRecord) + val senderRecordedTimestamp = Instant.ofEpochMilli(input.readLong()) + return HashedDistributionList(senderStatesToRecord, peerHashToStatesToRecord, senderRecordedTimestamp) } } } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt index c4ef9b2f48..5f52c0849f 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageLedgerRecoveryTests.kt @@ -279,7 +279,7 @@ class DBTransactionStorageLedgerRecoveryTests { @Test(timeout = 300_000) fun `test lightweight serialization and deserialization of hashed distribution list payload`() { val dl = HashedDistributionList(ALL_VISIBLE, - mapOf(BOB.name.hashCode().toLong() to NONE, CHARLIE_NAME.hashCode().toLong() to ONLY_RELEVANT)) + mapOf(BOB.name.hashCode().toLong() to NONE, CHARLIE_NAME.hashCode().toLong() to ONLY_RELEVANT), now()) assertEquals(dl, dl.serialize().let { HashedDistributionList.deserialize(it) }) } @@ -373,7 +373,7 @@ class DBTransactionStorageLedgerRecoveryTests { private fun DistributionList.toWire(cryptoService: CryptoService = MockCryptoService(emptyMap())): ByteArray { val hashedPeersToStatesToRecord = this.peersToStatesToRecord.map { (peer, statesToRecord) -> partyInfoCache.getPartyIdByCordaX500Name(peer) to statesToRecord }.toMap() - val hashedDistributionList = HashedDistributionList(this.senderStatesToRecord, hashedPeersToStatesToRecord) + val hashedDistributionList = HashedDistributionList(this.senderStatesToRecord, hashedPeersToStatesToRecord, now()) return cryptoService.encrypt(hashedDistributionList.serialize()) } }