Merge remote-tracking branch 'origin/release/os/4.11' into colljos/encryption_receiver_self_recovery

This commit is contained in:
Jose Coll 2023-08-22 12:31:29 +01:00
commit 32c3b0c517
15 changed files with 153 additions and 67 deletions

View File

@ -30,7 +30,7 @@ import java.util.*
class ContractUpgradeFlowTest : WithContracts, WithFinality {
companion object {
private val classMockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()))
private val classMockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP, DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()))
@JvmStatic
@AfterClass

View File

@ -40,6 +40,7 @@ import net.corda.core.utilities.unwrap
import net.corda.coretesting.internal.matchers.flow.willReturn
import net.corda.coretesting.internal.matchers.flow.willThrow
import net.corda.coretests.flows.WithFinality.FinalityInvoker
import net.corda.coretests.flows.WithFinality.OldFinalityInvoker
import net.corda.finance.GBP
import net.corda.finance.POUNDS
import net.corda.finance.contracts.asset.Cash
@ -50,6 +51,9 @@ import net.corda.finance.test.flows.CashIssueWithObserversFlow
import net.corda.finance.test.flows.CashPaymentWithObserversFlow
import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery.DBReceiverDistributionRecord
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord
import net.corda.node.services.persistence.HashedDistributionList
import net.corda.node.services.persistence.ReceiverDistributionRecord
import net.corda.node.services.persistence.SenderDistributionRecord
import net.corda.nodeapi.internal.persistence.CordaPersistence
@ -59,7 +63,6 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.CHARLIE_NAME
import net.corda.testing.core.TestIdentity
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.CustomCordapp
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP
@ -87,9 +90,7 @@ class FinalityFlowTests : WithFinality {
}
override val mockNet = InternalMockNetwork(cordappsForAllNodes = setOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP, DUMMY_CONTRACTS_CORDAPP, enclosedCordapp(),
findCordapp("net.corda.finance.test.flows"),
CustomCordapp(targetPlatformVersion = 3, classes = setOf(FinalityFlow::class.java))))
findCordapp("net.corda.finance.test.flows")))
private val aliceNode = makeNode(ALICE_NAME)
private val notary = mockNet.defaultNotaryIdentity
@ -124,7 +125,7 @@ class FinalityFlowTests : WithFinality {
val oldBob = createBob(cordapps = listOf(tokenOldCordapp()))
val stx = aliceNode.issuesCashTo(oldBob)
@Suppress("DEPRECATION")
aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture.getOrThrow()
aliceNode.startFlowAndRunNetwork(OldFinalityInvoker(stx)).resultFuture.getOrThrow()
assertThat(oldBob.services.validatedTransactions.getTransaction(stx.id)).isNotNull
}
@ -394,8 +395,10 @@ class FinalityFlowTests : WithFinality {
assertEquals(StatesToRecord.ONLY_RELEVANT, this?.statesToRecord)
assertEquals(aliceNode.info.singleIdentity().name.hashCode().toLong(), 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), this?.peersToStatesToRecord)
assertEquals(mapOf(
BOB_NAME.hashCode().toLong() to StatesToRecord.ONLY_RELEVANT,
CHARLIE_NAME.hashCode().toLong() to StatesToRecord.ALL_VISIBLE
), distList.peerHashToStatesToRecord)
}
validateSenderAndReceiverTimestamps(sdrs, rdr!!)
@ -511,6 +514,7 @@ class FinalityFlowTests : WithFinality {
}
}
@Suppress("unused")
@InitiatedBy(SpendFlow::class)
class AcceptSpendFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
@ -547,6 +551,7 @@ class FinalityFlowTests : WithFinality {
}
}
@Suppress("unused")
@InitiatedBy(SpeedySpendFlow::class)
class AcceptSpeedySpendFlow(private val otherSideSession: FlowSession) : FlowLogic<SignedTransaction>() {
@ -580,7 +585,7 @@ class FinalityFlowTests : WithFinality {
}
}
class FinaliseSpeedySpendFlow(val id: SecureHash, val sigs: List<TransactionSignature>) : FlowLogic<SignedTransaction>() {
class FinaliseSpeedySpendFlow(val id: SecureHash, private val sigs: List<TransactionSignature>) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
@ -606,6 +611,7 @@ class FinalityFlowTests : WithFinality {
}
}
@Suppress("unused")
@InitiatedBy(MimicFinalityFailureFlow::class)
class TriggerReceiveFinalityFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
@Suspendable

View File

@ -4,7 +4,13 @@ import co.paralleluniverse.fibers.Suspendable
import com.natpryce.hamkrest.MatchResult
import com.natpryce.hamkrest.Matcher
import com.natpryce.hamkrest.equalTo
import net.corda.core.flows.*
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSession
import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.ReceiveFinalityFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.core.internal.FlowStateMachineHandle
import net.corda.core.messaging.CordaRPCOps
@ -58,4 +64,13 @@ interface WithFinality : WithMockNet {
subFlow(ReceiveFinalityFlow(otherSide))
}
}
@StartableByRPC
class OldFinalityInvoker(private val transaction: SignedTransaction) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
@Suppress("DEPRECATION")
return subFlow(FinalityFlow(transaction))
}
}
}

View File

@ -219,6 +219,7 @@ class FinalityFlow private constructor(val transaction: SignedTransaction,
val requiresNotarisation = needsNotarySignature(transaction)
val useTwoPhaseFinality = serviceHub.myInfo.platformVersion >= PlatformVersionSwitches.TWO_PHASE_FINALITY
&& serviceHub.getAppContext().cordapp.targetPlatformVersion >= PlatformVersionSwitches.TWO_PHASE_FINALITY
if (useTwoPhaseFinality) {
val stxn = if (requiresNotarisation) {
@ -250,6 +251,7 @@ class FinalityFlow private constructor(val transaction: SignedTransaction,
return stxn
}
else {
logger.warnOnce("The current usage of FinalityFlow is not using Two Phase Finality. Please consider upgrading your CorDapp (refer to Corda 4.11 release notes).")
val stxn = if (requiresNotarisation) {
notarise().first
} else transaction
@ -501,6 +503,8 @@ class ReceiveFinalityFlow(private val otherSideSession: FlowSession,
val requiresNotarisation = needsNotarySignature(stx)
val fromTwoPhaseFinalityNode = serviceHub.networkMapCache.getNodeByLegalIdentity(otherSideSession.counterparty)?.platformVersion!! >= PlatformVersionSwitches.TWO_PHASE_FINALITY
&& serviceHub.getAppContext().cordapp.targetPlatformVersion >= PlatformVersionSwitches.TWO_PHASE_FINALITY
if (fromTwoPhaseFinalityNode) {
if (requiresNotarisation) {
serviceHub.telemetryServiceInternal.span("${this::class.java.name}#recordUnnotarisedTransaction", flowLogic = this) {
@ -537,6 +541,7 @@ class ReceiveFinalityFlow(private val otherSideSession: FlowSession,
otherSideSession.send(FetchDataFlow.Request.End) // Finish fetching data (deferredAck)
}
} else {
logger.warnOnce("The current usage of ReceiveFinalityFlow is not using Two Phase Finality. Please consider upgrading your CorDapp (refer to Corda 4.11 release notes).")
serviceHub.telemetryServiceInternal.span("${this::class.java.name}#recordTransactions", flowLogic = this) {
serviceHub.recordTransactions(statesToRecord, setOf(stx))
}

View File

@ -432,7 +432,7 @@ object LoggerSerializer : Serializer<Logger>() {
object ClassSerializer : Serializer<Class<*>>() {
override fun read(kryo: Kryo, input: Input, type: Class<Class<*>>): Class<*> {
val className = input.readString()
return Class.forName(className, true, kryo.classLoader)
return if (className == "void") Void.TYPE else Class.forName(className, true, kryo.classLoader)
}
override fun write(kryo: Kryo, output: Output, clazz: Class<*>) {

View File

@ -351,6 +351,20 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
assertEquals(randomHash, exception2.requested)
}
@Test(timeout=300_000)
fun `serialize - deserialize primative void`() {
val original = JavaVoidHolder()
val roundtrip = original.checkpointSerialize(context).checkpointDeserialize(context)
assertThat(roundtrip.voidClass).isEqualTo(original.voidClass)
}
class JavaVoidHolder {
val voidClass: Class<Void> = Void.TYPE
init {
check(voidClass.name == "void") // Sanity check to make sure we're dealing with the primitive void
}
}
@Test(timeout=300_000)
fun `compression has the desired effect`() {
compression ?: return
@ -373,6 +387,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
@Test(timeout=300_000)
fun `compression reduces number of bytes significantly`() {
@Suppress("unused")
class Holder(val holder: ByteArray)
val obj = Holder(ByteArray(20000))

View File

@ -36,6 +36,7 @@ class AesDbEncryptionService(private val database: CordaPersistence) : Encryptio
companion object {
private const val INITIAL_KEY_COUNT = 10
private const val UUID_BYTES = 16
private const val VERSION_TAG = 1
}
private val aesKeys = ArrayList<Pair<UUID, SecretKey>>()
@ -73,7 +74,7 @@ class AesDbEncryptionService(private val database: CordaPersistence) : Encryptio
val (keyId, aesKey) = aesKeys[newSecureRandom().nextInt(aesKeys.size)]
val ciphertext = AesEncryption.encrypt(aesKey, plaintext, additionalData)
val buffer = ByteBuffer.allocate(1 + UUID_BYTES + Integer.BYTES + (additionalData?.size ?: 0) + ciphertext.size)
buffer.put(1) // Version tag
buffer.put(VERSION_TAG.toByte())
// Prepend the key ID to the returned ciphertext. It's OK that this is not included in the authenticated additional data because
// changing this value will lead to either an non-existent key or an another key which will not be able decrypt the ciphertext.
buffer.putUUID(keyId)
@ -88,9 +89,7 @@ class AesDbEncryptionService(private val database: CordaPersistence) : Encryptio
}
override fun decrypt(ciphertext: ByteArray): EncryptionService.PlaintextAndAAD {
val buffer = ByteBuffer.wrap(ciphertext)
val version = buffer.get().toInt()
require(version == 1)
val buffer = wrap(ciphertext)
val keyId = buffer.getUUID()
val aesKey = requireNotNull(aesKeys.find { it.first == keyId }?.second) { "Unable to decrypt" }
val additionalData = buffer.getAdditionaData()
@ -100,11 +99,18 @@ class AesDbEncryptionService(private val database: CordaPersistence) : Encryptio
}
override fun extractUnauthenticatedAdditionalData(ciphertext: ByteArray): ByteArray? {
val buffer = ByteBuffer.wrap(ciphertext)
buffer.position(1 + UUID_BYTES)
val buffer = wrap(ciphertext)
buffer.position(buffer.position() + UUID_BYTES)
return buffer.getAdditionaData()
}
private fun wrap(ciphertext: ByteArray): ByteBuffer {
val buffer = ByteBuffer.wrap(ciphertext)
val version = buffer.get().toInt()
require(version == VERSION_TAG) { "Unknown version $version" }
return buffer
}
private fun ByteBuffer.getAdditionaData(): ByteArray? {
val additionalDataSize = getInt()
return if (additionalDataSize > 0) ByteArray(additionalDataSize).also { get(it) } else null

View File

@ -11,6 +11,7 @@ import net.corda.core.internal.VisibleForTesting
import net.corda.core.node.StatesToRecord
import net.corda.core.node.services.vault.Sort
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.OpaqueBytes
import net.corda.node.CordaClock
import net.corda.node.services.EncryptionService
import net.corda.node.services.network.PersistentPartyInfoCache
@ -105,8 +106,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
return ReceiverDistributionRecord(
SecureHash.parse(this.txId),
this.compositeKey.peerPartyId,
hashedDL.peerHashToStatesToRecord,
hashedDL.senderStatesToRecord,
OpaqueBytes(this.distributionList),
this.compositeKey.timestamp
)
}
@ -132,7 +132,7 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
val timestamp: Instant,
val timestampDiscriminator: Int = nextDiscriminatorNumber.andIncrement
) {
constructor(key: TimestampKey, partyId: Long): this(partyId = partyId, timestamp = key.timestamp, timestampDiscriminator = key.timestampDiscriminator)
constructor(key: TimestampKey, partyId: Long): this(partyId, key.timestamp, key.timestampDiscriminator)
companion object {
val nextDiscriminatorNumber = AtomicInteger()
}
@ -268,30 +268,34 @@ class DBTransactionStorageLedgerRecovery(private val database: CordaPersistence,
val txnMetadata = criteriaQuery.from(DBReceiverDistributionRecord::class.java)
val predicates = mutableListOf<Predicate>()
val compositeKey = txnMetadata.get<PersistentKey>("compositeKey")
predicates.add(criteriaBuilder.greaterThanOrEqualTo(compositeKey.get<Instant>(PersistentKey::timestamp.name), timeWindow.fromTime))
predicates.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(compositeKey.get<Instant>(PersistentKey::timestamp.name), timeWindow.untilTime)))
val timestamp = compositeKey.get<Instant>(PersistentKey::timestamp.name)
predicates.add(criteriaBuilder.greaterThanOrEqualTo(timestamp, timeWindow.fromTime))
predicates.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(timestamp, timeWindow.untilTime)))
if (excludingTxnIds.isNotEmpty()) {
predicates.add(criteriaBuilder.and(criteriaBuilder.not(txnMetadata.get<String>(DBSenderDistributionRecord::txId.name).`in`(
excludingTxnIds.map { it.toString() }))))
val txId = txnMetadata.get<String>(DBSenderDistributionRecord::txId.name)
predicates.add(criteriaBuilder.and(criteriaBuilder.not(txId.`in`(excludingTxnIds.map { it.toString() }))))
}
if (initiators.isNotEmpty()) {
val initiatorPartyIds = initiators.map { partyInfoCache.getPartyIdByCordaX500Name(it) }
val initiatorPartyIds = initiators.map(partyInfoCache::getPartyIdByCordaX500Name)
predicates.add(criteriaBuilder.and(compositeKey.get<Long>(PersistentKey::peerPartyId.name).`in`(initiatorPartyIds)))
}
criteriaQuery.where(*predicates.toTypedArray())
// optionally order by timestamp
orderByTimestamp?.let {
val orderCriteria =
when (orderByTimestamp) {
// when adding column position of 'group by' shift in case columns were removed
Sort.Direction.ASC -> criteriaBuilder.asc(compositeKey.get<Instant>(PersistentKey::timestamp.name))
Sort.Direction.DESC -> criteriaBuilder.desc(compositeKey.get<Instant>(PersistentKey::timestamp.name))
}
val orderCriteria = when (orderByTimestamp) {
// when adding column position of 'group by' shift in case columns were removed
Sort.Direction.ASC -> criteriaBuilder.asc(timestamp)
Sort.Direction.DESC -> criteriaBuilder.desc(timestamp)
}
criteriaQuery.orderBy(orderCriteria)
}
session.createQuery(criteriaQuery).resultList
}
}
fun decryptHashedDistributionList(encryptedBytes: ByteArray): HashedDistributionList {
return HashedDistributionList.decrypt(encryptedBytes, encryptionService)
}
}
@ -301,35 +305,33 @@ class DistributionRecords(
val receiverRecords: List<DBTransactionStorageLedgerRecovery.DBReceiverDistributionRecord> = emptyList()
) {
init {
assert(senderRecords.isNotEmpty() || receiverRecords.isNotEmpty()) { "Must set senderRecords or receiverRecords or both." }
require(senderRecords.isNotEmpty() || receiverRecords.isNotEmpty()) { "Must set senderRecords or receiverRecords or both." }
}
val size = senderRecords.size + receiverRecords.size
}
@CordaSerializable
open class DistributionRecord(
open val txId: SecureHash,
open val statesToRecord: StatesToRecord,
open val timestamp: Instant
)
abstract class DistributionRecord {
abstract val txId: SecureHash
abstract val timestamp: Instant
}
@CordaSerializable
data class SenderDistributionRecord(
override val txId: SecureHash,
val peerPartyId: Long, // CordaX500Name hashCode()
override val statesToRecord: StatesToRecord,
val statesToRecord: StatesToRecord,
override val timestamp: Instant
) : DistributionRecord(txId, statesToRecord, timestamp)
) : DistributionRecord()
@CordaSerializable
data class ReceiverDistributionRecord(
override val txId: SecureHash,
val initiatorPartyId: Long, // CordaX500Name hashCode()
val peersToStatesToRecord: Map<Long, StatesToRecord>, // CordaX500Name hashCode() -> StatesToRecord
override val statesToRecord: StatesToRecord,
val encryptedDistributionList: OpaqueBytes,
override val timestamp: Instant
) : DistributionRecord(txId, statesToRecord, timestamp)
) : DistributionRecord()
@CordaSerializable
enum class DistributionRecordType {

View File

@ -71,6 +71,7 @@ import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.internal.LogHelper
import net.corda.testing.internal.vault.VaultFiller
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.FINANCE_WORKFLOWS_CORDAPP
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.TestStartedNode
@ -140,7 +141,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
// We run this in parallel threads to help catch any race conditions that may exist. The other tests
// we run in the unit test thread exclusively to speed things up, ensure deterministic results and
// allow interruption half way through.
mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP), threadPerNode = true)
mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP), threadPerNode = true)
val notaryNode = mockNet.defaultNotaryNode
val notary = mockNet.defaultNotaryIdentity
notaryNode.services.ledger(notary) {
@ -247,7 +248,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test(timeout=300_000)
fun `shutdown and restore`() {
Assume.assumeTrue(!IS_OPENJ9)
mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP))
mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP))
val notaryNode = mockNet.defaultNotaryNode
val notary = mockNet.defaultNotaryIdentity
notaryNode.services.ledger(notary) {

View File

@ -13,6 +13,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.issuedBy
import net.corda.testing.node.internal.CustomCordapp
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.startFlow
@ -23,7 +24,8 @@ import rx.schedulers.Schedulers
import java.util.concurrent.CountDownLatch
class ServiceHubConcurrentUsageTest {
private val mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP))
private val mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP,
CustomCordapp(classes = setOf(TestFlow::class.java))))
@After
fun stopNodes() {

View File

@ -75,7 +75,9 @@ class TimedFlowTests {
@JvmStatic
fun setup() {
mockNet = InternalMockNetwork(
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()),
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP,
CustomCordapp(classes = setOf(FinalityFlow::class.java)),
enclosedCordapp()),
defaultParameters = MockNetworkParameters().withServicePeerAllocationStrategy(InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin()),
threadPerNode = true
)

View File

@ -24,6 +24,8 @@ import net.corda.node.services.network.PersistentNetworkMapCache
import net.corda.node.services.network.PersistentPartyInfoCache
import net.corda.node.services.persistence.DBTransactionStorage.TransactionStatus.IN_FLIGHT
import net.corda.node.services.persistence.DBTransactionStorage.TransactionStatus.VERIFIED
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery.DBReceiverDistributionRecord
import net.corda.node.services.persistence.DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord
import net.corda.nodeapi.internal.DEV_ROOT_CA
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
@ -260,11 +262,12 @@ class DBTransactionStorageLedgerRecoveryTests {
transactionRecovery.addReceiverTransactionRecoveryMetadata(receiverTransaction.id, ALICE_NAME,
TransactionMetadata(ALICE_NAME, ReceiverDistributionList(encryptedDL, ALL_VISIBLE)))
assertEquals(IN_FLIGHT, readTransactionFromDB(receiverTransaction.id).status)
readReceiverDistributionRecordFromDB(receiverTransaction.id).let {
assertEquals(ONLY_RELEVANT, it.statesToRecord)
assertEquals(ALL_VISIBLE, it.peersToStatesToRecord.map { it.value }[0])
assertEquals(ALICE_NAME, partyInfoCache.getCordaX500NameByPartyId(it.initiatorPartyId))
assertEquals(setOf(BOB_NAME), it.peersToStatesToRecord.map { (peer, _) -> partyInfoCache.getCordaX500NameByPartyId(peer) }.toSet() )
readReceiverDistributionRecordFromDB(receiverTransaction.id).let { record ->
val distList = transactionRecovery.decryptHashedDistributionList(record.encryptedDistributionList.bytes)
assertEquals(ONLY_RELEVANT, distList.senderStatesToRecord)
assertEquals(ALL_VISIBLE, distList.peerHashToStatesToRecord.values.first())
assertEquals(ALICE_NAME, partyInfoCache.getCordaX500NameByPartyId(record.initiatorPartyId))
assertEquals(setOf(BOB_NAME), distList.peerHashToStatesToRecord.map { (peer) -> partyInfoCache.getCordaX500NameByPartyId(peer) }.toSet() )
}
}
@ -323,7 +326,7 @@ class DBTransactionStorageLedgerRecoveryTests {
assertThat(roundtrip).isEqualTo(hashedDistList)
}
private fun readTransactionFromDB(id: SecureHash): DBTransactionStorage.DBTransaction {
private fun readTransactionFromDB(txId: SecureHash): DBTransactionStorage.DBTransaction {
val fromDb = database.transaction {
session.createQuery(
"from ${DBTransactionStorage.DBTransaction::class.java.name} where txId = :transactionId",
@ -334,22 +337,22 @@ class DBTransactionStorageLedgerRecoveryTests {
return fromDb[0]
}
private fun readSenderDistributionRecordFromDB(id: SecureHash? = null): List<SenderDistributionRecord> {
private fun readSenderDistributionRecordFromDB(txId: SecureHash? = null): List<SenderDistributionRecord> {
return database.transaction {
if (id != null)
if (txId != null)
session.createQuery(
"from ${DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord::class.java.name} where txId = :transactionId",
DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord::class.java
).setParameter("transactionId", id.toString()).resultList.map { it.toSenderDistributionRecord() }
"from ${DBSenderDistributionRecord::class.java.name} where txId = :transactionId",
DBSenderDistributionRecord::class.java
).setParameter("transactionId", txId.toString()).resultList.map { it.toSenderDistributionRecord() }
else
session.createQuery(
"from ${DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord::class.java.name}",
DBTransactionStorageLedgerRecovery.DBSenderDistributionRecord::class.java
"from ${DBSenderDistributionRecord::class.java.name}",
DBSenderDistributionRecord::class.java
).resultList.map { it.toSenderDistributionRecord() }
}
}
private fun readReceiverDistributionRecordFromDB(id: SecureHash): ReceiverDistributionRecord {
private fun readReceiverDistributionRecordFromDB(txId: SecureHash): ReceiverDistributionRecord {
val fromDb = database.transaction {
session.createQuery(
"from ${DBTransactionStorageLedgerRecovery.DBReceiverDistributionRecord::class.java.name} where txId = :transactionId",

View File

@ -58,6 +58,7 @@ import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.internal.CustomCordapp
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.InternalMockNetwork
@ -124,7 +125,7 @@ class FlowFrameworkTests {
@Before
fun setUpMockNet() {
mockNet = InternalMockNetwork(
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, FINANCE_CONTRACTS_CORDAPP),
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, FINANCE_CONTRACTS_CORDAPP, CustomCordapp(setOf("net.corda.node.services.statemachine"))),
servicePeerAllocationStrategy = RoundRobin()
)

View File

@ -1,10 +1,10 @@
apply plugin: 'kotlin'
//apply plugin: 'net.corda.plugins.cordapp'
apply plugin: 'net.corda.plugins.cordapp'
//apply plugin: 'net.corda.plugins.quasar-utils'
dependencies {
compile project(":core")
compile project(':finance:workflows')
cordaCompile project(":core")
cordapp project(':finance:workflows')
}
jar {
@ -14,4 +14,18 @@ jar {
// Driver will not include it as part of an out-of-process node.
attributes('Corda-Testing': true)
}
}
cordapp {
targetPlatformVersion corda_platform_version.toInteger()
minimumPlatformVersion 1
workflow {
name "Corda Cash Observers Test CorDapp"
versionId 1
vendor "R3"
licence "Open Source (Apache 2)"
}
signing {
enabled false
}
}

View File

@ -1,10 +1,10 @@
apply plugin: 'kotlin'
//apply plugin: 'net.corda.plugins.cordapp'
apply plugin: 'net.corda.plugins.cordapp'
//apply plugin: 'net.corda.plugins.quasar-utils'
dependencies {
compile project(":core")
compile project(":testing:cordapps:dbfailure:dbfcontracts")
cordaCompile project(":core")
cordapp project(":testing:cordapps:dbfailure:dbfcontracts")
}
jar {
@ -14,4 +14,18 @@ jar {
// Driver will not include it as part of an out-of-process node.
attributes('Corda-Testing': true)
}
}
cordapp {
targetPlatformVersion corda_platform_version.toInteger()
minimumPlatformVersion 1
workflow {
name "Corda DB Failure Test CorDapp"
versionId 1
vendor "R3"
licence "Open Source (Apache 2)"
}
signing {
enabled false
}
}