mirror of
https://github.com/corda/corda.git
synced 2025-01-30 16:14:39 +00:00
CORDA-2520: Add FetchParametersFlow (#4674)
* CORDA-2520: Add FetchParametersFlow * Address comments, add test
This commit is contained in:
parent
88e4b85537
commit
6efd54fce1
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<T : Any>(val raw: SerializedBytes<T>, val sig: DigitalSignatureWithCert) {
|
||||
class SignedDataWithCert<T : Any>(val raw: SerializedBytes<T>, val sig: DigitalSignatureWithCert): NamedByHash {
|
||||
override val id: SecureHash get () = raw.hash
|
||||
|
||||
fun verified(): T {
|
||||
sig.verify(raw)
|
||||
return uncheckedCast(raw.deserialize<Any>())
|
||||
|
@ -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<T : NamedByHash, in W : Any>(
|
||||
|
||||
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<T : NamedByHash, in W : Any>(
|
||||
|
||||
@CordaSerializable
|
||||
enum class DataType {
|
||||
TRANSACTION, ATTACHMENT
|
||||
TRANSACTION, ATTACHMENT, PARAMETERS
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
@Throws(HashNotFound::class)
|
||||
@Throws(HashNotFound::class, MissingNetworkParameters::class)
|
||||
override fun call(): Result<T> {
|
||||
// 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<T : NamedByHash, in W : Any>(
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<SecureHash>,
|
||||
@ -158,10 +161,10 @@ class FetchAttachmentsFlow(requests: Set<SecureHash>,
|
||||
} 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<SecureHash>, 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<SecureHash>,
|
||||
otherSide: FlowSession) : FetchDataFlow<SignedDataWithCert<NetworkParameters>, SignedDataWithCert<NetworkParameters>>(requests, otherSide, DataType.PARAMETERS) {
|
||||
override fun load(txid: SecureHash): SignedDataWithCert<NetworkParameters>? {
|
||||
return (serviceHub.networkParametersService as NetworkParametersStorage).lookupSigned(txid)
|
||||
}
|
||||
|
||||
override fun maybeWriteToDisk(downloaded: List<SignedDataWithCert<NetworkParameters>>) {
|
||||
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." }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<NetworkParameters>?
|
||||
|
||||
/**
|
||||
* 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<NetworkParameters>)
|
||||
|
||||
/**
|
||||
* Set information that given parameters are current parameters for the network.
|
||||
*/
|
||||
fun setCurrentParameters(currentSignedParameters: SignedDataWithCert<NetworkParameters>, trustRoot: X509Certificate)
|
||||
}
|
||||
|
@ -77,6 +77,8 @@ class ResolveTransactionsFlow(txHashesArg: Set<SecureHash>,
|
||||
@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<SignedTransaction>(txHashes.size)
|
||||
// Start fetching data.
|
||||
for (pageNumber in 0..(txHashes.size - 1) / RESOLUTION_PAGE_SIZE) {
|
||||
@ -85,6 +87,11 @@ class ResolveTransactionsFlow(txHashesArg: Set<SecureHash>,
|
||||
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<SecureHash>,
|
||||
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<SignedTransaction>) {
|
||||
val parameters = downloads.mapNotNull { it.networkParametersHash }
|
||||
val missingParameters = parameters.filter { !(serviceHub.networkParametersService as NetworkParametersStorage).hasParameters(it) }
|
||||
if (missingParameters.isNotEmpty())
|
||||
subFlow(FetchNetworkParametersFlow(missingParameters.toSet(), otherSide))
|
||||
}
|
||||
}
|
||||
|
@ -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<SignedTransaction, SignedTransaction> {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Unit>() {
|
||||
open class TestFlow(val otherSide: Party, private val resolveTransactionsFlowFactory: (FlowSession) -> ResolveTransactionsFlow, private val txCountLimit: Int? = null) : FlowLogic<Unit>() {
|
||||
constructor(txHashes: Set<SecureHash>, 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<Void?>() {
|
||||
class TestResponseFlow(val otherSideSession: FlowSession) : FlowLogic<Void?>() {
|
||||
@Suspendable
|
||||
override fun call() = subFlow(TestNoSecurityDataVendingFlow(otherSideSession))
|
||||
}
|
||||
|
@ -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<NetworkParameters>)
|
||||
|
||||
fun setCurrentParameters(currentSignedParameters: SignedDataWithCert<NetworkParameters>, 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<NetworkParameters>? {
|
||||
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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<SecureHash, NetworkParameters> = HashMap()
|
||||
private val hashToSignedParametersMap: HashMap<SecureHash, SignedNetworkParameters> = HashMap()
|
||||
|
||||
init {
|
||||
storeCurrentParameters()
|
||||
@ -29,6 +31,12 @@ class MockNetworkParametersStorage(private var currentParameters: NetworkParamet
|
||||
setCurrentParametersUnverified(currentSignedParameters.verifiedNetworkMapCert(trustRoot))
|
||||
}
|
||||
|
||||
override fun lookupSigned(hash: SecureHash): SignedDataWithCert<NetworkParameters>? {
|
||||
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? {
|
||||
|
Loading…
x
Reference in New Issue
Block a user