mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +00:00
ENT-9943: Now use SecureHash to represent CordaX500Name in distributi… (#7501)
This commit is contained in:
parent
aec91c450e
commit
3a23f60199
@ -355,14 +355,14 @@ class FinalityFlowTests : WithFinality {
|
||||
val sdrs = getSenderRecoveryData(stx.id, aliceNode.database).apply {
|
||||
assertEquals(1, this.size)
|
||||
assertEquals(StatesToRecord.ALL_VISIBLE, this[0].statesToRecord)
|
||||
assertEquals(BOB_NAME.hashCode().toLong(), this[0].peerPartyId)
|
||||
assertEquals(SecureHash.sha256(BOB_NAME.toString()), this[0].peerPartyId)
|
||||
}
|
||||
val rdr = getReceiverRecoveryData(stx.id, bobNode).apply {
|
||||
assertNotNull(this)
|
||||
val hashedDL = HashedDistributionList.decrypt(this!!.encryptedDistributionList.bytes, aliceNode.internals.encryptionService)
|
||||
assertEquals(StatesToRecord.ONLY_RELEVANT, hashedDL.senderStatesToRecord)
|
||||
assertEquals(aliceNode.info.singleIdentity().name.hashCode().toLong(), this.initiatorPartyId)
|
||||
assertEquals(mapOf(BOB_NAME.hashCode().toLong() to StatesToRecord.ALL_VISIBLE), hashedDL.peerHashToStatesToRecord)
|
||||
assertEquals(SecureHash.sha256(aliceNode.info.singleIdentity().name.toString()), this.initiatorPartyId)
|
||||
assertEquals(mapOf<SecureHash, StatesToRecord>(SecureHash.sha256(BOB_NAME.toString()) to StatesToRecord.ALL_VISIBLE), hashedDL.peerHashToStatesToRecord)
|
||||
}
|
||||
validateSenderAndReceiverTimestamps(sdrs, rdr!!)
|
||||
}
|
||||
@ -388,19 +388,19 @@ class FinalityFlowTests : WithFinality {
|
||||
val sdrs = getSenderRecoveryData(stx.id, aliceNode.database).apply {
|
||||
assertEquals(2, this.size)
|
||||
assertEquals(StatesToRecord.ONLY_RELEVANT, this[0].statesToRecord)
|
||||
assertEquals(BOB_NAME.hashCode().toLong(), this[0].peerPartyId)
|
||||
assertEquals(SecureHash.sha256(BOB_NAME.toString()), this[0].peerPartyId)
|
||||
assertEquals(StatesToRecord.ALL_VISIBLE, this[1].statesToRecord)
|
||||
assertEquals(CHARLIE_NAME.hashCode().toLong(), this[1].peerPartyId)
|
||||
assertEquals(SecureHash.sha256(CHARLIE_NAME.toString()), this[1].peerPartyId)
|
||||
}
|
||||
val rdr = getReceiverRecoveryData(stx.id, bobNode).apply {
|
||||
assertNotNull(this)
|
||||
val hashedDL = HashedDistributionList.decrypt(this!!.encryptedDistributionList.bytes, aliceNode.internals.encryptionService)
|
||||
assertEquals(StatesToRecord.ONLY_RELEVANT, hashedDL.senderStatesToRecord)
|
||||
assertEquals(aliceNode.info.singleIdentity().name.hashCode().toLong(), this.initiatorPartyId)
|
||||
assertEquals(SecureHash.sha256(aliceNode.info.singleIdentity().name.toString()), this.initiatorPartyId)
|
||||
// note: Charlie assertion here is using the hinted StatesToRecord value passed to it from Alice
|
||||
assertEquals(mapOf(
|
||||
BOB_NAME.hashCode().toLong() to StatesToRecord.ONLY_RELEVANT,
|
||||
CHARLIE_NAME.hashCode().toLong() to StatesToRecord.ALL_VISIBLE
|
||||
assertEquals(mapOf<SecureHash, StatesToRecord>(
|
||||
SecureHash.sha256(BOB_NAME.toString()) to StatesToRecord.ONLY_RELEVANT,
|
||||
SecureHash.sha256(CHARLIE_NAME.toString()) to StatesToRecord.ALL_VISIBLE
|
||||
), hashedDL.peerHashToStatesToRecord)
|
||||
}
|
||||
validateSenderAndReceiverTimestamps(sdrs, rdr!!)
|
||||
@ -452,14 +452,14 @@ class FinalityFlowTests : WithFinality {
|
||||
val sdr = getSenderRecoveryData(stx.id, aliceNode.database).apply {
|
||||
assertEquals(1, this.size)
|
||||
assertEquals(StatesToRecord.ONLY_RELEVANT, this[0].statesToRecord)
|
||||
assertEquals(BOB_NAME.hashCode().toLong(), this[0].peerPartyId)
|
||||
assertEquals(SecureHash.sha256(BOB_NAME.toString()), this[0].peerPartyId)
|
||||
}
|
||||
val rdr = getReceiverRecoveryData(stx.id, bobNode).apply {
|
||||
assertNotNull(this)
|
||||
val hashedDL = HashedDistributionList.decrypt(this!!.encryptedDistributionList.bytes, aliceNode.internals.encryptionService)
|
||||
assertEquals(StatesToRecord.ONLY_RELEVANT, hashedDL.senderStatesToRecord)
|
||||
assertEquals(aliceNode.info.singleIdentity().name.hashCode().toLong(), this.initiatorPartyId)
|
||||
assertEquals(mapOf(BOB_NAME.hashCode().toLong() to StatesToRecord.ONLY_RELEVANT), hashedDL.peerHashToStatesToRecord)
|
||||
assertEquals(SecureHash.sha256(aliceNode.info.singleIdentity().name.toString()), this.initiatorPartyId)
|
||||
assertEquals(mapOf<SecureHash, StatesToRecord>(SecureHash.sha256(BOB_NAME.toString()) to StatesToRecord.ONLY_RELEVANT), hashedDL.peerHashToStatesToRecord)
|
||||
}
|
||||
validateSenderAndReceiverTimestamps(sdr, rdr!!)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
@ -35,9 +36,9 @@ class PersistentPartyInfoCacheTest {
|
||||
createNodeInfo(listOf(CHARLIE))))
|
||||
val partyInfoCache = PersistentPartyInfoCache(charlieNetMapCache, TestingNamedCacheFactory(), database)
|
||||
partyInfoCache.start()
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(ALICE.name)).isEqualTo(ALICE.name.hashCode().toLong())
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(BOB.name)).isEqualTo(BOB.name.hashCode().toLong())
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(CHARLIE.name)).isEqualTo(CHARLIE.name.hashCode().toLong())
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(ALICE.name)).isEqualTo(SecureHash.sha256(ALICE.name.toString()))
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(BOB.name)).isEqualTo(SecureHash.sha256(BOB.name.toString()))
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(CHARLIE.name)).isEqualTo(SecureHash.sha256(CHARLIE.name.toString()))
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@ -50,9 +51,9 @@ class PersistentPartyInfoCacheTest {
|
||||
// clear network map cache & bootstrap another PersistentInfoCache
|
||||
charlieNetMapCache.clearNetworkMapCache()
|
||||
val partyInfoCache = PersistentPartyInfoCache(charlieNetMapCache, TestingNamedCacheFactory(), database)
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(ALICE.name)).isEqualTo(ALICE.name.hashCode().toLong())
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(BOB.name)).isEqualTo(BOB.name.hashCode().toLong())
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(CHARLIE.name)).isEqualTo(CHARLIE.name.hashCode().toLong())
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(ALICE.name)).isEqualTo(SecureHash.sha256(ALICE.name.toString()))
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(BOB.name)).isEqualTo(SecureHash.sha256(BOB.name.toString()))
|
||||
assertThat(partyInfoCache.getPartyIdByCordaX500Name(CHARLIE.name)).isEqualTo(SecureHash.sha256(CHARLIE.name.toString()))
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@ -63,9 +64,9 @@ class PersistentPartyInfoCacheTest {
|
||||
createNodeInfo(listOf(CHARLIE))))
|
||||
val partyInfoCache = PersistentPartyInfoCache(charlieNetMapCache, TestingNamedCacheFactory(), database)
|
||||
partyInfoCache.start()
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(ALICE.name.hashCode().toLong())).isEqualTo(ALICE.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(BOB.name.hashCode().toLong())).isEqualTo(BOB.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(CHARLIE.name.hashCode().toLong())).isEqualTo(CHARLIE.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(SecureHash.sha256(ALICE.name.toString()))).isEqualTo(ALICE.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(SecureHash.sha256(BOB.name.toString()))).isEqualTo(BOB.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(SecureHash.sha256(CHARLIE.name.toString()))).isEqualTo(CHARLIE.name)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@ -78,9 +79,9 @@ class PersistentPartyInfoCacheTest {
|
||||
// clear network map cache & bootstrap another PersistentInfoCache
|
||||
charlieNetMapCache.clearNetworkMapCache()
|
||||
val partyInfoCache = PersistentPartyInfoCache(charlieNetMapCache, TestingNamedCacheFactory(), database)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(ALICE.name.hashCode().toLong())).isEqualTo(ALICE.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(BOB.name.hashCode().toLong())).isEqualTo(BOB.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(CHARLIE.name.hashCode().toLong())).isEqualTo(CHARLIE.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(SecureHash.sha256(ALICE.name.toString()))).isEqualTo(ALICE.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(SecureHash.sha256(BOB.name.toString()))).isEqualTo(BOB.name)
|
||||
assertThat(partyInfoCache.getCordaX500NameByPartyId(SecureHash.sha256(CHARLIE.name.toString()))).isEqualTo(CHARLIE.name)
|
||||
}
|
||||
|
||||
private fun createNodeInfo(identities: List<TestIdentity>,
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
@ -14,13 +15,13 @@ class PersistentPartyInfoCache(private val networkMapCache: PersistentNetworkMap
|
||||
private val database: CordaPersistence) {
|
||||
|
||||
// probably better off using a BiMap here: https://www.baeldung.com/guava-bimap
|
||||
private val cordaX500NameToPartyIdCache = NonInvalidatingCache<CordaX500Name, Long?>(
|
||||
private val cordaX500NameToPartyIdCache = NonInvalidatingCache<CordaX500Name, SecureHash?>(
|
||||
cacheFactory = cacheFactory,
|
||||
name = "RecoveryPartyInfoCache_byCordaX500Name") { key ->
|
||||
database.transaction { queryByCordaX500Name(session, key) }
|
||||
}
|
||||
|
||||
private val partyIdToCordaX500NameCache = NonInvalidatingCache<Long, CordaX500Name?>(
|
||||
private val partyIdToCordaX500NameCache = NonInvalidatingCache<SecureHash, CordaX500Name?>(
|
||||
cacheFactory = cacheFactory,
|
||||
name = "RecoveryPartyInfoCache_byPartyId") { key ->
|
||||
database.transaction { queryByPartyId(session, key) }
|
||||
@ -32,48 +33,48 @@ class PersistentPartyInfoCache(private val networkMapCache: PersistentNetworkMap
|
||||
val (snapshot, updates) = networkMapCache.track()
|
||||
snapshot.map { entry ->
|
||||
entry.legalIdentities.map { party ->
|
||||
add(party.name.hashCode().toLong(), party.name)
|
||||
add(SecureHash.sha256(party.name.toString()), party.name)
|
||||
}
|
||||
}
|
||||
trackNetworkMapUpdates = updates
|
||||
trackNetworkMapUpdates.cache().forEach { nodeInfo ->
|
||||
nodeInfo.node.legalIdentities.map { party ->
|
||||
add(party.name.hashCode().toLong(), party.name)
|
||||
add(SecureHash.sha256(party.name.toString()), party.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getPartyIdByCordaX500Name(name: CordaX500Name): Long = cordaX500NameToPartyIdCache[name] ?: throw IllegalStateException("Missing cache entry for $name")
|
||||
fun getPartyIdByCordaX500Name(name: CordaX500Name): SecureHash = cordaX500NameToPartyIdCache[name] ?: throw IllegalStateException("Missing cache entry for $name")
|
||||
|
||||
fun getCordaX500NameByPartyId(partyId: Long): CordaX500Name = partyIdToCordaX500NameCache[partyId] ?: throw IllegalStateException("Missing cache entry for $partyId")
|
||||
fun getCordaX500NameByPartyId(partyId: SecureHash): CordaX500Name = partyIdToCordaX500NameCache[partyId] ?: throw IllegalStateException("Missing cache entry for $partyId")
|
||||
|
||||
private fun add(partyHashCode: Long, partyName: CordaX500Name) {
|
||||
private fun add(partyHashCode: SecureHash, partyName: CordaX500Name) {
|
||||
partyIdToCordaX500NameCache.cache.put(partyHashCode, partyName)
|
||||
cordaX500NameToPartyIdCache.cache.put(partyName, partyHashCode)
|
||||
updateInfoDB(partyHashCode, partyName)
|
||||
}
|
||||
|
||||
private fun updateInfoDB(partyHashCode: Long, partyName: CordaX500Name) {
|
||||
private fun updateInfoDB(partyHashCode: SecureHash, partyName: CordaX500Name) {
|
||||
database.transaction {
|
||||
if (queryByPartyId(session, partyHashCode) == null) {
|
||||
session.save(DBTransactionStorageLedgerRecovery.DBRecoveryPartyInfo(partyHashCode, partyName.toString()))
|
||||
session.save(DBTransactionStorageLedgerRecovery.DBRecoveryPartyInfo(partyHashCode.toString(), partyName.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun queryByCordaX500Name(session: Session, key: CordaX500Name): Long? {
|
||||
private fun queryByCordaX500Name(session: Session, key: CordaX500Name): SecureHash? {
|
||||
val query = session.createQuery(
|
||||
"FROM ${DBTransactionStorageLedgerRecovery.DBRecoveryPartyInfo::class.java.name} WHERE partyName = :partyName",
|
||||
DBTransactionStorageLedgerRecovery.DBRecoveryPartyInfo::class.java)
|
||||
query.setParameter("partyName", key.toString())
|
||||
return query.resultList.singleOrNull()?.partyId
|
||||
return query.resultList.singleOrNull()?.let { SecureHash.parse(it.partyId) }
|
||||
}
|
||||
|
||||
private fun queryByPartyId(session: Session, key: Long): CordaX500Name? {
|
||||
private fun queryByPartyId(session: Session, key: SecureHash): CordaX500Name? {
|
||||
val query = session.createQuery(
|
||||
"FROM ${DBTransactionStorageLedgerRecovery.DBRecoveryPartyInfo::class.java.name} WHERE partyId = :partyId",
|
||||
DBTransactionStorageLedgerRecovery.DBRecoveryPartyInfo::class.java)
|
||||
query.setParameter("partyId", key)
|
||||
query.setParameter("partyId", key.toString())
|
||||
return query.resultList.singleOrNull()?.partyName?.let { CordaX500Name.parse(it) }
|
||||
}
|
||||
}
|
@ -39,8 +39,8 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
@Immutable
|
||||
data class PersistentKey(
|
||||
/** PartyId of flow peer **/
|
||||
@Column(name = "peer_party_id", nullable = false)
|
||||
var peerPartyId: Long,
|
||||
@Column(name = "peer_party_id", length = 144, nullable = false)
|
||||
var peerPartyId: String,
|
||||
|
||||
@Column(name = "timestamp", nullable = false)
|
||||
var timestamp: Instant,
|
||||
@ -49,7 +49,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
var timestampDiscriminator: Int
|
||||
|
||||
) : Serializable {
|
||||
constructor(key: Key) : this(key.partyId, key.timestamp, key.timestampDiscriminator)
|
||||
constructor(key: Key) : this(key.partyId.toString(), key.timestamp, key.timestampDiscriminator)
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
@ -69,7 +69,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
fun toSenderDistributionRecord() =
|
||||
SenderDistributionRecord(
|
||||
SecureHash.parse(this.txId),
|
||||
this.compositeKey.peerPartyId,
|
||||
SecureHash.parse(this.compositeKey.peerPartyId),
|
||||
this.statesToRecord,
|
||||
this.compositeKey.timestamp
|
||||
)
|
||||
@ -104,7 +104,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
fun toReceiverDistributionRecord(): ReceiverDistributionRecord {
|
||||
return ReceiverDistributionRecord(
|
||||
SecureHash.parse(this.txId),
|
||||
this.compositeKey.peerPartyId,
|
||||
SecureHash.parse(this.compositeKey.peerPartyId),
|
||||
OpaqueBytes(this.distributionList),
|
||||
this.compositeKey.timestamp
|
||||
)
|
||||
@ -116,8 +116,8 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
data class DBRecoveryPartyInfo(
|
||||
@Id
|
||||
/** CordaX500Name hashCode() **/
|
||||
@Column(name = "party_id", nullable = false)
|
||||
var partyId: Long,
|
||||
@Column(name = "party_id", length = 144, nullable = false)
|
||||
var partyId: String,
|
||||
|
||||
/** CordaX500Name of party **/
|
||||
@Column(name = "party_name", nullable = false)
|
||||
@ -127,11 +127,11 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
data class TimestampKey(val timestamp: Instant, val timestampDiscriminator: Int)
|
||||
|
||||
class Key(
|
||||
val partyId: Long,
|
||||
val partyId: SecureHash,
|
||||
val timestamp: Instant,
|
||||
val timestampDiscriminator: Int = nextDiscriminatorNumber.andIncrement
|
||||
) {
|
||||
constructor(key: TimestampKey, partyId: Long): this(partyId, key.timestamp, key.timestampDiscriminator)
|
||||
constructor(key: TimestampKey, partyId: SecureHash): this(partyId, key.timestamp, key.timestampDiscriminator)
|
||||
companion object {
|
||||
val nextDiscriminatorNumber = AtomicInteger()
|
||||
}
|
||||
@ -237,7 +237,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
excludingTxnIds.map { it.toString() }))))
|
||||
}
|
||||
if (peers.isNotEmpty()) {
|
||||
val peerPartyIds = peers.map { partyInfoCache.getPartyIdByCordaX500Name(it) }
|
||||
val peerPartyIds = peers.map { partyInfoCache.getPartyIdByCordaX500Name(it).toString() }
|
||||
predicates.add(criteriaBuilder.and(compositeKey.get<Long>(PersistentKey::peerPartyId.name).`in`(peerPartyIds)))
|
||||
}
|
||||
criteriaQuery.where(*predicates.toTypedArray())
|
||||
@ -275,7 +275,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
|
||||
predicates.add(criteriaBuilder.and(criteriaBuilder.not(txId.`in`(excludingTxnIds.map { it.toString() }))))
|
||||
}
|
||||
if (initiators.isNotEmpty()) {
|
||||
val initiatorPartyIds = initiators.map(partyInfoCache::getPartyIdByCordaX500Name)
|
||||
val initiatorPartyIds = initiators.map { partyInfoCache.getPartyIdByCordaX500Name(it).toString() }
|
||||
predicates.add(criteriaBuilder.and(compositeKey.get<Long>(PersistentKey::peerPartyId.name).`in`(initiatorPartyIds)))
|
||||
}
|
||||
criteriaQuery.where(*predicates.toTypedArray())
|
||||
@ -319,7 +319,7 @@ abstract class DistributionRecord {
|
||||
@CordaSerializable
|
||||
data class SenderDistributionRecord(
|
||||
override val txId: SecureHash,
|
||||
val peerPartyId: Long, // CordaX500Name hashCode()
|
||||
val peerPartyId: SecureHash, // CordaX500Name hashCode()
|
||||
val statesToRecord: StatesToRecord,
|
||||
override val timestamp: Instant
|
||||
) : DistributionRecord()
|
||||
@ -327,7 +327,7 @@ data class SenderDistributionRecord(
|
||||
@CordaSerializable
|
||||
data class ReceiverDistributionRecord(
|
||||
override val txId: SecureHash,
|
||||
val initiatorPartyId: Long, // CordaX500Name hashCode()
|
||||
val initiatorPartyId: SecureHash, // CordaX500Name hashCode()
|
||||
val encryptedDistributionList: OpaqueBytes,
|
||||
override val timestamp: Instant
|
||||
) : DistributionRecord()
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.services.persistence
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.StatesToRecord
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.node.services.EncryptionService
|
||||
@ -13,7 +14,7 @@ import java.time.Instant
|
||||
@CordaSerializable
|
||||
data class HashedDistributionList(
|
||||
val senderStatesToRecord: StatesToRecord,
|
||||
val peerHashToStatesToRecord: Map<Long, StatesToRecord>,
|
||||
val peerHashToStatesToRecord: Map<SecureHash, StatesToRecord>,
|
||||
val publicHeader: PublicHeader
|
||||
) {
|
||||
/**
|
||||
@ -28,7 +29,7 @@ data class HashedDistributionList(
|
||||
out.writeByte(senderStatesToRecord.ordinal)
|
||||
out.writeInt(peerHashToStatesToRecord.size)
|
||||
for (entry in peerHashToStatesToRecord) {
|
||||
out.writeLong(entry.key)
|
||||
entry.key.writeTo(out)
|
||||
out.writeByte(entry.value.ordinal)
|
||||
}
|
||||
return encryptionService.encrypt(baos.toByteArray(), publicHeader.serialise())
|
||||
@ -78,6 +79,7 @@ data class HashedDistributionList(
|
||||
// The version tag is serialised in the header, even though it is separate from the encrypted main body of the distribution list.
|
||||
// This is because the header and the dist list are cryptographically coupled and we want to avoid declaring the version field twice.
|
||||
private const val VERSION_TAG = 1
|
||||
private const val SECURE_HASH_LENGTH = 32
|
||||
private val statesToRecordValues = StatesToRecord.values() // Cache the enum values since .values() returns a new array each time.
|
||||
|
||||
/**
|
||||
@ -91,9 +93,11 @@ data class HashedDistributionList(
|
||||
try {
|
||||
val senderStatesToRecord = statesToRecordValues[input.readByte().toInt()]
|
||||
val numPeerHashToStatesToRecords = input.readInt()
|
||||
val peerHashToStatesToRecord = mutableMapOf<Long, StatesToRecord>()
|
||||
val peerHashToStatesToRecord = mutableMapOf<SecureHash, StatesToRecord>()
|
||||
repeat(numPeerHashToStatesToRecords) {
|
||||
peerHashToStatesToRecord[input.readLong()] = statesToRecordValues[input.readByte().toInt()]
|
||||
val secureHashBytes = ByteArray(SECURE_HASH_LENGTH)
|
||||
input.readFully(secureHashBytes)
|
||||
peerHashToStatesToRecord[SecureHash.createSHA256(secureHashBytes)] = statesToRecordValues[input.readByte().toInt()]
|
||||
}
|
||||
return HashedDistributionList(senderStatesToRecord, peerHashToStatesToRecord, publicHeader)
|
||||
} catch (e: Exception) {
|
||||
|
@ -21,7 +21,7 @@
|
||||
<column name="transaction_id" type="NVARCHAR(144)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="peer_party_id" type="BIGINT">
|
||||
<column name="peer_party_id" type="NVARCHAR(144)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="states_to_record" type="INT">
|
||||
@ -46,7 +46,7 @@
|
||||
<column name="transaction_id" type="NVARCHAR(144)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="peer_party_id" type="BIGINT">
|
||||
<column name="peer_party_id" type="NVARCHAR(144)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="distribution_list" type="BLOB">
|
||||
@ -65,7 +65,7 @@
|
||||
|
||||
<changeSet author="R3.Corda" id="create_recovery_party_info_table">
|
||||
<createTable tableName="node_recovery_party_info">
|
||||
<column name="party_id" type="BIGINT">
|
||||
<column name="party_id" type="NVARCHAR(144)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="party_name" type="NVARCHAR(255)">
|
||||
|
@ -147,12 +147,12 @@ class DBTransactionStorageLedgerRecoveryTests {
|
||||
val timeWindow = RecoveryTimeWindow(fromTime = now().minus(1, ChronoUnit.DAYS))
|
||||
transactionRecovery.queryDistributionRecords(timeWindow, recordType = DistributionRecordType.SENDER).let {
|
||||
assertEquals(2, it.size)
|
||||
assertEquals(BOB_NAME.hashCode().toLong(), it.senderRecords[0].compositeKey.peerPartyId)
|
||||
assertEquals(SecureHash.sha256(BOB_NAME.toString()).toString(), it.senderRecords[0].compositeKey.peerPartyId)
|
||||
assertEquals(ALL_VISIBLE, it.senderRecords[0].statesToRecord)
|
||||
}
|
||||
transactionRecovery.queryDistributionRecords(timeWindow, recordType = DistributionRecordType.RECEIVER).let {
|
||||
assertEquals(1, it.size)
|
||||
assertEquals(BOB_NAME.hashCode().toLong(), it.receiverRecords[0].compositeKey.peerPartyId)
|
||||
assertEquals(SecureHash.sha256(BOB_NAME.toString()).toString(), it.receiverRecords[0].compositeKey.peerPartyId)
|
||||
assertEquals(ALL_VISIBLE, (HashedDistributionList.decrypt(it.receiverRecords[0].distributionList, encryptionService)).peerHashToStatesToRecord.map { it.value }[0])
|
||||
}
|
||||
val resultsAll = transactionRecovery.queryDistributionRecords(timeWindow, recordType = DistributionRecordType.ALL)
|
||||
@ -319,7 +319,7 @@ class DBTransactionStorageLedgerRecoveryTests {
|
||||
fun `test lightweight serialization and deserialization of hashed distribution list payload`() {
|
||||
val hashedDistList = HashedDistributionList(
|
||||
ALL_VISIBLE,
|
||||
mapOf(BOB.name.hashCode().toLong() to NONE, CHARLIE_NAME.hashCode().toLong() to ONLY_RELEVANT),
|
||||
mapOf(SecureHash.sha256(BOB.name.toString()) to NONE, SecureHash.sha256(CHARLIE_NAME.toString()) to ONLY_RELEVANT),
|
||||
HashedDistributionList.PublicHeader(now())
|
||||
)
|
||||
val roundtrip = HashedDistributionList.decrypt(hashedDistList.encrypt(encryptionService), encryptionService)
|
||||
|
Loading…
Reference in New Issue
Block a user