diff --git a/core/src/main/kotlin/net/corda/core/flows/NotaryFlow.kt b/core/src/main/kotlin/net/corda/core/flows/NotaryFlow.kt index 915ac30f58..5ef32b478d 100644 --- a/core/src/main/kotlin/net/corda/core/flows/NotaryFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/NotaryFlow.kt @@ -8,12 +8,9 @@ import net.corda.core.contracts.TimeWindow import net.corda.core.crypto.SecureHash import net.corda.core.crypto.TransactionSignature import net.corda.core.identity.Party -import net.corda.core.internal.BackpressureAwareTimedFlow -import net.corda.core.internal.FetchDataFlow -import net.corda.core.internal.NetworkParametersServiceInternal +import net.corda.core.internal.* import net.corda.core.internal.notary.generateSignature import net.corda.core.internal.notary.validateSignatures -import net.corda.core.internal.pushToLoggingContext import net.corda.core.transactions.* import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.UntrustworthyData @@ -107,7 +104,7 @@ class NotaryFlow { check(stx.coreTransaction is NotaryChangeWireTransaction) { "Notary $notaryParty is not on the network parameter whitelist. A non-whitelisted notary can only be used for notary change transactions" } - val historicNotary = (serviceHub.networkParametersService as NetworkParametersServiceInternal).getHistoricNotary(notaryParty) + val historicNotary = (serviceHub.networkParametersService as NetworkParametersStorage).getHistoricNotary(notaryParty) ?: throw IllegalStateException("The notary party $notaryParty specified by transaction ${stx.id}, is not recognised as a current or historic notary.") historicNotary.validating diff --git a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt index 0da13b1ea9..b9a9b5b480 100644 --- a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt @@ -3,9 +3,7 @@ package net.corda.core.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.StateAndRef import net.corda.core.crypto.SecureHash -import net.corda.core.internal.FetchDataFlow -import net.corda.core.internal.RetrieveAnyTransactionPayload -import net.corda.core.internal.readFully +import net.corda.core.internal.* import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap @@ -42,7 +40,7 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any) @Suspendable override fun call(): Void? { - // The first payload will be the transaction data, subsequent payload will be the transaction/attachment data. + // The first payload will be the transaction data, subsequent payload will be the transaction/attachment/network parameters data. var payload = payload // Depending on who called this flow, the type of the initial payload is different. @@ -93,6 +91,10 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any) serviceHub.attachments.openAttachment(it)?.open()?.readFully() ?: throw FetchDataFlow.HashNotFound(it) } + FetchDataFlow.DataType.PARAMETERS -> dataRequest.hashes.map { + (serviceHub.networkParametersService as NetworkParametersStorage).lookupSigned(it) + ?: throw FetchDataFlow.MissingNetworkParameters(it) + } } } } diff --git a/core/src/main/kotlin/net/corda/core/internal/DigitalSignatureWithCert.kt b/core/src/main/kotlin/net/corda/core/internal/DigitalSignatureWithCert.kt index c06cfe2e55..7e0312a9ff 100644 --- a/core/src/main/kotlin/net/corda/core/internal/DigitalSignatureWithCert.kt +++ b/core/src/main/kotlin/net/corda/core/internal/DigitalSignatureWithCert.kt @@ -1,6 +1,8 @@ package net.corda.core.internal +import net.corda.core.contracts.NamedByHash import net.corda.core.crypto.DigitalSignature +import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData import net.corda.core.crypto.verify import net.corda.core.serialization.CordaSerializable @@ -43,7 +45,9 @@ Cert path: $fullCertPath /** Similar to [SignedData] but instead of just attaching the public key, the certificate for the key is attached instead. */ @CordaSerializable -class SignedDataWithCert(val raw: SerializedBytes, val sig: DigitalSignatureWithCert) { +class SignedDataWithCert(val raw: SerializedBytes, val sig: DigitalSignatureWithCert): NamedByHash { + override val id: SecureHash get () = raw.hash + fun verified(): T { sig.verify(raw) return uncheckedCast(raw.deserialize()) diff --git a/core/src/main/kotlin/net/corda/core/internal/FetchDataFlow.kt b/core/src/main/kotlin/net/corda/core/internal/FetchDataFlow.kt index 7a0453dd1d..87ea20d428 100644 --- a/core/src/main/kotlin/net/corda/core/internal/FetchDataFlow.kt +++ b/core/src/main/kotlin/net/corda/core/internal/FetchDataFlow.kt @@ -10,6 +10,7 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSession import net.corda.core.internal.FetchDataFlow.DownloadedVsRequestedDataMismatch import net.corda.core.internal.FetchDataFlow.HashNotFound +import net.corda.core.node.NetworkParameters import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializationToken import net.corda.core.serialization.SerializeAsToken @@ -51,6 +52,8 @@ sealed class FetchDataFlow( class HashNotFound(val requested: SecureHash) : FlowException() + class MissingNetworkParameters(val requested: SecureHash) : FlowException("Failed to fetch network parameters with hash: $requested") + class IllegalTransactionRequest(val requested: SecureHash) : FlowException("Illegal attempt to request a transaction (${requested}) that is not in the transitive dependency graph of the sent transaction.") @CordaSerializable @@ -64,11 +67,11 @@ sealed class FetchDataFlow( @CordaSerializable enum class DataType { - TRANSACTION, ATTACHMENT + TRANSACTION, ATTACHMENT, PARAMETERS } @Suspendable - @Throws(HashNotFound::class) + @Throws(HashNotFound::class, MissingNetworkParameters::class) override fun call(): Result { // Load the items we have from disk and figure out which we're missing. val (fromDisk, toFetch) = loadWhatWeHave() @@ -139,7 +142,7 @@ sealed class FetchDataFlow( } /** - * Given a set of hashes either loads from from local storage or requests them from the other peer. Downloaded + * Given a set of hashes either loads from local storage or requests them from the other peer. Downloaded * attachments are saved to local storage automatically. */ class FetchAttachmentsFlow(requests: Set, @@ -158,10 +161,10 @@ class FetchAttachmentsFlow(requests: Set, } catch (e: FileAlreadyExistsException) { // This can happen when another transaction will insert the same attachment during this transaction. // The outcome is the same (the attachment is imported), so we can ignore this exception. - logger.debug("Attachment ${attachment.id} already inserted.") + logger.debug { "Attachment ${attachment.id} already inserted." } } } else { - logger.debug("Attachment ${attachment.id} already exists, skipping.") + logger.debug { "Attachment ${attachment.id} already exists, skipping." } } } } @@ -193,3 +196,28 @@ class FetchTransactionsFlow(requests: Set, otherSide: FlowSession) : override fun load(txid: SecureHash): SignedTransaction? = serviceHub.validatedTransactions.getTransaction(txid) } + +/** + * Given a set of hashes either loads from local network parameters storage or requests them from the other peer. Downloaded + * network parameters are saved to local parameters storage automatically. This flow can be used only if the minimumPlatformVersion is >= 4. + * Nodes on lower versions won't respond to this flow. + */ +class FetchNetworkParametersFlow(requests: Set, + otherSide: FlowSession) : FetchDataFlow, SignedDataWithCert>(requests, otherSide, DataType.PARAMETERS) { + override fun load(txid: SecureHash): SignedDataWithCert? { + return (serviceHub.networkParametersService as NetworkParametersStorage).lookupSigned(txid) + } + + override fun maybeWriteToDisk(downloaded: List>) { + for (parameters in downloaded) { + with(serviceHub.networkParametersService as NetworkParametersStorage) { + if (!hasParameters(parameters.id)) { + // This will perform the signature check too and throws SignatureVerificationException + saveParameters(parameters) + } else { + logger.debug { "Network parameters ${parameters.id} already exists in storage, skipping." } + } + } + } + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/internal/NetworkParametersServiceInternal.kt b/core/src/main/kotlin/net/corda/core/internal/NetworkParametersServiceInternal.kt index 7aacf46edf..4b3acb2312 100644 --- a/core/src/main/kotlin/net/corda/core/internal/NetworkParametersServiceInternal.kt +++ b/core/src/main/kotlin/net/corda/core/internal/NetworkParametersServiceInternal.kt @@ -1,12 +1,44 @@ package net.corda.core.internal +import net.corda.core.crypto.SecureHash import net.corda.core.identity.Party +import net.corda.core.node.NetworkParameters import net.corda.core.node.NotaryInfo import net.corda.core.node.services.NetworkParametersService +import java.security.cert.X509Certificate + +interface NetworkParametersStorage : NetworkParametersService { + /** + * Return parameters epoch for the given parameters hash. Null if there are no parameters for this hash in the storage and we are unable to + * get them from network map. + */ + fun getEpochFromHash(hash: SecureHash): Int? + + /** + * Return signed network parameters with certificate for the given hash. Null if there are no parameters for this hash in the storage. + * (No fallback to network map.) + */ + fun lookupSigned(hash: SecureHash): SignedDataWithCert? + + /** + * Checks if parameters with given hash are in the storage. + */ + fun hasParameters(hash: SecureHash): Boolean -interface NetworkParametersServiceInternal : NetworkParametersService { /** * Returns the [NotaryInfo] for a notary [party] in the current or any historic network parameter whitelist, or null if not found. */ fun getHistoricNotary(party: Party): NotaryInfo? + + /** + * Save signed network parameters data. Internally network parameters bytes should be stored with the signature. + * It's because of ability of older nodes to function in network where parameters were extended with new fields. + * Hash should always be calculated over the serialized bytes. + */ + fun saveParameters(signedNetworkParameters: SignedDataWithCert) + + /** + * Set information that given parameters are current parameters for the network. + */ + fun setCurrentParameters(currentSignedParameters: SignedDataWithCert, trustRoot: X509Certificate) } diff --git a/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt b/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt index 5816266db2..ff8291cd0c 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/core/internal/ResolveTransactionsFlow.kt @@ -77,6 +77,8 @@ class ResolveTransactionsFlow(txHashesArg: Set, @Suspendable @Throws(FetchDataFlow.HashNotFound::class, FetchDataFlow.IllegalTransactionRequest::class) override fun call() { + val counterpartyPlatformVersion = serviceHub.networkMapCache.getNodeByLegalIdentity(otherSide.counterparty)?.platformVersion ?: + throw FlowException("Couldn't retrieve party's ${otherSide.counterparty} platform version from NetworkMapCache") val newTxns = ArrayList(txHashes.size) // Start fetching data. for (pageNumber in 0..(txHashes.size - 1) / RESOLUTION_PAGE_SIZE) { @@ -85,6 +87,11 @@ class ResolveTransactionsFlow(txHashesArg: Set, newTxns += downloadDependencies(page) val txsWithMissingAttachments = if (pageNumber == 0) signedTransaction?.let { newTxns + it } ?: newTxns else newTxns fetchMissingAttachments(txsWithMissingAttachments) + // Fetch missing parameters flow was added in version 4. This check is needed so we don't end up with node V4 sending parameters + // request to node V3 that doesn't know about this protocol. + if (counterpartyPlatformVersion >= 4) { + fetchMissingParameters(txsWithMissingAttachments) + } } otherSide.send(FetchDataFlow.Request.End) // Finish fetching data. @@ -180,4 +187,13 @@ class ResolveTransactionsFlow(txHashesArg: Set, if (missingAttachments.isNotEmpty()) subFlow(FetchAttachmentsFlow(missingAttachments.toSet(), otherSide)) } + + // TODO This can also be done in parallel. See comment to [fetchMissingAttachments] above. + @Suspendable + private fun fetchMissingParameters(downloads: List) { + val parameters = downloads.mapNotNull { it.networkParametersHash } + val missingParameters = parameters.filter { !(serviceHub.networkParametersService as NetworkParametersStorage).hasParameters(it) } + if (missingParameters.isNotEmpty()) + subFlow(FetchNetworkParametersFlow(missingParameters.toSet(), otherSide)) + } } diff --git a/core/src/test/kotlin/net/corda/core/internal/NetworkParametersResolutionTest.kt b/core/src/test/kotlin/net/corda/core/internal/NetworkParametersResolutionTest.kt new file mode 100644 index 0000000000..5383700d3c --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/internal/NetworkParametersResolutionTest.kt @@ -0,0 +1,132 @@ +package net.corda.core.internal + +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.SignableData +import net.corda.core.crypto.SignatureMetadata +import net.corda.core.identity.CordaX500Name +import net.corda.core.identity.Party +import net.corda.core.node.NetworkParameters +import net.corda.core.node.NotaryInfo +import net.corda.core.node.ServiceHub +import net.corda.core.serialization.SerializationFactory +import net.corda.core.serialization.serialize +import net.corda.core.transactions.SignedTransaction +import net.corda.core.transactions.TransactionBuilder +import net.corda.core.transactions.WireTransaction +import net.corda.core.utilities.getOrThrow +import net.corda.nodeapi.internal.createDevNetworkMapCa +import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair +import net.corda.testing.common.internal.testNetworkParameters +import net.corda.testing.contracts.DummyContract +import net.corda.testing.core.singleIdentity +import net.corda.testing.node.MockNetwork +import net.corda.testing.node.MockNetworkParameters +import net.corda.testing.node.StartedMockNode +import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP +import net.corda.testing.node.internal.cordappForClasses +import org.assertj.core.api.Assertions.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test + +class NetworkParametersResolutionTest { + private lateinit var params2: NetworkParameters + private val certKeyPair: CertificateAndKeyPair = createDevNetworkMapCa() + private lateinit var mockNet: MockNetwork + private lateinit var notaryNode: StartedMockNode + private lateinit var megaCorpNode: StartedMockNode + private lateinit var miniCorpNode: StartedMockNode + private lateinit var megaCorpParty: Party + private lateinit var miniCorpParty: Party + private lateinit var notaryParty: Party + + @Before + fun setup() { + mockNet = MockNetwork(MockNetworkParameters( + cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, cordappForClasses(ResolveTransactionsFlowTest.TestFlow::class.java, ResolveTransactionsFlowTest.TestResponseFlow::class.java)))) + notaryNode = mockNet.defaultNotaryNode + megaCorpNode = mockNet.createPartyNode(CordaX500Name("MegaCorp", "London", "GB")) + miniCorpNode = mockNet.createPartyNode(CordaX500Name("MiniCorp", "London", "GB")) + notaryParty = mockNet.defaultNotaryIdentity + megaCorpParty = megaCorpNode.info.singleIdentity() + miniCorpParty = miniCorpNode.info.singleIdentity() + params2 = testNetworkParameters(epoch = 2, minimumPlatformVersion = 3, notaries = listOf((NotaryInfo(notaryParty, true)))) + } + + @After + fun tearDown() { + mockNet.stopNodes() + } + + // This function is resolving and signing WireTransaction with special parameters. + private fun TransactionBuilder.toSignedTransactionWithParameters(parameters: NetworkParameters?, services: ServiceHub): SignedTransaction { + val wtx = toWireTransaction(services) + val wtxWithHash = SerializationFactory.defaultFactory.withCurrentContext(null) { + WireTransaction( + createComponentGroups( + wtx.inputs, + wtx.outputs, + wtx.commands, + wtx.attachments, + wtx.notary, + wtx.timeWindow, + wtx.references, + parameters?.serialize()?.hash), + wtx.privacySalt + ) + } + val publicKey = services.myInfo.singleIdentity().owningKey + val signatureMetadata = SignatureMetadata(services.myInfo.platformVersion, Crypto.findSignatureScheme(publicKey).schemeNumberID) + val signableData = SignableData(wtxWithHash.id, signatureMetadata) + val sig = services.keyManagementService.sign(signableData, publicKey) + return SignedTransaction(wtxWithHash, listOf(sig)) + } + + // Similar to ResolveTransactionsFlowTest but creates transactions with given network parameters + // First transaction in pair is dependency of the second one. + private fun makeTransactions(parameters1: NetworkParameters?, parameters2: NetworkParameters?): Pair { + // Make a chain of custody of dummy states and insert into node A. + val dummy1: SignedTransaction = DummyContract.generateInitial(0, notaryParty, megaCorpParty.ref(1)).let { + val ptx = it.toSignedTransactionWithParameters(parameters1, megaCorpNode.services) + notaryNode.services.addSignature(ptx, notaryParty.owningKey) + } + val dummy2: SignedTransaction = DummyContract.move(dummy1.tx.outRef(0), miniCorpParty).let { + val ptx = it.toSignedTransactionWithParameters(parameters2, megaCorpNode.services) + notaryNode.services.addSignature(ptx, notaryParty.owningKey) + } + megaCorpNode.transaction { + megaCorpNode.services.recordTransactions(dummy1, dummy2) + // Record parameters too. + with(megaCorpNode.services.networkParametersService as NetworkParametersStorage) { + parameters1?.let { saveParameters(certKeyPair.sign(it)) } + parameters2?.let { saveParameters(certKeyPair.sign(it)) } + } + } + return Pair(dummy1, dummy2) + } + + @Test + fun `request parameters that are not in the storage`() { + val params1 = miniCorpNode.services.networkParameters + val hash1 = params1.serialize().hash + val hash2 = params2.serialize().hash + // Create two transactions on megaCorpNode + val (stx1, stx2) = makeTransactions(params1, params2) + assertThat(stx1.networkParametersHash).isEqualTo(hash1) + assertThat(stx2.networkParametersHash).isEqualTo(hash2) + miniCorpNode.transaction { + assertThat(miniCorpNode.services.networkParametersService.lookup(hash1)).isNotNull() + assertThat(miniCorpNode.services.networkParametersService.lookup(hash2)).isNull() + } + // miniCorpNode resolves the stx2 from megaCorpParty + val p = ResolveTransactionsFlowTest.TestFlow(setOf(stx2.id), megaCorpParty) + val future = miniCorpNode.startFlow(p) + mockNet.runNetwork() + future.getOrThrow() + miniCorpNode.transaction { + // Check that parameters were downloaded to the storage. + assertThat(miniCorpNode.services.networkParametersService.lookup(hash1)).isEqualTo(params1) + assertThat(miniCorpNode.services.networkParametersService.lookup(hash2)).isEqualTo(params2) + } + } +} \ No newline at end of file diff --git a/core/src/test/kotlin/net/corda/core/internal/ResolveTransactionsFlowTest.kt b/core/src/test/kotlin/net/corda/core/internal/ResolveTransactionsFlowTest.kt index da27807e1b..98861f2399 100644 --- a/core/src/test/kotlin/net/corda/core/internal/ResolveTransactionsFlowTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/ResolveTransactionsFlowTest.kt @@ -229,7 +229,7 @@ class ResolveTransactionsFlowTest { @InitiatingFlow - private open class TestFlow(val otherSide: Party, private val resolveTransactionsFlowFactory: (FlowSession) -> ResolveTransactionsFlow, private val txCountLimit: Int? = null) : FlowLogic() { + open class TestFlow(val otherSide: Party, private val resolveTransactionsFlowFactory: (FlowSession) -> ResolveTransactionsFlow, private val txCountLimit: Int? = null) : FlowLogic() { constructor(txHashes: Set, otherSide: Party, txCountLimit: Int? = null) : this(otherSide, { ResolveTransactionsFlow(txHashes, it) }, txCountLimit = txCountLimit) constructor(stx: SignedTransaction, otherSide: Party) : this(otherSide, { ResolveTransactionsFlow(stx, it) }) @@ -243,7 +243,7 @@ class ResolveTransactionsFlowTest { } @Suppress("unused") @InitiatedBy(TestFlow::class) - private class TestResponseFlow(val otherSideSession: FlowSession) : FlowLogic() { + class TestResponseFlow(val otherSideSession: FlowSession) : FlowLogic() { @Suspendable override fun call() = subFlow(TestNoSecurityDataVendingFlow(otherSideSession)) } diff --git a/node/src/main/kotlin/net/corda/node/internal/DBNetworkParametersStorage.kt b/node/src/main/kotlin/net/corda/node/internal/DBNetworkParametersStorage.kt index 2cef9156c4..52abfb3e26 100644 --- a/node/src/main/kotlin/net/corda/node/internal/DBNetworkParametersStorage.kt +++ b/node/src/main/kotlin/net/corda/node/internal/DBNetworkParametersStorage.kt @@ -2,10 +2,7 @@ package net.corda.node.internal import net.corda.core.crypto.SecureHash import net.corda.core.identity.Party -import net.corda.core.internal.DigitalSignatureWithCert -import net.corda.core.internal.NamedCacheFactory -import net.corda.core.internal.SignedDataWithCert -import net.corda.core.internal.NetworkParametersServiceInternal +import net.corda.core.internal.* import net.corda.core.node.NetworkParameters import net.corda.core.node.NotaryInfo import net.corda.core.serialization.SerializedBytes @@ -26,23 +23,6 @@ import org.apache.commons.lang.ArrayUtils import java.security.cert.X509Certificate import javax.persistence.* -interface NetworkParametersStorage : NetworkParametersServiceInternal { - /** - * Return parameters epoch for the given parameters hash. Null if there are no parameters for this hash in the storage and we are unable to - * get them from network map. - */ - fun getEpochFromHash(hash: SecureHash): Int? - - /** - * Save signed network parameters data. Internally network parameters bytes should be stored with the signature. - * It's because of ability of older nodes to function in network where parameters were extended with new fields. - * Hash should always be calculated over the serialized bytes. - */ - fun saveParameters(signedNetworkParameters: SignedDataWithCert) - - fun setCurrentParameters(currentSignedParameters: SignedDataWithCert, trustRoot: X509Certificate) -} - class DBNetworkParametersStorage( cacheFactory: NamedCacheFactory, private val database: CordaPersistence, @@ -94,6 +74,12 @@ class DBNetworkParametersStorage( override fun getEpochFromHash(hash: SecureHash): Int? = lookup(hash)?.epoch + override fun lookupSigned(hash: SecureHash): SignedDataWithCert? { + return database.transaction { hashToParameters[hash] } + } + + override fun hasParameters(hash: SecureHash): Boolean = hash in hashToParameters + override fun saveParameters(signedNetworkParameters: SignedNetworkParameters) { log.trace { "Saving new network parameters to network parameters storage." } val networkParameters = signedNetworkParameters.verified() @@ -104,7 +90,6 @@ class DBNetworkParametersStorage( } } - // TODO For the future we could get them also as signed (by network operator) attachments on transactions. private fun tryDownloadUnknownParameters(parametersHash: SecureHash): NetworkParameters? { return if (networkMapClient != null) { try { diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt index a3e4ca8ab2..bb8cce5116 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt @@ -13,7 +13,6 @@ import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.serialize import net.corda.core.utilities.contextLogger import net.corda.core.utilities.minutes -import net.corda.node.internal.NetworkParametersStorage import net.corda.node.services.api.NetworkMapCacheInternal import net.corda.node.services.config.NetworkParameterAcceptanceSettings import net.corda.node.utilities.NamedThreadFactory diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt index 5528fd59b0..e66e22e5b9 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt @@ -18,7 +18,6 @@ import net.corda.core.node.services.AttachmentId import net.corda.core.serialization.serialize import net.corda.core.utilities.millis import net.corda.node.VersionInfo -import net.corda.node.internal.NetworkParametersStorage import net.corda.node.services.api.NetworkMapCacheInternal import net.corda.node.services.config.NetworkParameterAcceptanceSettings import net.corda.nodeapi.internal.NodeInfoAndSigned diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt index b6f425aa68..fff4e46a12 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt @@ -28,7 +28,6 @@ import net.corda.core.utilities.seconds import net.corda.node.VersionInfo import net.corda.node.internal.AbstractNode import net.corda.node.internal.InitiatedFlowFactory -import net.corda.node.internal.NetworkParametersStorage import net.corda.node.internal.NodeFlowManager import net.corda.node.services.api.FlowStarter import net.corda.node.services.api.ServiceHubInternal diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt index 497c249843..d2ef2f39a4 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt @@ -2,11 +2,12 @@ package net.corda.testing.node.internal import net.corda.core.crypto.SecureHash import net.corda.core.identity.Party +import net.corda.core.internal.NetworkParametersStorage import net.corda.core.internal.SignedDataWithCert import net.corda.core.node.NetworkParameters import net.corda.core.node.NotaryInfo import net.corda.core.serialization.serialize -import net.corda.node.internal.NetworkParametersStorage +import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.verifiedNetworkMapCert import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.internal.withTestSerializationEnvIfNotSet @@ -15,6 +16,7 @@ import java.time.Instant class MockNetworkParametersStorage(private var currentParameters: NetworkParameters = testNetworkParameters(modifiedTime = Instant.MIN)) : NetworkParametersStorage { private val hashToParametersMap: HashMap = HashMap() + private val hashToSignedParametersMap: HashMap = HashMap() init { storeCurrentParameters() @@ -29,6 +31,12 @@ class MockNetworkParametersStorage(private var currentParameters: NetworkParamet setCurrentParametersUnverified(currentSignedParameters.verifiedNetworkMapCert(trustRoot)) } + override fun lookupSigned(hash: SecureHash): SignedDataWithCert? { + return hashToSignedParametersMap[hash] + } + + override fun hasParameters(hash: SecureHash): Boolean = hash in hashToParametersMap + override val currentHash: SecureHash get() { return withTestSerializationEnvIfNotSet { @@ -42,6 +50,7 @@ class MockNetworkParametersStorage(private var currentParameters: NetworkParamet val networkParameters = signedNetworkParameters.verified() val hash = signedNetworkParameters.raw.hash hashToParametersMap[hash] = networkParameters + hashToSignedParametersMap[hash] = signedNetworkParameters } override fun getHistoricNotary(party: Party): NotaryInfo? {