mirror of
https://github.com/corda/corda.git
synced 2025-04-28 06:49:55 +00:00
Kdoc/comment updates (#2626)
This commit is contained in:
parent
98a6c71480
commit
d70cd26a7c
@ -76,7 +76,8 @@ class SwapIdentitiesFlow(private val otherParty: Party,
|
||||
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, revocationEnabled)
|
||||
val serializedIdentity = SerializedBytes<PartyAndCertificate>(legalIdentityAnonymous.serialize().bytes)
|
||||
|
||||
// Special case that if we're both parties, a single identity is generated
|
||||
// Special case that if we're both parties, a single identity is generated.
|
||||
// TODO: for increased privacy, we should create one anonymous key per output state.
|
||||
val identities = LinkedHashMap<Party, AnonymousParty>()
|
||||
if (serviceHub.myInfo.isLegalIdentity(otherParty)) {
|
||||
identities.put(otherParty, legalIdentityAnonymous.party.anonymise())
|
||||
|
@ -24,9 +24,7 @@ import java.security.cert.X509Certificate
|
||||
// also note that IDs are numbered from 1 upwards, matching numbering of other enum types in ASN.1 specifications.
|
||||
// TODO: Link to the specification once it has a permanent URL
|
||||
enum class CertRole(val validParents: NonEmptySet<CertRole?>, val isIdentity: Boolean, val isWellKnown: Boolean) : ASN1Encodable {
|
||||
/**
|
||||
* Intermediate CA (Doorman service).
|
||||
*/
|
||||
/** Intermediate CA (Doorman service). */
|
||||
INTERMEDIATE_CA(NonEmptySet.of(null), false, false),
|
||||
/** Signing certificate for the network map. */
|
||||
NETWORK_MAP(NonEmptySet.of(null), false, false),
|
||||
@ -37,6 +35,10 @@ enum class CertRole(val validParents: NonEmptySet<CertRole?>, val isIdentity: Bo
|
||||
/** Transport layer security certificate for a node. */
|
||||
TLS(NonEmptySet.of(NODE_CA), false, false),
|
||||
/** Well known (publicly visible) identity of a legal entity. */
|
||||
// TODO: at the moment, Legal Identity certs are issued by Node CA only. However, [INTERMEDIATE_CA] is also added
|
||||
// as a valid parent of [LEGAL_IDENTITY] for backwards compatibility purposes (eg. if we decide TLS has its
|
||||
// own Root CA and Intermediate CA directly issues Legal Identities; thus, there won't be a requirement for
|
||||
// Node CA). Consider removing [INTERMEDIATE_CA] from [validParents] when the model is finalised.
|
||||
LEGAL_IDENTITY(NonEmptySet.of(INTERMEDIATE_CA, NODE_CA), true, true),
|
||||
/** Confidential (limited visibility) identity of a legal entity. */
|
||||
CONFIDENTIAL_LEGAL_IDENTITY(NonEmptySet.of(LEGAL_IDENTITY), true, false);
|
||||
|
@ -6,13 +6,14 @@ import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.messaging.DataFeed
|
||||
import net.corda.core.node.services.vault.PageSpecification
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.node.services.vault.Sort
|
||||
import net.corda.core.node.services.Vault.StateStatus
|
||||
import net.corda.core.node.services.vault.*
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import rx.Observable
|
||||
import java.time.Instant
|
||||
@ -110,15 +111,15 @@ class Vault<out T : ContractState>(val states: Iterable<StateAndRef<T>>) {
|
||||
/**
|
||||
* Returned in queries [VaultService.queryBy] and [VaultService.trackBy].
|
||||
* A Page contains:
|
||||
* 1) a [List] of actual [StateAndRef] requested by the specified [QueryCriteria] to a maximum of [MAX_PAGE_SIZE]
|
||||
* 2) a [List] of associated [Vault.StateMetadata], one per [StateAndRef] result
|
||||
* 3) a total number of states that met the given [QueryCriteria] if a [PageSpecification] was provided
|
||||
* (otherwise defaults to -1)
|
||||
* 4) Status types used in this query: UNCONSUMED, CONSUMED, ALL
|
||||
* 5) Other results as a [List] of any type (eg. aggregate function results with/without group by)
|
||||
* 1) a [List] of actual [StateAndRef] requested by the specified [QueryCriteria] to a maximum of [MAX_PAGE_SIZE].
|
||||
* 2) a [List] of associated [Vault.StateMetadata], one per [StateAndRef] result.
|
||||
* 3) a total number of states that met the given [QueryCriteria] if a [PageSpecification] was provided,
|
||||
* otherwise it defaults to -1.
|
||||
* 4) Status types used in this query: [StateStatus.UNCONSUMED], [StateStatus.CONSUMED], [StateStatus.ALL].
|
||||
* 5) Other results as a [List] of any type (eg. aggregate function results with/without group by).
|
||||
*
|
||||
* Note: currently otherResults are used only for Aggregate Functions (in which case, the states and statesMetadata
|
||||
* results will be empty)
|
||||
* results will be empty).
|
||||
*/
|
||||
@CordaSerializable
|
||||
data class Page<out T : ContractState>(val states: List<StateAndRef<T>>,
|
||||
@ -158,17 +159,18 @@ interface VaultService {
|
||||
/**
|
||||
* Prefer the use of [updates] unless you know why you want to use this instead.
|
||||
*
|
||||
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the Vault will already incorporate
|
||||
* the update, and the database transaction associated with the update will still be open and current. If for some
|
||||
* reason the processing crosses outside of the database transaction (for example, the update is pushed outside the current
|
||||
* JVM or across to another [Thread] which is executing in a different database transaction) then the Vault may
|
||||
* not incorporate the update due to racing with committing the current database transaction.
|
||||
* Get a synchronous [Observable] of updates. When observations are pushed to the Observer, the [Vault] will already
|
||||
* incorporate the update, and the database transaction associated with the update will still be open and current.
|
||||
* If for some reason the processing crosses outside of the database transaction (for example, the update is pushed
|
||||
* outside the current JVM or across to another [Thread], which is executing in a different database transaction),
|
||||
* then the [Vault] may not incorporate the update due to racing with committing the current database transaction.
|
||||
*/
|
||||
val rawUpdates: Observable<Vault.Update<ContractState>>
|
||||
|
||||
/**
|
||||
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the Vault will already incorporate
|
||||
* the update, and the database transaction associated with the update will have been committed and closed.
|
||||
* Get a synchronous [Observable] of updates. When observations are pushed to the Observer, the [Vault] will
|
||||
* already incorporate the update and the database transaction associated with the update will have been committed
|
||||
* and closed.
|
||||
*/
|
||||
val updates: Observable<Vault.Update<ContractState>>
|
||||
|
||||
@ -180,10 +182,10 @@ interface VaultService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a note to an existing [LedgerTransaction] given by its unique [SecureHash] id
|
||||
* Add a note to an existing [LedgerTransaction] given by its unique [SecureHash] id.
|
||||
* Multiple notes may be attached to the same [LedgerTransaction].
|
||||
* These are additively and immutably persisted within the node local vault database in a single textual field
|
||||
* using a semi-colon separator
|
||||
* These are additively and immutably persisted within the node local vault database in a single textual field.
|
||||
* using a semi-colon separator.
|
||||
*/
|
||||
fun addNoteToTransaction(txnId: SecureHash, noteText: String)
|
||||
|
||||
@ -192,7 +194,7 @@ interface VaultService {
|
||||
// DOCEND VaultStatesQuery
|
||||
|
||||
/**
|
||||
* Soft locking is used to prevent multiple transactions trying to use the same output simultaneously.
|
||||
* Soft locking is used to prevent multiple transactions trying to use the same states simultaneously.
|
||||
* Violation of a soft lock would result in a double spend being created and rejected by the notary.
|
||||
*/
|
||||
|
||||
@ -200,35 +202,35 @@ interface VaultService {
|
||||
|
||||
/**
|
||||
* Reserve a set of [StateRef] for a given [UUID] unique identifier.
|
||||
* Typically, the unique identifier will refer to a [FlowLogic.runId.uuid] associated with an in-flight flow.
|
||||
* Typically, the unique identifier will refer to a [FlowLogic.runId]'s [UUID] associated with an in-flight flow.
|
||||
* In this case if the flow terminates the locks will automatically be freed, even if there is an error.
|
||||
* However, the user can specify their own [UUID] and manage this manually, possibly across the lifetime of multiple flows,
|
||||
* or from other thread contexts e.g. [CordaService] instances.
|
||||
* However, the user can specify their own [UUID] and manage this manually, possibly across the lifetime of multiple
|
||||
* flows, or from other thread contexts e.g. [CordaService] instances.
|
||||
* In the case of coin selection, soft locks are automatically taken upon gathering relevant unconsumed input refs.
|
||||
*
|
||||
* @throws [StatesNotAvailableException] when not possible to softLock all of requested [StateRef]
|
||||
* @throws [StatesNotAvailableException] when not possible to soft-lock all of requested [StateRef].
|
||||
*/
|
||||
@Throws(StatesNotAvailableException::class)
|
||||
fun softLockReserve(lockId: UUID, stateRefs: NonEmptySet<StateRef>)
|
||||
|
||||
/**
|
||||
* Release all or an explicitly specified set of [StateRef] for a given [UUID] unique identifier.
|
||||
* A vault soft lock manager is automatically notified of a Flows that are terminated, such that any soft locked states
|
||||
* may be released.
|
||||
* In the case of coin selection, softLock are automatically released once previously gathered unconsumed input refs
|
||||
* are consumed as part of cash spending.
|
||||
* A [Vault] soft-lock manager is automatically notified from flows that are terminated, such that any soft locked
|
||||
* states may be released.
|
||||
* In the case of coin selection, soft-locks are automatically released once previously gathered unconsumed
|
||||
* input refs are consumed as part of cash spending.
|
||||
*/
|
||||
fun softLockRelease(lockId: UUID, stateRefs: NonEmptySet<StateRef>? = null)
|
||||
// DOCEND SoftLockAPI
|
||||
|
||||
/**
|
||||
* Helper function to determine spendable states and soft locking them.
|
||||
* Currently performance will be worse than for the hand optimised version in `Cash.unconsumedCashStatesForSpending`
|
||||
* Currently performance will be worse than for the hand optimised version in `Cash.unconsumedCashStatesForSpending`.
|
||||
* However, this is fully generic and can operate with custom [FungibleAsset] states.
|
||||
* @param lockId The [FlowLogic.runId.uuid] of the current flow used to soft lock the states.
|
||||
* @param lockId The [FlowLogic.runId]'s [UUID] of the current flow used to soft lock the states.
|
||||
* @param eligibleStatesQuery A custom query object that selects down to the appropriate subset of all states of the
|
||||
* [contractStateType]. e.g. by selecting on account, issuer, etc. The query is internally augmented with the UNCONSUMED,
|
||||
* soft lock and contract type requirements.
|
||||
* [contractStateType]. e.g. by selecting on account, issuer, etc. The query is internally augmented with the
|
||||
* [StateStatus.UNCONSUMED], soft lock and contract type requirements.
|
||||
* @param amount The required amount of the asset, but with the issuer stripped off.
|
||||
* It is assumed that compatible issuer states will be filtered out by the [eligibleStatesQuery].
|
||||
* @param contractStateType class type of the result set.
|
||||
@ -249,12 +251,12 @@ interface VaultService {
|
||||
* and returns a [Vault.Page] object containing the following:
|
||||
* 1. states as a List of <StateAndRef> (page number and size defined by [PageSpecification])
|
||||
* 2. states metadata as a List of [Vault.StateMetadata] held in the Vault States table.
|
||||
* 3. total number of results available if [PageSpecification] supplied (otherwise returns -1)
|
||||
* 4. status types used in this query: UNCONSUMED, CONSUMED, ALL
|
||||
* 5. other results (aggregate functions with/without using value groups)
|
||||
* 3. total number of results available if [PageSpecification] supplied (otherwise returns -1).
|
||||
* 4. status types used in this query: [StateStatus.UNCONSUMED], [StateStatus.CONSUMED], [StateStatus.ALL].
|
||||
* 5. other results (aggregate functions with/without using value groups).
|
||||
*
|
||||
* @throws VaultQueryException if the query cannot be executed for any reason
|
||||
* (missing criteria or parsing error, paging errors, unsupported query, underlying database error)
|
||||
* (missing criteria or parsing error, paging errors, unsupported query, underlying database error).
|
||||
*
|
||||
* Notes
|
||||
* If no [PageSpecification] is provided, a maximum of [DEFAULT_PAGE_SIZE] results will be returned.
|
||||
@ -271,11 +273,11 @@ interface VaultService {
|
||||
/**
|
||||
* Generic vault query function which takes a [QueryCriteria] object to define filters,
|
||||
* optional [PageSpecification] and optional [Sort] modification criteria (default unsorted),
|
||||
* and returns a [Vault.PageAndUpdates] object containing
|
||||
* 1) a snapshot as a [Vault.Page] (described previously in [queryBy])
|
||||
* 2) an [Observable] of [Vault.Update]
|
||||
* and returns a [DataFeed] object containing:
|
||||
* 1) a snapshot as a [Vault.Page] (described previously in [queryBy]).
|
||||
* 2) an [Observable] of [Vault.Update].
|
||||
*
|
||||
* @throws VaultQueryException if the query cannot be executed for any reason
|
||||
* @throws VaultQueryException if the query cannot be executed for any reason.
|
||||
*
|
||||
* Notes: the snapshot part of the query adheres to the same behaviour as the [queryBy] function.
|
||||
* the [QueryCriteria] applies to both snapshot and deltas (streaming updates).
|
||||
@ -287,8 +289,8 @@ interface VaultService {
|
||||
contractStateType: Class<out T>): DataFeed<Vault.Page<T>, Vault.Update<T>>
|
||||
// DOCEND VaultQueryAPI
|
||||
|
||||
// Note: cannot apply @JvmOverloads to interfaces nor interface implementations
|
||||
// Java Helpers
|
||||
// Note: cannot apply @JvmOverloads to interfaces nor interface implementations.
|
||||
// Java Helpers.
|
||||
fun <T : ContractState> queryBy(contractStateType: Class<out T>): Vault.Page<T> {
|
||||
return _queryBy(QueryCriteria.VaultQueryCriteria(), PageSpecification(), Sort(emptySet()), contractStateType)
|
||||
}
|
||||
|
@ -400,6 +400,6 @@ data class LedgerTransaction @JvmOverloads constructor(
|
||||
notary: Party?,
|
||||
timeWindow: TimeWindow?,
|
||||
privacySalt: PrivacySalt
|
||||
) = copy(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, null)
|
||||
) = copy(inputs = inputs, outputs = outputs, commands = commands, attachments = attachments, id = id, notary = notary, timeWindow = timeWindow, privacySalt = privacySalt, networkParameters = null)
|
||||
}
|
||||
|
||||
|
@ -85,18 +85,18 @@ abstract class TraversableTransaction(open val componentGroups: List<ComponentGr
|
||||
val signersList = deserialiseComponentGroup(ComponentGroupEnum.SIGNERS_GROUP, { SerializedBytes<List<PublicKey>>(it).deserialize() })
|
||||
val commandDataList = deserialiseComponentGroup(ComponentGroupEnum.COMMANDS_GROUP, { SerializedBytes<CommandData>(it).deserialize(context = SerializationFactory.defaultFactory.defaultContext.withAttachmentsClassLoader(attachments)) })
|
||||
val group = componentGroups.firstOrNull { it.groupIndex == ComponentGroupEnum.COMMANDS_GROUP.ordinal }
|
||||
if (group is FilteredComponentGroup) {
|
||||
return if (group is FilteredComponentGroup) {
|
||||
check(commandDataList.size <= signersList.size) { "Invalid Transaction. Less Signers (${signersList.size}) than CommandData (${commandDataList.size}) objects" }
|
||||
val componentHashes = group.components.mapIndexed { index, component -> componentHash(group.nonces[index], component) }
|
||||
val leafIndices = componentHashes.map { group.partialMerkleTree.leafIndex(it) }
|
||||
if (leafIndices.isNotEmpty())
|
||||
check(leafIndices.max()!! < signersList.size) { "Invalid Transaction. A command with no corresponding signer detected" }
|
||||
return commandDataList.mapIndexed { index, commandData -> Command(commandData, signersList[leafIndices[index]]) }
|
||||
commandDataList.mapIndexed { index, commandData -> Command(commandData, signersList[leafIndices[index]]) }
|
||||
} else {
|
||||
// It is a WireTransaction
|
||||
// or a FilteredTransaction with no Commands (in which case group is null).
|
||||
check(commandDataList.size == signersList.size) { "Invalid Transaction. Sizes of CommandData (${commandDataList.size}) and Signers (${signersList.size}) do not match" }
|
||||
return commandDataList.mapIndexed { index, commandData -> Command(commandData, signersList[index]) }
|
||||
commandDataList.mapIndexed { index, commandData -> Command(commandData, signersList[index]) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,9 +148,9 @@ class FilteredTransaction internal constructor(
|
||||
// As all of the helper Map structures, like availableComponentNonces, availableComponentHashes
|
||||
// and groupsMerkleRoots, are computed lazily via componentGroups.forEach, there should always be
|
||||
// a match on Map.get ensuring it will never return null.
|
||||
filteredSerialisedComponents.put(componentGroupIndex, mutableListOf(serialisedComponent))
|
||||
filteredComponentNonces.put(componentGroupIndex, mutableListOf(wtx.availableComponentNonces[componentGroupIndex]!![internalIndex]))
|
||||
filteredComponentHashes.put(componentGroupIndex, mutableListOf(wtx.availableComponentHashes[componentGroupIndex]!![internalIndex]))
|
||||
filteredSerialisedComponents[componentGroupIndex] = mutableListOf(serialisedComponent)
|
||||
filteredComponentNonces[componentGroupIndex] = mutableListOf(wtx.availableComponentNonces[componentGroupIndex]!![internalIndex])
|
||||
filteredComponentHashes[componentGroupIndex] = mutableListOf(wtx.availableComponentHashes[componentGroupIndex]!![internalIndex])
|
||||
} else {
|
||||
group.add(serialisedComponent)
|
||||
// If the group[componentGroupIndex] existed, then we guarantee that
|
||||
@ -165,9 +165,9 @@ class FilteredTransaction internal constructor(
|
||||
val signersGroupIndex = ComponentGroupEnum.SIGNERS_GROUP.ordinal
|
||||
// There exist commands, thus the signers group is not empty.
|
||||
val signersGroupComponents = wtx.componentGroups.first { it.groupIndex == signersGroupIndex }
|
||||
filteredSerialisedComponents.put(signersGroupIndex, signersGroupComponents.components.toMutableList())
|
||||
filteredComponentNonces.put(signersGroupIndex, wtx.availableComponentNonces[signersGroupIndex]!!.toMutableList())
|
||||
filteredComponentHashes.put(signersGroupIndex, wtx.availableComponentHashes[signersGroupIndex]!!.toMutableList())
|
||||
filteredSerialisedComponents[signersGroupIndex] = signersGroupComponents.components.toMutableList()
|
||||
filteredComponentNonces[signersGroupIndex] = wtx.availableComponentNonces[signersGroupIndex]!!.toMutableList()
|
||||
filteredComponentHashes[signersGroupIndex] = wtx.availableComponentHashes[signersGroupIndex]!!.toMutableList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -312,14 +312,14 @@ class FilteredTransaction internal constructor(
|
||||
.filter { signers -> publicKey in signers }.size
|
||||
}
|
||||
|
||||
inline private fun verificationCheck(value: Boolean, lazyMessage: () -> Any) {
|
||||
private inline fun verificationCheck(value: Boolean, lazyMessage: () -> Any) {
|
||||
if (!value) {
|
||||
val message = lazyMessage()
|
||||
throw FilteredTransactionVerificationException(id, message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
inline private fun visibilityCheck(value: Boolean, lazyMessage: () -> Any) {
|
||||
private inline fun visibilityCheck(value: Boolean, lazyMessage: () -> Any) {
|
||||
if (!value) {
|
||||
val message = lazyMessage()
|
||||
throw ComponentVisibilityException(id, message.toString())
|
||||
|
@ -102,7 +102,7 @@ open class TransactionBuilder(
|
||||
// with an explicit [AttachmentConstraint]
|
||||
val resolvedOutputs = outputs.map { state ->
|
||||
when {
|
||||
state.constraint !is AutomaticHashConstraint -> state
|
||||
state.constraint !== AutomaticHashConstraint -> state
|
||||
useWhitelistedByZoneAttachmentConstraint(state.contract, services.networkParameters) -> state.copy(constraint = WhitelistedByZoneAttachmentConstraint)
|
||||
else -> services.cordappProvider.getContractAttachmentID(state.contract)?.let {
|
||||
state.copy(constraint = HashAttachmentConstraint(it))
|
||||
|
@ -17,26 +17,37 @@ sealed class ConnectionDirection {
|
||||
) : ConnectionDirection()
|
||||
}
|
||||
|
||||
/** Class to set Artemis TCP configuration options. */
|
||||
class ArtemisTcpTransport {
|
||||
companion object {
|
||||
const val VERIFY_PEER_LEGAL_NAME = "corda.verifyPeerCommonName"
|
||||
|
||||
// Restrict enabled TLS cipher suites to:
|
||||
// AES128 using Galois/Counter Mode (GCM) for the block cipher being used to encrypt the message stream.
|
||||
// SHA256 as message authentication algorithm.
|
||||
// ECDHE as key exchange algorithm. DHE is also supported if one wants to completely avoid the use of ECC for TLS.
|
||||
// ECDSA and RSA for digital signatures. Our self-generated certificates all use ECDSA for handshakes,
|
||||
// but we allow classical RSA certificates to work in case:
|
||||
// a) we need to use keytool certificates in some demos,
|
||||
// b) we use cloud providers or HSMs that do not support ECC.
|
||||
/**
|
||||
* Corda supported TLS schemes.
|
||||
* <p><ul>
|
||||
* <li>TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
* <li>TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
* <li>TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
* </ul></p>
|
||||
* As shown above, current version restricts enabled TLS cipher suites to:
|
||||
* AES128 using Galois/Counter Mode (GCM) for the block cipher being used to encrypt the message stream.
|
||||
* SHA256 as message authentication algorithm.
|
||||
* Ephemeral Diffie Hellman key exchange for advanced forward secrecy. ECDHE is preferred, but DHE is also
|
||||
* supported in case one wants to completely avoid the use of ECC for TLS.
|
||||
* ECDSA and RSA for digital signatures. Our self-generated certificates all use ECDSA for handshakes,
|
||||
* but we allow classical RSA certificates to work in case one uses external tools or cloud providers or HSMs
|
||||
* that do not support ECC certificates.
|
||||
*/
|
||||
val CIPHER_SUITES = listOf(
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
)
|
||||
|
||||
/** Supported TLS versions, currently TLSv1.2 only. */
|
||||
val TLS_VERSIONS = listOf("TLSv1.2")
|
||||
|
||||
/** Specify [TransportConfiguration] for TCP communication. */
|
||||
fun tcpTransport(
|
||||
direction: ConnectionDirection,
|
||||
hostAndPort: NetworkHostAndPort,
|
||||
|
@ -44,6 +44,10 @@ data class ParametersUpdate(
|
||||
val updateDeadline: Instant
|
||||
)
|
||||
|
||||
/** Verify that a Network Map certificate is issued by Root CA and its [CertRole] is correct. */
|
||||
// TODO: Current implementation works under the assumption that there are no intermediate CAs between Root and
|
||||
// Network Map. Consider a more flexible implementation without the above assumption.
|
||||
|
||||
fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCert: X509Certificate): T {
|
||||
require(CertRole.extract(sig.by) == CertRole.NETWORK_MAP) { "Incorrect cert role: ${CertRole.extract(sig.by)}" }
|
||||
X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert)
|
||||
|
Loading…
x
Reference in New Issue
Block a user