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 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())

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.
// 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);

View File

@ -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)
}

View File

@ -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)
}

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 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())

View File

@ -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))

View File

@ -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,

View File

@ -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)