mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
ENT-1933: make NetworkParameters serialization compatible (#3234)
* ENT-1933: make NetworkParameters serialization compatible
This commit is contained in:
parent
d772bc8b7f
commit
8504b65e7b
@ -3,6 +3,7 @@ package net.corda.core.node
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.DeprecatedConstructorForDeserialization
|
||||
import net.corda.core.utilities.days
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
@ -23,7 +24,7 @@ import java.time.Instant
|
||||
* during this period
|
||||
*/
|
||||
@CordaSerializable
|
||||
data class NetworkParameters @JvmOverloads constructor(
|
||||
data class NetworkParameters(
|
||||
val minimumPlatformVersion: Int,
|
||||
val notaries: List<NotaryInfo>,
|
||||
val maxMessageSize: Int,
|
||||
@ -31,8 +32,26 @@ data class NetworkParameters @JvmOverloads constructor(
|
||||
val modifiedTime: Instant,
|
||||
val epoch: Int,
|
||||
val whitelistedContractImplementations: Map<String, List<AttachmentId>>,
|
||||
val eventHorizon: Duration = Int.MAX_VALUE.days
|
||||
val eventHorizon: Duration
|
||||
) {
|
||||
@DeprecatedConstructorForDeserialization(1)
|
||||
constructor (minimumPlatformVersion: Int,
|
||||
notaries: List<NotaryInfo>,
|
||||
maxMessageSize: Int,
|
||||
maxTransactionSize: Int,
|
||||
modifiedTime: Instant,
|
||||
epoch: Int,
|
||||
whitelistedContractImplementations: Map<String, List<AttachmentId>>
|
||||
) : this(minimumPlatformVersion,
|
||||
notaries,
|
||||
maxMessageSize,
|
||||
maxTransactionSize,
|
||||
modifiedTime,
|
||||
epoch,
|
||||
whitelistedContractImplementations,
|
||||
Int.MAX_VALUE.days
|
||||
)
|
||||
|
||||
init {
|
||||
require(minimumPlatformVersion > 0) { "minimumPlatformVersion must be at least 1" }
|
||||
require(notaries.distinctBy { it.identity } == notaries) { "Duplicate notary identities" }
|
||||
|
@ -64,7 +64,7 @@ above. A sensible default for the missing value is provided for instantiation of
|
||||
order, see the discussion below.
|
||||
|
||||
As before, instances of the class at version A will be able to deserialize serialized forms of example B as it
|
||||
will simply treat them as if the property has been removed (as from its perspective, they will have been.)
|
||||
will simply treat them as if the property has been removed (as from its perspective, they will have been).
|
||||
|
||||
|
||||
Constructor Versioning
|
||||
@ -144,7 +144,6 @@ be:
|
||||
|
||||
// The third alteration, and how it currently exists, property e added
|
||||
data class Example3 (val a: Int, val b: Int, val c: Int, val d: Int, val: Int e) {
|
||||
// NOTE: version number purposefully omitted from annotation for demonstration purposes
|
||||
@DeprecatedConstructorForDeserialization(1)
|
||||
constructor (a: Int, b: Int) : this(a, b, -1, -1, -1) // alt constructor 1
|
||||
@DeprecatedConstructorForDeserialization(2)
|
||||
|
@ -283,8 +283,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
val identityService = makeIdentityService(identity.certificate)
|
||||
|
||||
networkMapClient = configuration.networkServices?.let { NetworkMapClient(it.networkMapURL, identityService.trustRoot) }
|
||||
|
||||
val networkParameters = NetworkParametersReader(identityService.trustRoot, networkMapClient, configuration.baseDirectory).networkParameters
|
||||
val networkParameteresReader = NetworkParametersReader(identityService.trustRoot, networkMapClient, configuration.baseDirectory)
|
||||
val networkParameters = networkParameteresReader.networkParameters
|
||||
check(networkParameters.minimumPlatformVersion <= versionInfo.platformVersion) {
|
||||
"Node's platform version is lower than network's required minimumPlatformVersion"
|
||||
}
|
||||
@ -354,7 +354,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
||||
networkMapUpdater = NetworkMapUpdater(services.networkMapCache,
|
||||
NodeInfoWatcher(configuration.baseDirectory, getRxIoScheduler(), Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec)),
|
||||
networkMapClient,
|
||||
networkParameters.serialize().hash,
|
||||
networkParameteresReader.hash,
|
||||
services.myInfo.serialize().hash,
|
||||
configuration.baseDirectory,
|
||||
configuration.extraNetworkMapKeys)
|
||||
|
@ -21,11 +21,14 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
||||
private val logger = contextLogger()
|
||||
}
|
||||
|
||||
private data class NetworkParamsAndHash(val networkParameters: NetworkParameters, val hash: SecureHash)
|
||||
private val networkParamsFile = baseDirectory / NETWORK_PARAMS_FILE_NAME
|
||||
private val parametersUpdateFile = baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME
|
||||
val networkParameters by lazy { retrieveNetworkParameters() }
|
||||
private val netParamsAndHash by lazy { retrieveNetworkParameters() }
|
||||
val networkParameters get() = netParamsAndHash.networkParameters
|
||||
val hash get() = netParamsAndHash.hash
|
||||
|
||||
private fun retrieveNetworkParameters(): NetworkParameters {
|
||||
private fun retrieveNetworkParameters(): NetworkParamsAndHash {
|
||||
val advertisedParametersHash = try {
|
||||
networkMapClient?.getNetworkMap()?.payload?.networkParameterHash
|
||||
} catch (e: Exception) {
|
||||
@ -43,17 +46,17 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
||||
// on the other we have parameters update process - it needs to be unified. Say you start the node, you don't have matching parameters,
|
||||
// you get them from network map, but you have to run the approval step.
|
||||
if (signedParametersFromFile == null) { // Node joins for the first time.
|
||||
downloadParameters(trustRoot, advertisedParametersHash)
|
||||
downloadParameters(advertisedParametersHash)
|
||||
} else if (signedParametersFromFile.raw.hash == advertisedParametersHash) { // Restarted with the same parameters.
|
||||
signedParametersFromFile.verifiedNetworkMapCert(trustRoot)
|
||||
signedParametersFromFile
|
||||
} else { // Update case.
|
||||
readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash).verifiedNetworkMapCert(trustRoot)
|
||||
readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash)
|
||||
}
|
||||
} else { // No compatibility zone configured. Node should proceed with parameters from file.
|
||||
signedParametersFromFile?.verifiedNetworkMapCert(trustRoot) ?: throw IllegalArgumentException("Couldn't find network parameters file and compatibility zone wasn't configured/isn't reachable")
|
||||
signedParametersFromFile ?: throw IllegalArgumentException("Couldn't find network parameters file and compatibility zone wasn't configured/isn't reachable")
|
||||
}
|
||||
logger.info("Loaded network parameters: $parameters")
|
||||
return parameters
|
||||
return NetworkParamsAndHash(parameters.verifiedNetworkMapCert(trustRoot), parameters.raw.hash)
|
||||
}
|
||||
|
||||
private fun readParametersUpdate(advertisedParametersHash: SecureHash, previousParametersHash: SecureHash): SignedNetworkParameters {
|
||||
@ -74,14 +77,13 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
|
||||
}
|
||||
|
||||
// Used only when node joins for the first time.
|
||||
private fun downloadParameters(trustRoot: X509Certificate, parametersHash: SecureHash): NetworkParameters {
|
||||
private fun downloadParameters(parametersHash: SecureHash): SignedNetworkParameters {
|
||||
logger.info("No network-parameters file found. Expecting network parameters to be available from the network map.")
|
||||
val networkMapClient = checkNotNull(networkMapClient) {
|
||||
"Node hasn't been configured to connect to a network map from which to get the network parameters"
|
||||
}
|
||||
val signedParams = networkMapClient.getNetworkParameters(parametersHash)
|
||||
val verifiedParams = signedParams.verifiedNetworkMapCert(trustRoot)
|
||||
signedParams.serialize().open().copyTo(baseDirectory / NETWORK_PARAMS_FILE_NAME)
|
||||
return verifiedParams
|
||||
return signedParams
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ The node will shutdown now.""")
|
||||
val (update, signedNewNetParams) = requireNotNull(newNetworkParameters) { "Couldn't find parameters update for the hash: $parametersHash" }
|
||||
// We should check that we sign the right data structure hash.
|
||||
val newNetParams = signedNewNetParams.verifiedNetworkMapCert(networkMapClient.trustedRoot)
|
||||
val newParametersHash = newNetParams.serialize().hash
|
||||
val newParametersHash = signedNewNetParams.raw.hash
|
||||
if (parametersHash == newParametersHash) {
|
||||
// The latest parameters have priority.
|
||||
signedNewNetParams.serialize()
|
||||
|
@ -6,6 +6,8 @@ import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.exists
|
||||
import net.corda.core.internal.readObject
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.node.internal.NetworkParametersReader
|
||||
import net.corda.nodeapi.internal.network.*
|
||||
@ -23,6 +25,7 @@ import java.net.URL
|
||||
import java.nio.file.FileSystem
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class NetworkParametersReaderTest {
|
||||
@Rule
|
||||
@ -73,4 +76,14 @@ class NetworkParametersReaderTest {
|
||||
val parameters = NetworkParametersReader(DEV_ROOT_CA.certificate, networkMapClient, baseDirectory).networkParameters
|
||||
assertThat(parameters).isEqualTo(fileParameters)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `serialized parameters compatibility`() {
|
||||
// Network parameters file from before eventHorizon extension
|
||||
val inputStream = javaClass.classLoader.getResourceAsStream("network-compatibility/network-parameters")
|
||||
assertNotNull(inputStream)
|
||||
val inByteArray: ByteArray = inputStream.readBytes()
|
||||
val parameters = inByteArray.deserialize<SignedNetworkParameters>()
|
||||
assertThat(parameters.verified().eventHorizon).isEqualTo(Int.MAX_VALUE.days)
|
||||
}
|
||||
}
|
BIN
node/src/test/resources/network-compatibility/network-parameters
Normal file
BIN
node/src/test/resources/network-compatibility/network-parameters
Normal file
Binary file not shown.
@ -120,7 +120,7 @@ abstract class EvolutionSerializer(
|
||||
this.resultsIndex = it.index
|
||||
} ?: if (!it.value.type.isMarkedNullable) {
|
||||
throw NotSerializableException(
|
||||
"New parameter ${it.value.name} is mandatory, should be nullable for evolution to worK")
|
||||
"New parameter ${it.value.name} is mandatory, should be nullable for evolution to work")
|
||||
}
|
||||
}
|
||||
return EvolutionSerializerViaConstructor(new.type, factory, readersAsSerialized, constructor, constructorArgs)
|
||||
|
Loading…
Reference in New Issue
Block a user