mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Merge remote-tracking branch 'origin/release/os/4.11' into colljos/encryption_receiver_self_recovery
This commit is contained in:
commit
32c3b0c517
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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<*>) {
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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",
|
||||
|
@ -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()
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user