Kdoc/comment updates (#2626)

This commit is contained in:
Konstantinos Chalkias 2018-03-08 10:52:07 +00:00 committed by GitHub
parent 98a6c71480
commit d70cd26a7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 68 deletions

View File

@ -76,7 +76,8 @@ class SwapIdentitiesFlow(private val otherParty: Party,
val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, revocationEnabled) val legalIdentityAnonymous = serviceHub.keyManagementService.freshKeyAndCert(ourIdentityAndCert, revocationEnabled)
val serializedIdentity = SerializedBytes<PartyAndCertificate>(legalIdentityAnonymous.serialize().bytes) 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>() val identities = LinkedHashMap<Party, AnonymousParty>()
if (serviceHub.myInfo.isLegalIdentity(otherParty)) { if (serviceHub.myInfo.isLegalIdentity(otherParty)) {
identities.put(otherParty, legalIdentityAnonymous.party.anonymise()) identities.put(otherParty, legalIdentityAnonymous.party.anonymise())

View File

@ -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. // 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 // 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 { 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), INTERMEDIATE_CA(NonEmptySet.of(null), false, false),
/** Signing certificate for the network map. */ /** Signing certificate for the network map. */
NETWORK_MAP(NonEmptySet.of(null), false, false), 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. */ /** Transport layer security certificate for a node. */
TLS(NonEmptySet.of(NODE_CA), false, false), TLS(NonEmptySet.of(NODE_CA), false, false),
/** Well known (publicly visible) identity of a legal entity. */ /** 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), LEGAL_IDENTITY(NonEmptySet.of(INTERMEDIATE_CA, NODE_CA), true, true),
/** Confidential (limited visibility) identity of a legal entity. */ /** Confidential (limited visibility) identity of a legal entity. */
CONFIDENTIAL_LEGAL_IDENTITY(NonEmptySet.of(LEGAL_IDENTITY), true, false); CONFIDENTIAL_LEGAL_IDENTITY(NonEmptySet.of(LEGAL_IDENTITY), true, false);

View File

@ -6,13 +6,14 @@ import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.messaging.DataFeed import net.corda.core.messaging.DataFeed
import net.corda.core.node.services.vault.PageSpecification import net.corda.core.node.services.Vault.StateStatus
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.*
import net.corda.core.node.services.vault.Sort
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.toFuture import net.corda.core.toFuture
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.utilities.NonEmptySet import net.corda.core.utilities.NonEmptySet
import rx.Observable import rx.Observable
import java.time.Instant 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]. * Returned in queries [VaultService.queryBy] and [VaultService.trackBy].
* A Page contains: * A Page contains:
* 1) a [List] of actual [StateAndRef] requested by the specified [QueryCriteria] to a maximum of [MAX_PAGE_SIZE] * 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 * 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 * 3) a total number of states that met the given [QueryCriteria] if a [PageSpecification] was provided,
* (otherwise defaults to -1) * otherwise it defaults to -1.
* 4) Status types used in this query: UNCONSUMED, CONSUMED, ALL * 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) * 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 * 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 @CordaSerializable
data class Page<out T : ContractState>(val states: List<StateAndRef<T>>, 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. * 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 * Get a synchronous [Observable] of updates. When observations are pushed to the Observer, the [Vault] will already
* the update, and the database transaction associated with the update will still be open and current. If for some * incorporate the update, and the database transaction associated with the update will still be open and current.
* reason the processing crosses outside of the database transaction (for example, the update is pushed outside the current * If for some reason the processing crosses outside of the database transaction (for example, the update is pushed
* JVM or across to another [Thread] which is executing in a different database transaction) then the Vault may * outside the current JVM or across to another [Thread], which is executing in a different database transaction),
* not incorporate the update due to racing with committing the current 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>> val rawUpdates: Observable<Vault.Update<ContractState>>
/** /**
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the Vault will already incorporate * Get a synchronous [Observable] of updates. When observations are pushed to the Observer, the [Vault] will
* the update, and the database transaction associated with the update will have been committed and closed. * already incorporate the update and the database transaction associated with the update will have been committed
* and closed.
*/ */
val updates: Observable<Vault.Update<ContractState>> 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]. * 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 * These are additively and immutably persisted within the node local vault database in a single textual field.
* using a semi-colon separator * using a semi-colon separator.
*/ */
fun addNoteToTransaction(txnId: SecureHash, noteText: String) fun addNoteToTransaction(txnId: SecureHash, noteText: String)
@ -192,7 +194,7 @@ interface VaultService {
// DOCEND VaultStatesQuery // 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. * 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. * 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. * 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, * However, the user can specify their own [UUID] and manage this manually, possibly across the lifetime of multiple
* or from other thread contexts e.g. [CordaService] instances. * 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. * 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) @Throws(StatesNotAvailableException::class)
fun softLockReserve(lockId: UUID, stateRefs: NonEmptySet<StateRef>) fun softLockReserve(lockId: UUID, stateRefs: NonEmptySet<StateRef>)
/** /**
* Release all or an explicitly specified set of [StateRef] for a given [UUID] unique identifier. * 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 * A [Vault] soft-lock manager is automatically notified from flows that are terminated, such that any soft locked
* may be released. * states may be released.
* In the case of coin selection, softLock are automatically released once previously gathered unconsumed input refs * In the case of coin selection, soft-locks are automatically released once previously gathered unconsumed
* are consumed as part of cash spending. * input refs are consumed as part of cash spending.
*/ */
fun softLockRelease(lockId: UUID, stateRefs: NonEmptySet<StateRef>? = null) fun softLockRelease(lockId: UUID, stateRefs: NonEmptySet<StateRef>? = null)
// DOCEND SoftLockAPI // DOCEND SoftLockAPI
/** /**
* Helper function to determine spendable states and soft locking them. * 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. * 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 * @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, * [contractStateType]. e.g. by selecting on account, issuer, etc. The query is internally augmented with the
* soft lock and contract type requirements. * [StateStatus.UNCONSUMED], soft lock and contract type requirements.
* @param amount The required amount of the asset, but with the issuer stripped off. * @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]. * It is assumed that compatible issuer states will be filtered out by the [eligibleStatesQuery].
* @param contractStateType class type of the result set. * @param contractStateType class type of the result set.
@ -249,12 +251,12 @@ interface VaultService {
* and returns a [Vault.Page] object containing the following: * and returns a [Vault.Page] object containing the following:
* 1. states as a List of <StateAndRef> (page number and size defined by [PageSpecification]) * 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. * 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) * 3. total number of results available if [PageSpecification] supplied (otherwise returns -1).
* 4. status types used in this query: UNCONSUMED, CONSUMED, ALL * 4. status types used in this query: [StateStatus.UNCONSUMED], [StateStatus.CONSUMED], [StateStatus.ALL].
* 5. other results (aggregate functions with/without using value groups) * 5. other results (aggregate functions with/without using value groups).
* *
* @throws VaultQueryException if the query cannot be executed for any reason * @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 * Notes
* If no [PageSpecification] is provided, a maximum of [DEFAULT_PAGE_SIZE] results will be returned. * 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, * Generic vault query function which takes a [QueryCriteria] object to define filters,
* optional [PageSpecification] and optional [Sort] modification criteria (default unsorted), * optional [PageSpecification] and optional [Sort] modification criteria (default unsorted),
* and returns a [Vault.PageAndUpdates] object containing * and returns a [DataFeed] object containing:
* 1) a snapshot as a [Vault.Page] (described previously in [queryBy]) * 1) a snapshot as a [Vault.Page] (described previously in [queryBy]).
* 2) an [Observable] of [Vault.Update] * 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. * 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). * 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>> contractStateType: Class<out T>): DataFeed<Vault.Page<T>, Vault.Update<T>>
// DOCEND VaultQueryAPI // DOCEND VaultQueryAPI
// Note: cannot apply @JvmOverloads to interfaces nor interface implementations // Note: cannot apply @JvmOverloads to interfaces nor interface implementations.
// Java Helpers // Java Helpers.
fun <T : ContractState> queryBy(contractStateType: Class<out T>): Vault.Page<T> { fun <T : ContractState> queryBy(contractStateType: Class<out T>): Vault.Page<T> {
return _queryBy(QueryCriteria.VaultQueryCriteria(), PageSpecification(), Sort(emptySet()), contractStateType) return _queryBy(QueryCriteria.VaultQueryCriteria(), PageSpecification(), Sort(emptySet()), contractStateType)
} }

View File

@ -400,6 +400,6 @@ data class LedgerTransaction @JvmOverloads constructor(
notary: Party?, notary: Party?,
timeWindow: TimeWindow?, timeWindow: TimeWindow?,
privacySalt: PrivacySalt 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)
} }

View File

@ -85,18 +85,18 @@ abstract class TraversableTransaction(open val componentGroups: List<ComponentGr
val signersList = deserialiseComponentGroup(ComponentGroupEnum.SIGNERS_GROUP, { SerializedBytes<List<PublicKey>>(it).deserialize() }) 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 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 } 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" } 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 componentHashes = group.components.mapIndexed { index, component -> componentHash(group.nonces[index], component) }
val leafIndices = componentHashes.map { group.partialMerkleTree.leafIndex(it) } val leafIndices = componentHashes.map { group.partialMerkleTree.leafIndex(it) }
if (leafIndices.isNotEmpty()) if (leafIndices.isNotEmpty())
check(leafIndices.max()!! < signersList.size) { "Invalid Transaction. A command with no corresponding signer detected" } 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 { } else {
// It is a WireTransaction // It is a WireTransaction
// or a FilteredTransaction with no Commands (in which case group is null). // 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" } 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 // As all of the helper Map structures, like availableComponentNonces, availableComponentHashes
// and groupsMerkleRoots, are computed lazily via componentGroups.forEach, there should always be // and groupsMerkleRoots, are computed lazily via componentGroups.forEach, there should always be
// a match on Map.get ensuring it will never return null. // a match on Map.get ensuring it will never return null.
filteredSerialisedComponents.put(componentGroupIndex, mutableListOf(serialisedComponent)) filteredSerialisedComponents[componentGroupIndex] = mutableListOf(serialisedComponent)
filteredComponentNonces.put(componentGroupIndex, mutableListOf(wtx.availableComponentNonces[componentGroupIndex]!![internalIndex])) filteredComponentNonces[componentGroupIndex] = mutableListOf(wtx.availableComponentNonces[componentGroupIndex]!![internalIndex])
filteredComponentHashes.put(componentGroupIndex, mutableListOf(wtx.availableComponentHashes[componentGroupIndex]!![internalIndex])) filteredComponentHashes[componentGroupIndex] = mutableListOf(wtx.availableComponentHashes[componentGroupIndex]!![internalIndex])
} else { } else {
group.add(serialisedComponent) group.add(serialisedComponent)
// If the group[componentGroupIndex] existed, then we guarantee that // If the group[componentGroupIndex] existed, then we guarantee that
@ -165,9 +165,9 @@ class FilteredTransaction internal constructor(
val signersGroupIndex = ComponentGroupEnum.SIGNERS_GROUP.ordinal val signersGroupIndex = ComponentGroupEnum.SIGNERS_GROUP.ordinal
// There exist commands, thus the signers group is not empty. // There exist commands, thus the signers group is not empty.
val signersGroupComponents = wtx.componentGroups.first { it.groupIndex == signersGroupIndex } val signersGroupComponents = wtx.componentGroups.first { it.groupIndex == signersGroupIndex }
filteredSerialisedComponents.put(signersGroupIndex, signersGroupComponents.components.toMutableList()) filteredSerialisedComponents[signersGroupIndex] = signersGroupComponents.components.toMutableList()
filteredComponentNonces.put(signersGroupIndex, wtx.availableComponentNonces[signersGroupIndex]!!.toMutableList()) filteredComponentNonces[signersGroupIndex] = wtx.availableComponentNonces[signersGroupIndex]!!.toMutableList()
filteredComponentHashes.put(signersGroupIndex, wtx.availableComponentHashes[signersGroupIndex]!!.toMutableList()) filteredComponentHashes[signersGroupIndex] = wtx.availableComponentHashes[signersGroupIndex]!!.toMutableList()
} }
} }
} }
@ -312,14 +312,14 @@ class FilteredTransaction internal constructor(
.filter { signers -> publicKey in signers }.size .filter { signers -> publicKey in signers }.size
} }
inline private fun verificationCheck(value: Boolean, lazyMessage: () -> Any) { private inline fun verificationCheck(value: Boolean, lazyMessage: () -> Any) {
if (!value) { if (!value) {
val message = lazyMessage() val message = lazyMessage()
throw FilteredTransactionVerificationException(id, message.toString()) throw FilteredTransactionVerificationException(id, message.toString())
} }
} }
inline private fun visibilityCheck(value: Boolean, lazyMessage: () -> Any) { private inline fun visibilityCheck(value: Boolean, lazyMessage: () -> Any) {
if (!value) { if (!value) {
val message = lazyMessage() val message = lazyMessage()
throw ComponentVisibilityException(id, message.toString()) throw ComponentVisibilityException(id, message.toString())

View File

@ -102,7 +102,7 @@ open class TransactionBuilder(
// with an explicit [AttachmentConstraint] // with an explicit [AttachmentConstraint]
val resolvedOutputs = outputs.map { state -> val resolvedOutputs = outputs.map { state ->
when { when {
state.constraint !is AutomaticHashConstraint -> state state.constraint !== AutomaticHashConstraint -> state
useWhitelistedByZoneAttachmentConstraint(state.contract, services.networkParameters) -> state.copy(constraint = WhitelistedByZoneAttachmentConstraint) useWhitelistedByZoneAttachmentConstraint(state.contract, services.networkParameters) -> state.copy(constraint = WhitelistedByZoneAttachmentConstraint)
else -> services.cordappProvider.getContractAttachmentID(state.contract)?.let { else -> services.cordappProvider.getContractAttachmentID(state.contract)?.let {
state.copy(constraint = HashAttachmentConstraint(it)) state.copy(constraint = HashAttachmentConstraint(it))

View File

@ -17,26 +17,37 @@ sealed class ConnectionDirection {
) : ConnectionDirection() ) : ConnectionDirection()
} }
/** Class to set Artemis TCP configuration options. */
class ArtemisTcpTransport { class ArtemisTcpTransport {
companion object { companion object {
const val VERIFY_PEER_LEGAL_NAME = "corda.verifyPeerCommonName" 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. * Corda supported TLS schemes.
// SHA256 as message authentication algorithm. * <p><ul>
// ECDHE as key exchange algorithm. DHE is also supported if one wants to completely avoid the use of ECC for TLS. * <li>TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
// ECDSA and RSA for digital signatures. Our self-generated certificates all use ECDSA for handshakes, * <li>TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
// but we allow classical RSA certificates to work in case: * <li>TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
// a) we need to use keytool certificates in some demos, * </ul></p>
// b) we use cloud providers or HSMs that do not support ECC. * 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( val CIPHER_SUITES = listOf(
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_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") val TLS_VERSIONS = listOf("TLSv1.2")
/** Specify [TransportConfiguration] for TCP communication. */
fun tcpTransport( fun tcpTransport(
direction: ConnectionDirection, direction: ConnectionDirection,
hostAndPort: NetworkHostAndPort, hostAndPort: NetworkHostAndPort,

View File

@ -44,6 +44,10 @@ data class ParametersUpdate(
val updateDeadline: Instant 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 { fun <T : Any> SignedDataWithCert<T>.verifiedNetworkMapCert(rootCert: X509Certificate): T {
require(CertRole.extract(sig.by) == CertRole.NETWORK_MAP) { "Incorrect cert role: ${CertRole.extract(sig.by)}" } require(CertRole.extract(sig.by) == CertRole.NETWORK_MAP) { "Incorrect cert role: ${CertRole.extract(sig.by)}" }
X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert) X509Utilities.validateCertificateChain(rootCert, sig.by, rootCert)