ENT-9875: New network parameters (#7398)

* ENT-9875: Added new network parameters

- Added `transactionRecoveryPeriod`
- Added `confidentialIdentityPreGenerationPeriod`

These new parameters are currently set to be nullable meaning they can be ignored and the duration if not specified will be null rather than, e.g., 0. This currently allows for nothing changing/breaking in the node-api

_Note: if these params can stay as nullable then the deprecated constructor might not even be needed (since the existing one will still work), needs to be discussed._
This commit is contained in:
Tom Stark 2023-07-14 12:02:21 +01:00 committed by GitHub
parent 0f2312a201
commit 58ecce1713
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 10 deletions

View File

@ -30,6 +30,8 @@ import java.time.Duration
import java.time.Instant import java.time.Instant
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFails import kotlin.test.assertFails
import kotlin.test.assertNotEquals
import kotlin.test.assertNull
class NetworkParametersTest { class NetworkParametersTest {
private val mockNet = InternalMockNetwork( private val mockNet = InternalMockNetwork(
@ -93,6 +95,32 @@ class NetworkParametersTest {
assertEquals(twoDays, nm2.eventHorizon) assertEquals(twoDays, nm2.eventHorizon)
} }
@Test(timeout=300_000)
fun `that transactionRecoveryPeriod and confidentialIdentityPreGenerationPeriod aren't required`() {
// this is defensive tests in response to CORDA-2769
val aliceNotaryParty = TestIdentity(ALICE_NAME).party
val aliceNotaryInfo = NotaryInfo(aliceNotaryParty, false)
val nm1 = NetworkParameters(
minimumPlatformVersion = 1,
notaries = listOf(aliceNotaryInfo),
maxMessageSize = Int.MAX_VALUE,
maxTransactionSize = Int.MAX_VALUE,
modifiedTime = Instant.now(),
epoch = 1,
whitelistedContractImplementations = mapOf("MyClass" to listOf(AttachmentId.allOnesHash)),
eventHorizon = Duration.ofDays(1)
)
assertNull(nm1.recoveryMaximumBackupInterval)
assertNull(nm1.confidentialIdentityMinimumBackupInterval)
val nm2 = nm1.copy(recoveryMaximumBackupInterval = 10.days, confidentialIdentityMinimumBackupInterval = 10.days)
assertNotEquals(nm1.recoveryMaximumBackupInterval, nm2.recoveryMaximumBackupInterval)
assertNotEquals(nm1.confidentialIdentityMinimumBackupInterval, nm2.confidentialIdentityMinimumBackupInterval)
}
// Notaries tests // Notaries tests
@Test(timeout=300_000) @Test(timeout=300_000)
fun `choosing notary not specified in network parameters will fail`() { fun `choosing notary not specified in network parameters will fail`() {

View File

@ -34,10 +34,19 @@ import java.util.Collections.unmodifiableMap
* @property packageOwnership ([AutoAcceptable]) List of the network-wide java packages that were successfully claimed by their owners. * @property packageOwnership ([AutoAcceptable]) List of the network-wide java packages that were successfully claimed by their owners.
* Any CorDapp JAR that offers contracts and states in any of these packages must be signed by the owner. * Any CorDapp JAR that offers contracts and states in any of these packages must be signed by the owner.
* @property eventHorizon Time after which nodes will be removed from the network map if they have not been seen * @property eventHorizon Time after which nodes will be removed from the network map if they have not been seen
* during this period * during this period.
* @property recoveryMaximumBackupInterval A default value, that will be used by the Ledger Recovery flows to set how far back in time to
* consider for recovery. The expectation is that a node will restore to a database backup that is no older than this, by default, when
* attempting a recovery. This value can be overridden by specifying an override to the flow. It can also be overridden if the same parameter
* is specified, per-node in the node configuration. An override to the flow takes priority in terms of overrides. It is optional in both
* the network parameters and the node configuration however if no values are set then it needs to be specified in the flow.
* @property confidentialIdentityMinimumBackupInterval A default value for the minimum age of a generated confidential identity key before
* it can be used. This can be overridden in the node configuration or if a more recent database backup is indicated via RPC / shell. It is
* optional in both the network parameters and the node configuration and if no value is set for either then it is assumed to be zero.
*/ */
@KeepForDJVM @KeepForDJVM
@CordaSerializable @CordaSerializable
@Suppress("LongParameterList")
data class NetworkParameters( data class NetworkParameters(
val minimumPlatformVersion: Int, val minimumPlatformVersion: Int,
val notaries: List<NotaryInfo>, val notaries: List<NotaryInfo>,
@ -47,10 +56,12 @@ data class NetworkParameters(
@AutoAcceptable val epoch: Int, @AutoAcceptable val epoch: Int,
@AutoAcceptable val whitelistedContractImplementations: Map<String, List<AttachmentId>>, @AutoAcceptable val whitelistedContractImplementations: Map<String, List<AttachmentId>>,
val eventHorizon: Duration, val eventHorizon: Duration,
@AutoAcceptable val packageOwnership: Map<String, PublicKey> @AutoAcceptable val packageOwnership: Map<String, PublicKey>,
val recoveryMaximumBackupInterval: Duration? = null,
val confidentialIdentityMinimumBackupInterval: Duration? = null
) { ) {
// DOCEND 1 // DOCEND 1
@DeprecatedConstructorForDeserialization(1) @DeprecatedConstructorForDeserialization(version = 1)
constructor(minimumPlatformVersion: Int, constructor(minimumPlatformVersion: Int,
notaries: List<NotaryInfo>, notaries: List<NotaryInfo>,
maxMessageSize: Int, maxMessageSize: Int,
@ -69,7 +80,7 @@ data class NetworkParameters(
emptyMap() emptyMap()
) )
@DeprecatedConstructorForDeserialization(2) @DeprecatedConstructorForDeserialization(version = 2)
constructor(minimumPlatformVersion: Int, constructor(minimumPlatformVersion: Int,
notaries: List<NotaryInfo>, notaries: List<NotaryInfo>,
maxMessageSize: Int, maxMessageSize: Int,
@ -89,6 +100,29 @@ data class NetworkParameters(
emptyMap() emptyMap()
) )
@DeprecatedConstructorForDeserialization(version = 3)
constructor(minimumPlatformVersion: Int,
notaries: List<NotaryInfo>,
maxMessageSize: Int,
maxTransactionSize: Int,
modifiedTime: Instant,
epoch: Int,
whitelistedContractImplementations: Map<String, List<AttachmentId>>,
eventHorizon: Duration,
packageOwnership: Map<String, PublicKey>
) : this(minimumPlatformVersion,
notaries,
maxMessageSize,
maxTransactionSize,
modifiedTime,
epoch,
whitelistedContractImplementations,
eventHorizon,
packageOwnership,
recoveryMaximumBackupInterval = null,
confidentialIdentityMinimumBackupInterval = null
)
init { init {
require(minimumPlatformVersion > 0) { "Minimum platform level must be at least 1" } require(minimumPlatformVersion > 0) { "Minimum platform level must be at least 1" }
require(notaries.distinctBy { it.identity } == notaries) { "Duplicate notary identities" } require(notaries.distinctBy { it.identity } == notaries) { "Duplicate notary identities" }
@ -98,6 +132,41 @@ data class NetworkParameters(
require(!eventHorizon.isNegative) { "Event Horizon must be a positive value" } require(!eventHorizon.isNegative) { "Event Horizon must be a positive value" }
packageOwnership.keys.forEach(::requirePackageValid) packageOwnership.keys.forEach(::requirePackageValid)
require(noPackageOverlap(packageOwnership.keys)) { "Multiple packages added to the packageOwnership overlap." } require(noPackageOverlap(packageOwnership.keys)) { "Multiple packages added to the packageOwnership overlap." }
require(recoveryMaximumBackupInterval == null || !recoveryMaximumBackupInterval.isNegative) {
"Recovery maximum backup interval must be a positive value"
}
require(confidentialIdentityMinimumBackupInterval == null || !confidentialIdentityMinimumBackupInterval.isNegative) {
"Confidential Identities maximum backup interval must be a positive value"
}
}
/**
* This is to address backwards compatibility of the API, invariant to package ownership
* addresses bug CORDA-2769
*/
fun copy(minimumPlatformVersion: Int = this.minimumPlatformVersion,
notaries: List<NotaryInfo> = this.notaries,
maxMessageSize: Int = this.maxMessageSize,
maxTransactionSize: Int = this.maxTransactionSize,
modifiedTime: Instant = this.modifiedTime,
epoch: Int = this.epoch,
whitelistedContractImplementations: Map<String, List<AttachmentId>> = this.whitelistedContractImplementations,
eventHorizon: Duration = this.eventHorizon,
packageOwnership: Map<String, PublicKey> = this.packageOwnership
): NetworkParameters {
return NetworkParameters(
minimumPlatformVersion = minimumPlatformVersion,
notaries = notaries,
maxMessageSize = maxMessageSize,
maxTransactionSize = maxTransactionSize,
modifiedTime = modifiedTime,
epoch = epoch,
whitelistedContractImplementations = whitelistedContractImplementations,
eventHorizon = eventHorizon,
packageOwnership = packageOwnership,
recoveryMaximumBackupInterval = recoveryMaximumBackupInterval,
confidentialIdentityMinimumBackupInterval = confidentialIdentityMinimumBackupInterval
)
} }
/** /**
@ -122,7 +191,9 @@ data class NetworkParameters(
epoch = epoch, epoch = epoch,
whitelistedContractImplementations = whitelistedContractImplementations, whitelistedContractImplementations = whitelistedContractImplementations,
eventHorizon = eventHorizon, eventHorizon = eventHorizon,
packageOwnership = packageOwnership packageOwnership = packageOwnership,
recoveryMaximumBackupInterval = recoveryMaximumBackupInterval,
confidentialIdentityMinimumBackupInterval = confidentialIdentityMinimumBackupInterval
) )
} }
@ -147,7 +218,9 @@ data class NetworkParameters(
epoch = epoch, epoch = epoch,
whitelistedContractImplementations = whitelistedContractImplementations, whitelistedContractImplementations = whitelistedContractImplementations,
eventHorizon = eventHorizon, eventHorizon = eventHorizon,
packageOwnership = packageOwnership packageOwnership = packageOwnership,
recoveryMaximumBackupInterval = recoveryMaximumBackupInterval,
confidentialIdentityMinimumBackupInterval = confidentialIdentityMinimumBackupInterval
) )
} }
@ -166,6 +239,8 @@ data class NetworkParameters(
} }
modifiedTime=$modifiedTime modifiedTime=$modifiedTime
epoch=$epoch epoch=$epoch
transactionRecoveryPeriod=$recoveryMaximumBackupInterval
confidentialIdentityPreGenerationPeriod=$confidentialIdentityMinimumBackupInterval
}""" }"""
} }
@ -181,7 +256,9 @@ data class NetworkParameters(
unmodifiableList(entry.value) unmodifiableList(entry.value)
}, },
eventHorizon = eventHorizon, eventHorizon = eventHorizon,
packageOwnership = unmodifiable(packageOwnership) packageOwnership = unmodifiable(packageOwnership),
recoveryMaximumBackupInterval = recoveryMaximumBackupInterval,
confidentialIdentityMinimumBackupInterval = confidentialIdentityMinimumBackupInterval
) )
} }
} }

View File

@ -7,6 +7,7 @@ import net.corda.core.messaging.ParametersUpdateInfo
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.days
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.SignedNodeInfo
@ -76,7 +77,11 @@ class NetworkMapTest {
val nextParams = networkMapServer.networkParameters.copy( val nextParams = networkMapServer.networkParameters.copy(
epoch = 3, epoch = 3,
modifiedTime = Instant.ofEpochMilli(random63BitValue()), modifiedTime = Instant.ofEpochMilli(random63BitValue()),
maxMessageSize = networkMapServer.networkParameters.maxMessageSize + 1) maxMessageSize = networkMapServer.networkParameters.maxMessageSize + 1,
recoveryMaximumBackupInterval = networkMapServer.networkParameters
.recoveryMaximumBackupInterval?.minus(10.days) ?: 10.days,
confidentialIdentityMinimumBackupInterval = networkMapServer.networkParameters
.confidentialIdentityMinimumBackupInterval?.minus(10.days) ?: 10.days)
val nextHash = nextParams.serialize().hash val nextHash = nextParams.serialize().hash
val snapshot = alice.rpc.networkParametersFeed().snapshot val snapshot = alice.rpc.networkParametersFeed().snapshot
val updates = alice.rpc.networkParametersFeed().updates.bufferUntilSubscribed() val updates = alice.rpc.networkParametersFeed().updates.bufferUntilSubscribed()

View File

@ -10,6 +10,7 @@ import java.time.Duration
import java.time.Instant import java.time.Instant
@JvmOverloads @JvmOverloads
@Suppress("LongParameterList")
fun testNetworkParameters( fun testNetworkParameters(
notaries: List<NotaryInfo> = emptyList(), notaries: List<NotaryInfo> = emptyList(),
minimumPlatformVersion: Int = 1, minimumPlatformVersion: Int = 1,
@ -20,7 +21,9 @@ fun testNetworkParameters(
whitelistedContractImplementations: Map<String, List<AttachmentId>> = emptyMap(), whitelistedContractImplementations: Map<String, List<AttachmentId>> = emptyMap(),
epoch: Int = 1, epoch: Int = 1,
eventHorizon: Duration = 30.days, eventHorizon: Duration = 30.days,
packageOwnership: Map<String, PublicKey> = emptyMap() packageOwnership: Map<String, PublicKey> = emptyMap(),
recoveryMaximumBackupInterval: Duration = 30.days,
confidentialIdentityMinimumBackupInterval: Duration = 30.days
): NetworkParameters { ): NetworkParameters {
return NetworkParameters( return NetworkParameters(
minimumPlatformVersion = minimumPlatformVersion, minimumPlatformVersion = minimumPlatformVersion,
@ -31,7 +34,9 @@ fun testNetworkParameters(
epoch = epoch, epoch = epoch,
whitelistedContractImplementations = whitelistedContractImplementations, whitelistedContractImplementations = whitelistedContractImplementations,
eventHorizon = eventHorizon, eventHorizon = eventHorizon,
packageOwnership = packageOwnership packageOwnership = packageOwnership,
recoveryMaximumBackupInterval = recoveryMaximumBackupInterval,
confidentialIdentityMinimumBackupInterval = confidentialIdentityMinimumBackupInterval
) )
} }