diff --git a/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt b/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt index 378db88249..674b2beb3b 100644 --- a/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt +++ b/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt @@ -18,6 +18,7 @@ import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.i2p.crypto.eddsa.EdDSAPublicKey import java.math.BigDecimal +import java.security.PublicKey import java.util.* /** @@ -32,22 +33,22 @@ object JacksonSupport { interface PartyObjectMapper { fun partyFromName(partyName: String): Party? - fun partyFromKey(owningKey: CompositeKey): Party? + fun partyFromKey(owningKey: PublicKey): Party? } class RpcObjectMapper(val rpc: CordaRPCOps, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { override fun partyFromName(partyName: String): Party? = rpc.partyFromName(partyName) - override fun partyFromKey(owningKey: CompositeKey): Party? = rpc.partyFromKey(owningKey) + override fun partyFromKey(owningKey: PublicKey): Party? = rpc.partyFromKey(owningKey) } class IdentityObjectMapper(val identityService: IdentityService, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { override fun partyFromName(partyName: String): Party? = identityService.partyFromName(partyName) - override fun partyFromKey(owningKey: CompositeKey): Party? = identityService.partyFromKey(owningKey) + override fun partyFromKey(owningKey: PublicKey): Party? = identityService.partyFromKey(owningKey) } class NoPartyObjectMapper(factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { override fun partyFromName(partyName: String): Party? = throw UnsupportedOperationException() - override fun partyFromKey(owningKey: CompositeKey): Party? = throw UnsupportedOperationException() + override fun partyFromKey(owningKey: PublicKey): Party? = throw UnsupportedOperationException() } val cordaModule: Module by lazy { @@ -128,7 +129,7 @@ object JacksonSupport { } // TODO this needs to use some industry identifier(s) instead of these keys - val key = CompositeKey.parseFromBase58(parser.text) + val key = parsePublicKeyBase58(parser.text) return AnonymousParty(key) } } @@ -214,7 +215,7 @@ object JacksonSupport { object PublicKeyDeserializer : JsonDeserializer() { override fun deserialize(parser: JsonParser, context: DeserializationContext): EdDSAPublicKey { return try { - parsePublicKeyBase58(parser.text) + parsePublicKeyBase58(parser.text) as EdDSAPublicKey } catch (e: Exception) { throw JsonParseException(parser, "Invalid public key ${parser.text}: ${e.message}") } @@ -230,7 +231,7 @@ object JacksonSupport { object CompositeKeyDeserializer : JsonDeserializer() { override fun deserialize(parser: JsonParser, context: DeserializationContext): CompositeKey { return try { - CompositeKey.parseFromBase58(parser.text) + parsePublicKeyBase58(parser.text) as CompositeKey } catch (e: Exception) { throw JsonParseException(parser, "Invalid composite key ${parser.text}: ${e.message}") } diff --git a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt index 48df7516b1..c7cc700f70 100644 --- a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt +++ b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt @@ -6,6 +6,8 @@ import net.corda.core.bufferUntilSubscribed import net.corda.core.contracts.Amount import net.corda.core.contracts.DOLLARS import net.corda.core.contracts.USD +import net.corda.core.crypto.isFulfilledBy +import net.corda.core.crypto.keys import net.corda.core.flows.StateMachineRunId import net.corda.core.getOrThrow import net.corda.core.messaging.CordaRPCOps @@ -151,25 +153,25 @@ class NodeMonitorModelTest : DriverBasedTest() { transactions.expectEvents { sequence( // ISSUE - expect { tx -> - require(tx.tx.inputs.isEmpty()) - require(tx.tx.outputs.size == 1) - val signaturePubKeys = tx.sigs.map { it.by }.toSet() + expect { stx -> + require(stx.tx.inputs.isEmpty()) + require(stx.tx.outputs.size == 1) + val signaturePubKeys = stx.sigs.map { it.by }.toSet() // Only Alice signed val aliceKey = aliceNode.legalIdentity.owningKey require(signaturePubKeys.size <= aliceKey.keys.size) require(aliceKey.isFulfilledBy(signaturePubKeys)) - issueTx = tx + issueTx = stx }, // MOVE - expect { tx -> - require(tx.tx.inputs.size == 1) - require(tx.tx.outputs.size == 1) - val signaturePubKeys = tx.sigs.map { it.by }.toSet() + expect { stx -> + require(stx.tx.inputs.size == 1) + require(stx.tx.outputs.size == 1) + val signaturePubKeys = stx.sigs.map { it.by }.toSet() // Alice and Notary signed require(aliceNode.legalIdentity.owningKey.isFulfilledBy(signaturePubKeys)) require(notaryNode.notaryIdentity.owningKey.isFulfilledBy(signaturePubKeys)) - moveTx = tx + moveTx = stx } ) } diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt index 501eeed015..ee47ed9947 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt @@ -7,7 +7,7 @@ import net.corda.client.jfx.utils.firstOrDefault import net.corda.client.jfx.utils.firstOrNullObservable import net.corda.client.jfx.utils.fold import net.corda.client.jfx.utils.map -import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.keys import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache.MapChange import java.security.PublicKey @@ -39,10 +39,6 @@ class NetworkIdentityModel { } // TODO: Use Identity Service in service hub instead? - fun lookup(compositeKey: CompositeKey): ObservableValue = parties.firstOrDefault(notaries.firstOrNullObservable { it.notaryIdentity.owningKey == compositeKey }) { - it.legalIdentity.owningKey == compositeKey - } - fun lookup(publicKey: PublicKey): ObservableValue = parties.firstOrDefault(notaries.firstOrNullObservable { it.notaryIdentity.owningKey.keys.any { it == publicKey } }) { it.legalIdentity.owningKey.keys.any { it == publicKey } } diff --git a/core/src/main/kotlin/net/corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/net/corda/core/contracts/ContractsDSL.kt index e870a8d37e..2b14fa6a08 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/ContractsDSL.kt @@ -2,8 +2,8 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import java.security.PublicKey import java.math.BigDecimal import java.util.* @@ -69,7 +69,7 @@ inline fun requireThat(body: Requirements.() -> R) = Requirements.body() // TODO: Provide a version of select that interops with Java /** Filters the command list by type, party and public key all at once. */ -inline fun Collection>.select(signer: CompositeKey? = null, +inline fun Collection>.select(signer: PublicKey? = null, party: Party? = null) = filter { it.value is T }. filter { if (signer == null) true else signer in it.signers }. @@ -79,7 +79,7 @@ inline fun Collection // TODO: Provide a version of select that interops with Java /** Filters the command list by type, parties and public keys all at once. */ -inline fun Collection>.select(signers: Collection?, +inline fun Collection>.select(signers: Collection?, parties: Collection?) = filter { it.value is T }. filter { if (signers == null) true else it.signers.containsAll(signers) }. diff --git a/core/src/main/kotlin/net/corda/core/contracts/DummyContract.kt b/core/src/main/kotlin/net/corda/core/contracts/DummyContract.kt index dd0c70e314..9aca84bb5d 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/DummyContract.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/DummyContract.kt @@ -1,9 +1,9 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey // The dummy contract doesn't do anything useful. It exists for testing purposes. @@ -14,12 +14,12 @@ data class DummyContract(override val legalContractReference: SecureHash = Secur val magicNumber: Int } - data class SingleOwnerState(override val magicNumber: Int = 0, override val owner: CompositeKey) : OwnableState, State { + data class SingleOwnerState(override val magicNumber: Int = 0, override val owner: PublicKey) : OwnableState, State { override val contract = DUMMY_PROGRAM_ID - override val participants: List + override val participants: List get() = listOf(owner) - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) } /** @@ -28,9 +28,9 @@ data class DummyContract(override val legalContractReference: SecureHash = Secur * in a different field, however this is a good example of a contract with multiple states. */ data class MultiOwnerState(override val magicNumber: Int = 0, - val owners: List) : ContractState, State { + val owners: List) : ContractState, State { override val contract = DUMMY_PROGRAM_ID - override val participants: List get() = owners + override val participants: List get() = owners } interface Commands : CommandData { @@ -55,8 +55,8 @@ data class DummyContract(override val legalContractReference: SecureHash = Secur } } - fun move(prior: StateAndRef, newOwner: CompositeKey) = move(listOf(prior), newOwner) - fun move(priors: List>, newOwner: CompositeKey): TransactionBuilder { + fun move(prior: StateAndRef, newOwner: PublicKey) = move(listOf(prior), newOwner) + fun move(priors: List>, newOwner: PublicKey): TransactionBuilder { require(priors.isNotEmpty()) val priorState = priors[0].state.data val (cmd, state) = priorState.withNewOwner(newOwner) diff --git a/core/src/main/kotlin/net/corda/core/contracts/DummyContractV2.kt b/core/src/main/kotlin/net/corda/core/contracts/DummyContractV2.kt index e4dc7eac81..2fcc633144 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/DummyContractV2.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/DummyContractV2.kt @@ -1,9 +1,9 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.transactions.WireTransaction import net.corda.flows.ContractUpgradeFlow +import java.security.PublicKey // The dummy contract doesn't do anything useful. It exists for testing purposes. val DUMMY_V2_PROGRAM_ID = DummyContractV2() @@ -11,12 +11,13 @@ val DUMMY_V2_PROGRAM_ID = DummyContractV2() /** * Dummy contract state for testing of the upgrade process. */ +// DOCSTART 1 class DummyContractV2 : UpgradedContract { override val legacyContract = DummyContract::class.java - data class State(val magicNumber: Int = 0, val owners: List) : ContractState { + data class State(val magicNumber: Int = 0, val owners: List) : ContractState { override val contract = DUMMY_V2_PROGRAM_ID - override val participants: List = owners + override val participants: List = owners } interface Commands : CommandData { @@ -35,7 +36,7 @@ class DummyContractV2 : UpgradedContract): Pair> { + fun generateUpgradeFromV1(vararg states: StateAndRef): Pair> { val notary = states.map { it.state.notary }.single() require(states.isNotEmpty()) diff --git a/core/src/main/kotlin/net/corda/core/contracts/DummyState.kt b/core/src/main/kotlin/net/corda/core/contracts/DummyState.kt index 48195ed0d6..0eb8d4555f 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/DummyState.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/DummyState.kt @@ -1,12 +1,12 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey +import java.security.PublicKey /** * Dummy state for use in testing. Not part of any contract, not even the [DummyContract]. */ data class DummyState(val magicNumber: Int = 0) : ContractState { override val contract = DUMMY_PROGRAM_ID - override val participants: List + override val participants: List get() = emptyList() } diff --git a/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt b/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt index 578ca81dc8..99aafbbd1d 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt @@ -1,7 +1,7 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey import net.corda.core.flows.FlowException +import java.security.PublicKey class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException("Insufficient balance, missing $amountMissing") @@ -25,11 +25,11 @@ interface FungibleAsset : OwnableState { * There must be an ExitCommand signed by these keys to destroy the amount. While all states require their * owner to sign, some (i.e. cash) also require the issuer. */ - val exitKeys: Collection + val exitKeys: Collection /** There must be a MoveCommand signed by this key to claim the amount */ - override val owner: CompositeKey + override val owner: PublicKey - fun move(newAmount: Amount>, newOwner: CompositeKey): FungibleAsset + fun move(newAmount: Amount>, newOwner: PublicKey): FungibleAsset // Just for grouping interface Commands : CommandData { diff --git a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt index 3b3a50ad7f..52c5307bcc 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt @@ -2,7 +2,6 @@ package net.corda.core.contracts import net.corda.core.contracts.clauses.Clause import net.corda.core.crypto.AnonymousParty -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogicRef @@ -116,7 +115,7 @@ interface ContractState { * The participants list should normally be derived from the contents of the state. E.g. for [Cash] the participants * list should just contain the owner. */ - val participants: List + val participants: List } /** @@ -189,10 +188,10 @@ fun Amount>.withoutIssuer(): Amount = Amount(quantity, to */ interface OwnableState : ContractState { /** There must be a MoveCommand signed by this key to claim the amount */ - val owner: CompositeKey + val owner: PublicKey /** Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone */ - fun withNewOwner(newOwner: CompositeKey): Pair + fun withNewOwner(newOwner: PublicKey): Pair } /** Something which is scheduled to happen at a point in time */ @@ -237,7 +236,7 @@ interface LinearState : ContractState { /** * True if this should be tracked by our vault(s). - * */ + */ fun isRelevant(ourKeys: Set): Boolean /** @@ -376,12 +375,12 @@ abstract class TypeOnlyCommandData : CommandData { /** Command data/content plus pubkey pair: the signature is stored at the end of the serialized bytes */ @CordaSerializable -data class Command(val value: CommandData, val signers: List) { +data class Command(val value: CommandData, val signers: List) { init { require(signers.isNotEmpty()) } - constructor(data: CommandData, key: CompositeKey) : this(data, listOf(key)) + constructor(data: CommandData, key: PublicKey) : this(data, listOf(key)) private fun commandDataToString() = value.toString().let { if (it.contains("@")) it.replace('$', '.').split("@")[0] else it } override fun toString() = "${commandDataToString()} with pubkeys ${signers.joinToString()}" @@ -415,7 +414,7 @@ data class UpgradeCommand(val upgradedContractClass: Class( - val signers: List, + val signers: List, /** If any public keys were recognised, the looked up institutions are available here */ val signingParties: List, val value: T diff --git a/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt b/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt index a6185a43de..00c6099f4f 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt @@ -1,10 +1,10 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey /** Defines transaction build & validation logic for a specific transaction type */ @CordaSerializable @@ -27,7 +27,7 @@ sealed class TransactionType { } /** Check that the list of signers includes all the necessary keys */ - fun verifySigners(tx: LedgerTransaction): Set { + fun verifySigners(tx: LedgerTransaction): Set { val notaryKey = tx.inputs.map { it.state.notary.owningKey }.toSet() if (notaryKey.size > 1) throw TransactionVerificationException.MoreThanOneNotary(tx) @@ -54,7 +54,7 @@ sealed class TransactionType { * Return the list of public keys that that require signatures for the transaction type. * Note: the notary key is checked separately for all transactions and need not be included. */ - abstract fun getRequiredSigners(tx: LedgerTransaction): Set + abstract fun getRequiredSigners(tx: LedgerTransaction): Set /** Implement type specific transaction validation logic */ abstract fun verifyTransaction(tx: LedgerTransaction) diff --git a/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt b/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt index 5abbb28381..be8fa723f8 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt @@ -1,11 +1,11 @@ package net.corda.core.contracts -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowException import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction +import java.security.PublicKey import java.util.* // TODO: Consider moving this out of the core module and providing a different way for unit tests to test contracts. @@ -101,7 +101,7 @@ class TransactionConflictException(val conflictRef: StateRef, val tx1: LedgerTra sealed class TransactionVerificationException(val tx: LedgerTransaction, cause: Throwable?) : FlowException(cause) { class ContractRejection(tx: LedgerTransaction, val contract: Contract, cause: Throwable?) : TransactionVerificationException(tx, cause) class MoreThanOneNotary(tx: LedgerTransaction) : TransactionVerificationException(tx, null) - class SignersMissing(tx: LedgerTransaction, val missing: List) : TransactionVerificationException(tx, null) { + class SignersMissing(tx: LedgerTransaction, val missing: List) : TransactionVerificationException(tx, null) { override fun toString(): String = "Signers missing: ${missing.joinToString()}" } diff --git a/core/src/main/kotlin/net/corda/core/crypto/AbstractParty.kt b/core/src/main/kotlin/net/corda/core/crypto/AbstractParty.kt index d3561939b4..a9329f58c6 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/AbstractParty.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/AbstractParty.kt @@ -10,10 +10,7 @@ import java.security.PublicKey * the party. In most cases [Party] or [AnonymousParty] should be used, depending on use-case. */ @CordaSerializable -abstract class AbstractParty(val owningKey: CompositeKey) { - /** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */ - constructor(owningKey: PublicKey) : this(owningKey.composite) - +abstract class AbstractParty(val owningKey: PublicKey) { /** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */ override fun equals(other: Any?): Boolean = other is AbstractParty && this.owningKey == other.owningKey diff --git a/core/src/main/kotlin/net/corda/core/crypto/AnonymousParty.kt b/core/src/main/kotlin/net/corda/core/crypto/AnonymousParty.kt index 5081da3408..9128c66492 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/AnonymousParty.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/AnonymousParty.kt @@ -8,10 +8,7 @@ import java.security.PublicKey * The [AnonymousParty] class contains enough information to uniquely identify a [Party] while excluding private * information such as name. It is intended to represent a party on the distributed ledger. */ -class AnonymousParty(owningKey: CompositeKey) : AbstractParty(owningKey) { - /** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */ - constructor(owningKey: PublicKey) : this(owningKey.composite) - +class AnonymousParty(owningKey: PublicKey) : AbstractParty(owningKey) { // Use the key as the bulk of the toString(), but include a human readable identifier as well, so that [Party] // can put in the key and actual name override fun toString() = "${owningKey.toBase58String()} " diff --git a/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt b/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt index ed312e4e59..69382b3605 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt @@ -1,118 +1,146 @@ package net.corda.core.crypto -import net.corda.core.crypto.CompositeKey.Leaf -import net.corda.core.crypto.CompositeKey.Node import net.corda.core.serialization.CordaSerializable -import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import java.security.PublicKey /** * A tree data structure that enables the representation of composite public keys. + * Notice that with that implementation CompositeKey extends PublicKey. Leaves are represented by single public keys. * - * In the simplest case it may just contain a single node encapsulating a [PublicKey] – a [Leaf]. - * - * For more complex scenarios, such as *"Both Alice and Bob need to sign to consume a state S"*, we can represent - * the requirement by creating a tree with a root [Node], and Alice and Bob as children – [Leaf]s. + * For complex scenarios, such as *"Both Alice and Bob need to sign to consume a state S"*, we can represent + * the requirement by creating a tree with a root [CompositeKey], and Alice and Bob as children. * The root node would specify *weights* for each of its children and a *threshold* – the minimum total weight required * (e.g. the minimum number of child signatures required) to satisfy the tree signature requirement. * * Using these constructs we can express e.g. 1 of N (OR) or N of N (AND) signature requirements. By nesting we can * create multi-level requirements such as *"either the CEO or 3 of 5 of his assistants need to sign"*. + * + * [CompositeKey] maintains a list of [NodeAndWeight]s which holds child subtree with associated weight carried by child node signatures. + * + * The [threshold] specifies the minimum total weight required (in the simple case – the minimum number of child + * signatures required) to satisfy the sub-tree rooted at this node. */ @CordaSerializable -sealed class CompositeKey { - /** Checks whether [keys] match a sufficient amount of leaf nodes */ - abstract fun isFulfilledBy(keys: Iterable): Boolean - - fun isFulfilledBy(key: PublicKey) = isFulfilledBy(setOf(key)) - - /** Returns all [PublicKey]s contained within the tree leaves */ - abstract val keys: Set - - /** Checks whether any of the given [keys] matches a leaf on the tree */ - fun containsAny(otherKeys: Iterable) = keys.intersect(otherKeys).isNotEmpty() +class CompositeKey private constructor (val threshold: Int, + children: List) : PublicKey { + val children = children.sorted() + init { + require (children.size == children.toSet().size) { "Trying to construct CompositeKey with duplicated child nodes." } + // If we want PublicKey we only keep one key, otherwise it will lead to semantically equivalent trees but having different structures. + require(children.size > 1) { "Cannot construct CompositeKey with only one child node." } + } /** - * This is generated by serializing the composite key with Kryo, and encoding the resulting bytes in base58. - * A custom serialization format is being used. - * - * TODO: follow the crypto-conditions ASN.1 spec, some changes are needed to be compatible with the condition - * structure, e.g. mapping a PublicKey to a condition with the specific feature (ED25519). + * Holds node - weight pairs for a CompositeKey. Ordered first by weight, then by node's hashCode. */ - fun toBase58String(): String = Base58.encode(this.serialize().bytes) + @CordaSerializable + data class NodeAndWeight(val node: PublicKey, val weight: Int): Comparable { + override fun compareTo(other: NodeAndWeight): Int { + if (weight == other.weight) { + return node.hashCode().compareTo(other.node.hashCode()) + } + else return weight.compareTo(other.weight) + } + } companion object { - fun parseFromBase58(encoded: String) = Base58.decode(encoded).deserialize() - } - - /** The leaf node of the tree – a wrapper around a [PublicKey] primitive */ - data class Leaf(val publicKey: PublicKey) : CompositeKey() { - override fun isFulfilledBy(keys: Iterable) = publicKey in keys - - override val keys: Set get() = setOf(publicKey) - - override fun toString() = publicKey.toStringShort() + // TODO: Get the design standardised and from there define a recognised name + val ALGORITHM = "X-Corda-CompositeKey" + // TODO: We should be using a well defined format. + val FORMAT = "X-Corda-Kryo" } /** - * Represents a node in the key tree. It maintains a list of child nodes – sub-trees, and associated - * [weights] carried by child node signatures. - * - * The [threshold] specifies the minimum total weight required (in the simple case – the minimum number of child - * signatures required) to satisfy the sub-tree rooted at this node. + * Takes single PublicKey and checks if CompositeKey requirements hold for that key. */ - data class Node(val threshold: Int, val children: List, val weights: List) : CompositeKey() { - override fun isFulfilledBy(keys: Iterable): Boolean { - val totalWeight = children.mapIndexed { i, childNode -> - if (childNode.isFulfilledBy(keys)) weights[i] else 0 - }.sum() + fun isFulfilledBy(key: PublicKey) = isFulfilledBy(setOf(key)) - return totalWeight >= threshold - } + override fun getAlgorithm() = ALGORITHM + override fun getEncoded(): ByteArray = this.serialize().bytes + override fun getFormat() = FORMAT - override val keys: Set get() = children.flatMap { it.keys }.toSet() - - override fun toString() = "(${children.joinToString()})" + /** + * Function checks if the public keys corresponding to the signatures are matched against the leaves of the composite + * key tree in question, and the total combined weight of all children is calculated for every intermediary node. + * If all thresholds are satisfied, the composite key requirement is considered to be met. + */ + fun isFulfilledBy(keysToCheck: Iterable): Boolean { + if (keysToCheck.any { it is CompositeKey } ) return false + val totalWeight = children.map { (node, weight) -> + if (node is CompositeKey) { + if (node.isFulfilledBy(keysToCheck)) weight else 0 + } else { + if (keysToCheck.contains(node)) weight else 0 + } + }.sum() + return totalWeight >= threshold } - /** A helper class for building a [CompositeKey.Node]. */ + /** + * Set of all leaf keys of that CompositeKey. + */ + val leavesKeys: Set + get() = children.flatMap { it.node.keys }.toSet() // Uses PublicKey.keys extension. + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is CompositeKey) return false + if (threshold != other.threshold) return false + if (children != other.children) return false + + return true + } + + override fun hashCode(): Int { + var result = threshold + result = 31 * result + children.hashCode() + return result + } + + override fun toString() = "(${children.joinToString()})" + + /** A helper class for building a [CompositeKey]. */ class Builder { - private val children: MutableList = mutableListOf() - private val weights: MutableList = mutableListOf() + private val children: MutableList = mutableListOf() /** Adds a child [CompositeKey] node. Specifying a [weight] for the child is optional and will default to 1. */ - fun addKey(key: CompositeKey, weight: Int = 1): Builder { - children.add(key) - weights.add(weight) + fun addKey(key: PublicKey, weight: Int = 1): Builder { + children.add(NodeAndWeight(key, weight)) return this } - fun addKeys(vararg keys: CompositeKey): Builder { + fun addKeys(vararg keys: PublicKey): Builder { keys.forEach { addKey(it) } return this } - fun addKeys(keys: List): Builder = addKeys(*keys.toTypedArray()) + fun addKeys(keys: List): Builder = addKeys(*keys.toTypedArray()) /** - * Builds the [CompositeKey.Node]. If [threshold] is not specified, it will default to + * Builds the [CompositeKey]. If [threshold] is not specified, it will default to * the size of the children, effectively generating an "N of N" requirement. + * During process removes single keys wrapped in [CompositeKey] and enforces ordering on child nodes. */ - fun build(threshold: Int? = null): CompositeKey.Node { - return Node(threshold ?: children.size, children.toList(), weights.toList()) + @Throws(IllegalArgumentException::class) + fun build(threshold: Int? = null): PublicKey { + val n = children.size + if (n > 1) + return CompositeKey(threshold ?: n, children) + else if (n == 1) { + require(threshold == null || threshold == children.first().weight) + { "Trying to build invalid CompositeKey, threshold value different than weight of single child node." } + return children.first().node // We can assume that this node is a correct CompositeKey. + } + else throw IllegalArgumentException("Trying to build CompositeKey without child nodes.") } } - - /** - * Returns the enclosed [PublicKey] for a [CompositeKey] with a single leaf node - * - * @throws IllegalArgumentException if the [CompositeKey] contains more than one node - */ - val singleKey: PublicKey - get() = keys.singleOrNull() ?: throw IllegalStateException("The key is composed of more than one PublicKey primitive") } -/** Returns the set of all [PublicKey]s contained in the leaves of the [CompositeKey]s */ -val Iterable.keys: Set +/** + * Expands all [CompositeKey]s present in PublicKey iterable to set of single [PublicKey]s. + * If an element of the set is a single PublicKey it gives just that key, if it is a [CompositeKey] it returns all leaf + * keys for that composite element. + */ +val Iterable.expandedCompositeKeys: Set get() = flatMap { it.keys }.toSet() \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtilities.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtilities.kt index 499d99f238..93456fcf2e 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtilities.kt @@ -4,6 +4,8 @@ package net.corda.core.crypto import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.OpaqueBytes +import net.corda.core.serialization.deserialize +import net.corda.core.serialization.serialize import net.i2p.crypto.eddsa.EdDSAEngine import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPublicKey @@ -12,6 +14,7 @@ import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import java.math.BigInteger +import java.security.InvalidKeyException import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey @@ -27,7 +30,7 @@ open class DigitalSignature(bits: ByteArray) : OpaqueBytes(bits) { } // TODO: consider removing this as whoever needs to identify the signer should be able to derive it from the public key - class LegallyIdentifiable(val signer: Party, bits: ByteArray) : WithKey(signer.owningKey.singleKey, bits) + class LegallyIdentifiable(val signer: Party, bits: ByteArray) : WithKey(signer.owningKey, bits) } @CordaSerializable @@ -39,7 +42,6 @@ object NullPublicKey : PublicKey, Comparable { override fun toString() = "NULL_KEY" } -val NullCompositeKey = NullPublicKey.composite // TODO: Clean up this duplication between Null and Dummy public key @CordaSerializable @@ -72,22 +74,37 @@ fun PrivateKey.signWithECDSA(bytesToSign: ByteArray, publicKey: PublicKey): Digi val ed25519Curve = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512) -fun parsePublicKeyBase58(base58String: String) = EdDSAPublicKey(EdDSAPublicKeySpec(Base58.decode(base58String), ed25519Curve)) -fun PublicKey.toBase58String() = Base58.encode((this as EdDSAPublicKey).abyte) +// TODO We use for both CompositeKeys and EdDSAPublicKey custom Kryo serializers and deserializers. We need to specify encoding. +// TODO: follow the crypto-conditions ASN.1 spec, some changes are needed to be compatible with the condition +// structure, e.g. mapping a PublicKey to a condition with the specific feature (ED25519). +fun parsePublicKeyBase58(base58String: String): PublicKey = Base58.decode(base58String).deserialize() +fun PublicKey.toBase58String(): String = Base58.encode(this.serialize().bytes) fun KeyPair.signWithECDSA(bytesToSign: ByteArray) = private.signWithECDSA(bytesToSign, public) fun KeyPair.signWithECDSA(bytesToSign: OpaqueBytes) = private.signWithECDSA(bytesToSign.bytes, public) fun KeyPair.signWithECDSA(bytesToSign: OpaqueBytes, party: Party) = signWithECDSA(bytesToSign.bytes, party) +// TODO This case will need more careful thinking, as party owningKey can be a CompositeKey. One way of doing that is +// implementation of CompositeSignature. +@Throws(InvalidKeyException::class) fun KeyPair.signWithECDSA(bytesToSign: ByteArray, party: Party): DigitalSignature.LegallyIdentifiable { - check(public in party.owningKey.keys) val sig = signWithECDSA(bytesToSign) + val sigKey = when (party.owningKey) { // Quick workaround when we have CompositeKey as Party owningKey. + is CompositeKey -> throw InvalidKeyException("Signing for parties with CompositeKey not supported.") + else -> party.owningKey + } + sigKey.verifyWithECDSA(bytesToSign, sig) return DigitalSignature.LegallyIdentifiable(party, sig.bytes) } /** Utility to simplify the act of verifying a signature */ +@Throws(SignatureException::class, IllegalStateException::class) fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) { + val pubKey = when (this) { + is CompositeKey -> throw IllegalStateException("Verification of CompositeKey signatures currently not supported.") // TODO CompositeSignature verification. + else -> this + } val verifier = EdDSAEngine() - verifier.initVerify(this) + verifier.initVerify(pubKey) verifier.update(content) if (verifier.verify(signature.bytes) == false) throw SignatureException("Signature did not match") @@ -100,8 +117,22 @@ fun PublicKey.toStringShort(): String { } ?: toString() } -/** Creates a [CompositeKey] with a single leaf node containing the public key */ -val PublicKey.composite: CompositeKey get() = CompositeKey.Leaf(this) +val PublicKey.keys: Set get() { + return if (this is CompositeKey) this.leavesKeys + else setOf(this) +} + +fun PublicKey.isFulfilledBy(otherKey: PublicKey): Boolean = isFulfilledBy(setOf(otherKey)) +fun PublicKey.isFulfilledBy(otherKeys: Iterable): Boolean { + return if (this is CompositeKey) this.isFulfilledBy(otherKeys) + else this in otherKeys +} + +/** Checks whether any of the given [keys] matches a leaf on the CompositeKey tree or a single PublicKey */ +fun PublicKey.containsAny(otherKeys: Iterable): Boolean { + return if (this is CompositeKey) keys.intersect(otherKeys).isNotEmpty() + else this in otherKeys +} /** Returns the set of all [PublicKey]s of the signatures */ fun Iterable.byKeys() = map { it.by }.toSet() diff --git a/core/src/main/kotlin/net/corda/core/crypto/Party.kt b/core/src/main/kotlin/net/corda/core/crypto/Party.kt index 14a2806e3c..1e65cda82b 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Party.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Party.kt @@ -7,7 +7,7 @@ import java.security.PublicKey /** * The [Party] class represents an entity on the network, which is typically identified by a legal [name] and public key * that it can sign transactions under. As parties may use multiple keys for signing and, for example, have offline backup - * keys, the "public key" of a party is represented by a composite construct – a [CompositeKey], which combines multiple + * keys, the "public key" of a party can be represented by a composite construct – a [CompositeKey], which combines multiple * cryptographic public key primitives into a tree structure. * * For example: Alice has two key pairs (pub1/priv1 and pub2/priv2), and wants to be able to sign transactions with either of them. @@ -22,10 +22,7 @@ import java.security.PublicKey * * @see CompositeKey */ -class Party(val name: String, owningKey: CompositeKey) : AbstractParty(owningKey) { - /** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */ - constructor(name: String, owningKey: PublicKey) : this(name, owningKey.composite) - +class Party(val name: String, owningKey: PublicKey) : AbstractParty(owningKey) { override fun toAnonymous(): AnonymousParty = AnonymousParty(owningKey) override fun toString() = "${owningKey.toBase58String()} (${name})" override fun nameOrNull(): String? = name diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index 50f9640c50..d192a4fdd2 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -5,7 +5,6 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.UpgradedContract -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic @@ -18,6 +17,7 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import rx.Observable import java.io.InputStream +import java.security.PublicKey import java.time.Instant import java.util.* @@ -158,7 +158,7 @@ interface CordaRPCOps : RPCOps { /** * Returns the [Party] corresponding to the given key, if found. */ - fun partyFromKey(key: CompositeKey): Party? + fun partyFromKey(key: PublicKey): Party? /** * Returns the [Party] with the given name as it's [Party.name] diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt index 279b569e08..208df63775 100644 --- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt @@ -1,6 +1,7 @@ package net.corda.core.node import net.corda.core.contracts.* +import net.corda.core.crypto.keys import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowStateMachine import net.corda.core.messaging.MessagingService @@ -109,6 +110,8 @@ interface ServiceHub : ServicesForResolution { * used in contexts where the Node knows it is hosting a Notary Service. Otherwise, it will throw * an IllegalArgumentException. * Typical use is during signing in flows and for unit test signing. + * + * TODO: same problem as with legalIdentityKey. */ val notaryIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.notaryIdentity.owningKey.keys) } diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index ef1dcf4d9b..27793748f9 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -2,8 +2,8 @@ package net.corda.core.node.services import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.AnonymousParty -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import java.security.PublicKey /** * An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports @@ -23,7 +23,7 @@ interface IdentityService { // indefinitely. It may be that in the long term we need to drop or archive very old Party information for space, // but for now this is not supported. - fun partyFromKey(key: CompositeKey): Party? + fun partyFromKey(key: PublicKey): Party? fun partyFromName(name: String): Party? fun partyFromAnonymous(party: AnonymousParty): Party? diff --git a/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt b/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt index 7189372b89..480957e4ac 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt @@ -3,7 +3,6 @@ package net.corda.core.node.services import com.google.common.annotations.VisibleForTesting import com.google.common.util.concurrent.ListenableFuture import net.corda.core.contracts.Contract -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.messaging.MessagingService import net.corda.core.messaging.SingleMessageRecipient @@ -11,6 +10,7 @@ import net.corda.core.node.NodeInfo import net.corda.core.randomOrNull import net.corda.core.serialization.CordaSerializable import rx.Observable +import java.security.PublicKey /** * A network map contains lists of nodes on the network along with information about their identity keys, services @@ -74,11 +74,11 @@ interface NetworkMapCache { */ /** Look up the node info for a specific peer key. */ - fun getNodeByLegalIdentityKey(compositeKey: CompositeKey): NodeInfo? + fun getNodeByLegalIdentityKey(identityKey: PublicKey): NodeInfo? - /** Look up all nodes advertising the service owned by [compositeKey] */ - fun getNodesByAdvertisedServiceIdentityKey(compositeKey: CompositeKey): List { - return partyNodes.filter { it.advertisedServices.any { it.identity.owningKey == compositeKey } } + /** Look up all nodes advertising the service owned by [publicKey] */ + fun getNodesByAdvertisedServiceIdentityKey(publicKey: PublicKey): List { + return partyNodes.filter { it.advertisedServices.any { it.identity.owningKey == publicKey } } } /** Returns information about the party, which may be a specific node or a service */ diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index a58bfd090a..0d61fff334 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -204,8 +204,8 @@ interface VaultService { @Suspendable fun generateSpend(tx: TransactionBuilder, amount: Amount, - to: CompositeKey, - onlyFromParties: Set? = null): Pair> + to: PublicKey, + onlyFromParties: Set? = null): Pair> // DOCSTART VaultStatesQuery /** @@ -288,11 +288,19 @@ interface KeyManagementService { /** Returns a snapshot of the current pubkey->privkey mapping. */ val keys: Map + @Throws(IllegalStateException::class) fun toPrivate(publicKey: PublicKey) = keys[publicKey] ?: throw IllegalStateException("No private key known for requested public key ${publicKey.toStringShort()}") - fun toKeyPair(publicKey: PublicKey) = KeyPair(publicKey, toPrivate(publicKey)) + @Throws(IllegalArgumentException::class) + fun toKeyPair(publicKey: PublicKey): KeyPair { + when (publicKey) { + is CompositeKey -> throw IllegalArgumentException("Got CompositeKey when single PublicKey expected.") + else -> return KeyPair(publicKey, toPrivate(publicKey)) + } + } /** Returns the first [KeyPair] matching any of the [publicKeys] */ + @Throws(IllegalArgumentException::class) fun toKeyPair(publicKeys: Iterable) = publicKeys.first { keys.contains(it) }.let { toKeyPair(it) } /** Generates a new random key and adds it to the exposed map. */ diff --git a/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt b/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt index 4dad6f4037..d3062ba1e6 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt @@ -65,8 +65,7 @@ object DefaultKryoCustomizer { register(EdDSAPrivateKey::class.java, Ed25519PrivateKeySerializer) // Using a custom serializer for compactness - register(CompositeKey.Node::class.java, CompositeKeyNodeSerializer) - register(CompositeKey.Leaf::class.java, CompositeKeyLeafSerializer) + register(CompositeKey::class.java, CompositeKeySerializer) // Exceptions. We don't bother sending the stack traces as the client will fill in its own anyway. register(Array::class, read = { _, _ -> emptyArray() }, write = { _, _, _ -> }) diff --git a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt index bb546e90a0..a9aad7a0b5 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt @@ -330,7 +330,7 @@ object WireTransactionSerializer : Serializer() { val outputs = kryo.readClassAndObject(input) as List> val commands = kryo.readClassAndObject(input) as List val notary = kryo.readClassAndObject(input) as Party? - val signers = kryo.readClassAndObject(input) as List + val signers = kryo.readClassAndObject(input) as List val transactionType = kryo.readClassAndObject(input) as TransactionType val timestamp = kryo.readClassAndObject(input) as Timestamp? @@ -367,41 +367,38 @@ object Ed25519PublicKeySerializer : Serializer() { } } -/** For serialising composite keys */ +// TODO Implement standardized serialization of CompositeKeys. See JIRA issue: CORDA-249. @ThreadSafe -object CompositeKeyLeafSerializer : Serializer() { - override fun write(kryo: Kryo, output: Output, obj: CompositeKey.Leaf) { - val key = obj.publicKey - kryo.writeClassAndObject(output, key) - } - - override fun read(kryo: Kryo, input: Input, type: Class): CompositeKey.Leaf { - val key = kryo.readClassAndObject(input) as PublicKey - return CompositeKey.Leaf(key) - } -} - -@ThreadSafe -object CompositeKeyNodeSerializer : Serializer() { - override fun write(kryo: Kryo, output: Output, obj: CompositeKey.Node) { +object CompositeKeySerializer : Serializer() { + override fun write(kryo: Kryo, output: Output, obj: CompositeKey) { output.writeInt(obj.threshold) output.writeInt(obj.children.size) obj.children.forEach { kryo.writeClassAndObject(output, it) } - output.writeInts(obj.weights.toIntArray()) } - override fun read(kryo: Kryo, input: Input, type: Class): CompositeKey.Node { + override fun read(kryo: Kryo, input: Input, type: Class): CompositeKey { val threshold = input.readInt() - val childCount = input.readInt() - val children = (1..childCount).map { kryo.readClassAndObject(input) as CompositeKey } - val weights = input.readInts(childCount) - + val children = readListOfLength(kryo, input, minLen = 2) val builder = CompositeKey.Builder() - weights.zip(children).forEach { builder.addKey(it.second, it.first) } - return builder.build(threshold) + children.forEach { builder.addKey(it.node, it.weight) } + return builder.build(threshold) as CompositeKey } } +/** + * Helper function for reading lists with number of elements at the beginning. + * @param minLen minimum number of elements we expect for list to include, defaults to 1 + * @param expectedLen expected length of the list, defaults to null if arbitrary length list read + */ +inline fun readListOfLength(kryo: Kryo, input: Input, minLen: Int = 1, expectedLen: Int? = null): List { + val elemCount = input.readInt() + if (elemCount < minLen) throw KryoException("Cannot deserialize list, too little elements. Minimum required: $minLen, got: $elemCount") + if (expectedLen != null && elemCount != expectedLen) + throw KryoException("Cannot deserialize list, expected length: $expectedLen, got: $elemCount.") + val list = (1..elemCount).map { kryo.readClassAndObject(input) as T } + return list +} + /** Marker interface for kotlin object definitions so that they are deserialized as the singleton instance. */ interface DeserializeAsKotlinObjectDef diff --git a/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt index b3cca751fc..080c54ec42 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt @@ -1,8 +1,8 @@ package net.corda.core.transactions import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import java.security.PublicKey import java.util.* /** @@ -20,14 +20,14 @@ abstract class BaseTransaction( */ val notary: Party?, /** - * Composite keys that need to be fulfilled by signatures in order for the transaction to be valid. + * Public keys that need to be fulfilled by signatures in order for the transaction to be valid. * In a [SignedTransaction] this list is used to check whether there are any missing signatures. Note that * there is nothing that forces the list to be the _correct_ list of signers for this transaction until * the transaction is verified by using [LedgerTransaction.verify]. * * It includes the notary key, if the notary field is set. */ - val mustSign: List, + val mustSign: List, /** * Pointer to a class that defines the behaviour of this transaction: either normal, or "notary changing". */ diff --git a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt index c4d059b1c9..2d7dae9ec5 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt @@ -1,10 +1,10 @@ package net.corda.core.transactions import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.serialization.CordaSerializable +import java.security.PublicKey /** * A LedgerTransaction is derived from a [WireTransaction]. It is the result of doing the following operations: @@ -29,7 +29,7 @@ class LedgerTransaction( /** The hash of the original serialised WireTransaction. */ override val id: SecureHash, notary: Party?, - signers: List, + signers: List, timestamp: Timestamp?, type: TransactionType ) : BaseTransaction(inputs, outputs, notary, signers, type, timestamp) { diff --git a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt index dd080f5b1b..9513f46f8d 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt @@ -5,6 +5,7 @@ import net.corda.core.crypto.* import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.p2PKryo import net.corda.core.serialization.serialize +import java.security.PublicKey import net.corda.core.serialization.withoutReferences fun serializedHash(x: T): SecureHash { @@ -26,7 +27,7 @@ interface TraversableTransaction { val outputs: List> val commands: List val notary: Party? - val mustSign: List + val mustSign: List val type: TransactionType? val timestamp: Timestamp? @@ -74,7 +75,7 @@ class FilteredLeaves( override val outputs: List>, override val commands: List, override val notary: Party?, - override val mustSign: List, + override val mustSign: List, override val type: TransactionType?, override val timestamp: Timestamp? ) : TraversableTransaction { diff --git a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt index d26ff2b9ad..dec29f4027 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt @@ -3,21 +3,22 @@ package net.corda.core.transactions import net.corda.core.contracts.AttachmentResolutionException import net.corda.core.contracts.NamedByHash import net.corda.core.contracts.TransactionResolutionException -import net.corda.core.crypto.CompositeKey +import net.corda.core.node.ServiceHub import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.signWithECDSA -import net.corda.core.node.ServiceHub import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializedBytes import java.security.KeyPair +import java.security.PublicKey import java.security.SignatureException import java.util.* /** * SignedTransaction wraps a serialized WireTransaction. It contains one or more signatures, each one for - * a public key that is mentioned inside a transaction command. SignedTransaction is the top level transaction type - * and the type most frequently passed around the network and stored. The identity of a transaction is the hash + * a public key (including composite keys) that is mentioned inside a transaction command. SignedTransaction is the top level transaction type + * and the type most frequently passed around the network and stored. The identity of a transaction is the hash of Merkle root * of a WireTransaction, therefore if you are storing data keyed by WT hash be aware that multiple different STs may * map to the same key (and they could be different in important ways, like validity!). The signatures on a * SignedTransaction might be invalid or missing: the type does not imply validity. @@ -43,7 +44,7 @@ data class SignedTransaction(val txBits: SerializedBytes, override val id: SecureHash get() = tx.id @CordaSerializable - class SignaturesMissingException(val missing: Set, val descriptions: List, override val id: SecureHash) : NamedByHash, SignatureException() { + class SignaturesMissingException(val missing: Set, val descriptions: List, override val id: SecureHash) : NamedByHash, SignatureException() { override fun toString(): String { return "Missing signatures for $descriptions on transaction ${id.prefixChars()} for ${missing.joinToString()}" } @@ -62,13 +63,13 @@ data class SignedTransaction(val txBits: SerializedBytes, * @throws SignaturesMissingException if any signatures should have been present but were not. */ @Throws(SignatureException::class) - fun verifySignatures(vararg allowedToBeMissing: CompositeKey): WireTransaction { + fun verifySignatures(vararg allowedToBeMissing: PublicKey): WireTransaction { // Embedded WireTransaction is not deserialised until after we check the signatures. checkSignaturesAreValid() val missing = getMissingSignatures() if (missing.isNotEmpty()) { - val allowed = setOf(*allowedToBeMissing) + val allowed = allowedToBeMissing.toSet() val needed = missing - allowed if (needed.isNotEmpty()) throw SignaturesMissingException(needed, getMissingKeyDescriptions(needed), id) @@ -92,8 +93,10 @@ data class SignedTransaction(val txBits: SerializedBytes, } } - private fun getMissingSignatures(): Set { + private fun getMissingSignatures(): Set { val sigKeys = sigs.map { it.by }.toSet() + // TODO Problem is that we can get single PublicKey wrapped as CompositeKey in allowedToBeMissing/mustSign + // equals on CompositeKey won't catch this case (do we want to single PublicKey be equal to the same key wrapped in CompositeKey with threshold 1?) val missing = tx.mustSign.filter { !it.isFulfilledBy(sigKeys) }.toSet() return missing } @@ -102,7 +105,7 @@ data class SignedTransaction(val txBits: SerializedBytes, * Get a human readable description of where signatures are required from, and are missing, to assist in debugging * the underlying cause. */ - private fun getMissingKeyDescriptions(missing: Set): ArrayList { + private fun getMissingKeyDescriptions(missing: Set): ArrayList { // TODO: We need a much better way of structuring this data val missingElements = ArrayList() this.tx.commands.forEach { command -> diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt index 30d8308d4d..4db371d3a5 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.* import net.corda.core.flows.FlowStateMachine import net.corda.core.serialization.serialize import java.security.KeyPair +import java.security.PublicKey import java.time.Duration import java.time.Instant import java.util.* @@ -34,7 +35,7 @@ open class TransactionBuilder( protected val attachments: MutableList = arrayListOf(), protected val outputs: MutableList> = arrayListOf(), protected val commands: MutableList = arrayListOf(), - protected val signers: MutableSet = mutableSetOf(), + protected val signers: MutableSet = mutableSetOf(), protected var timestamp: Timestamp? = null) { val time: Timestamp? get() = timestamp @@ -135,7 +136,7 @@ open class TransactionBuilder( fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction { if (checkSufficientSignatures) { val gotKeys = currentSigs.map { it.by }.toSet() - val missing: Set = signers.filter { !it.isFulfilledBy(gotKeys) }.toSet() + val missing: Set = signers.filter { !it.isFulfilledBy(gotKeys) }.toSet() if (missing.isNotEmpty()) throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.joinToString()}") } @@ -178,8 +179,8 @@ open class TransactionBuilder( commands.add(arg) } - fun addCommand(data: CommandData, vararg keys: CompositeKey) = addCommand(Command(data, listOf(*keys))) - fun addCommand(data: CommandData, keys: List) = addCommand(Command(data, keys)) + fun addCommand(data: CommandData, vararg keys: PublicKey) = addCommand(Command(data, listOf(*keys))) + fun addCommand(data: CommandData, keys: List) = addCommand(Command(data, keys)) // Accessors that yield immutable snapshots. fun inputStates(): List = ArrayList(inputs) diff --git a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt index f6a979a2ed..83c90b9e97 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -2,7 +2,6 @@ package net.corda.core.transactions import com.esotericsoftware.kryo.pool.KryoPool import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.MerkleTree import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash @@ -30,7 +29,7 @@ class WireTransaction( /** Ordered list of ([CommandData], [PublicKey]) pairs that instruct the contracts what to do. */ override val commands: List, notary: Party?, - signers: List, + signers: List, type: TransactionType, timestamp: Timestamp? ) : BaseTransaction(inputs, outputs, notary, signers, type, timestamp), TraversableTransaction { @@ -87,7 +86,7 @@ class WireTransaction( */ @Throws(AttachmentResolutionException::class, TransactionResolutionException::class) fun toLedgerTransaction( - resolveIdentity: (CompositeKey) -> Party?, + resolveIdentity: (PublicKey) -> Party?, resolveAttachment: (SecureHash) -> Attachment?, resolveStateRef: (StateRef) -> TransactionState<*>? ): LedgerTransaction { diff --git a/core/src/main/kotlin/net/corda/core/utilities/ApiUtils.kt b/core/src/main/kotlin/net/corda/core/utilities/ApiUtils.kt index 77d6e23004..94663d3634 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/ApiUtils.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/ApiUtils.kt @@ -1,8 +1,8 @@ package net.corda.core.utilities import net.corda.core.ErrorOr -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import net.corda.core.crypto.parsePublicKeyBase58 import net.corda.core.messaging.CordaRPCOps import javax.ws.rs.core.Response @@ -18,7 +18,7 @@ class ApiUtils(val rpc: CordaRPCOps) { */ fun withParty(partyKeyStr: String, notFound: (String) -> Response = defaultNotFound, found: (Party) -> Response): Response { val party = try { - val partyKey = CompositeKey.parseFromBase58(partyKeyStr) + val partyKey = parsePublicKeyBase58(partyKeyStr) ErrorOr(rpc.partyFromKey(partyKey)) } catch (e: IllegalArgumentException) { ErrorOr.of(Exception("Invalid base58 key passed for party key $e")) diff --git a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt index ae281e0554..8e932973ae 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt @@ -5,13 +5,14 @@ package net.corda.core.utilities import net.corda.core.crypto.* import java.math.BigInteger import java.security.KeyPair +import java.security.PublicKey import java.time.Instant // A dummy time at which we will be pretending test transactions are created. val TEST_TX_TIME: Instant get() = Instant.parse("2015-04-17T12:00:00.00Z") -val DUMMY_PUBKEY_1: CompositeKey get() = DummyPublicKey("x1").composite -val DUMMY_PUBKEY_2: CompositeKey get() = DummyPublicKey("x2").composite +val DUMMY_PUBKEY_1: PublicKey get() = DummyPublicKey("x1") +val DUMMY_PUBKEY_2: PublicKey get() = DummyPublicKey("x2") val DUMMY_KEY_1: KeyPair by lazy { generateKeyPair() } val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() } diff --git a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt index 16c96c10a9..2744bf4cbb 100644 --- a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt @@ -4,10 +4,7 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef -import net.corda.core.crypto.CompositeKey -import net.corda.core.crypto.DigitalSignature -import net.corda.core.crypto.Party -import net.corda.core.crypto.signWithECDSA +import net.corda.core.crypto.* import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.serialization.CordaSerializable @@ -16,6 +13,7 @@ import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.unwrap +import java.security.PublicKey /** * Abstract flow to be used for replacing one state with another, for example when changing the notary of a state. @@ -74,10 +72,10 @@ abstract class AbstractStateReplacementFlow { return finalTx.tx.outRef(0) } - abstract protected fun assembleTx(): Pair> + abstract protected fun assembleTx(): Pair> @Suspendable - private fun collectSignatures(participants: Iterable, stx: SignedTransaction): List { + private fun collectSignatures(participants: Iterable, stx: SignedTransaction): List { val parties = participants.map { val participantNode = serviceHub.networkMapCache.getNodeByLegalIdentityKey(it) ?: throw IllegalStateException("Participant $it to state $originalState not found on the network") diff --git a/core/src/main/kotlin/net/corda/flows/ContractUpgradeFlow.kt b/core/src/main/kotlin/net/corda/flows/ContractUpgradeFlow.kt index d4e687886a..65a79f7dd7 100644 --- a/core/src/main/kotlin/net/corda/flows/ContractUpgradeFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/ContractUpgradeFlow.kt @@ -2,13 +2,13 @@ package net.corda.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.flows.AbstractStateReplacementFlow.Proposal import net.corda.flows.ContractUpgradeFlow.Acceptor import net.corda.flows.ContractUpgradeFlow.Instigator +import java.security.PublicKey /** * A flow to be used for upgrading state objects of an old contract to a new contract. @@ -28,8 +28,8 @@ object ContractUpgradeFlow { @JvmStatic fun verify(input: ContractState, output: ContractState, commandData: Command) { val command = commandData.value as UpgradeCommand - val participants: Set = input.participants.toSet() - val keysThatSigned: Set = commandData.signers.toSet() + val participants: Set = input.participants.toSet() + val keysThatSigned: Set = commandData.signers.toSet() @Suppress("UNCHECKED_CAST") val upgradedContract = command.upgradedContractClass.newInstance() as UpgradedContract requireThat { @@ -54,7 +54,7 @@ object ContractUpgradeFlow { newContractClass: Class> ) : AbstractStateReplacementFlow.Instigator>>(originalState, newContractClass) { - override fun assembleTx(): Pair> { + override fun assembleTx(): Pair> { val stx = assembleBareTx(originalState, modification) .signWith(serviceHub.legalIdentityKey) .toSignedTransaction(false) diff --git a/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt b/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt index b000b260c6..319274f10a 100644 --- a/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt @@ -5,6 +5,7 @@ import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateRef import net.corda.core.contracts.TransactionState import net.corda.core.crypto.Party +import net.corda.core.crypto.isFulfilledBy import net.corda.core.flows.FlowLogic import net.corda.core.node.ServiceHub import net.corda.core.transactions.LedgerTransaction diff --git a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt index 58ab8752e6..af2fcde85d 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt @@ -1,13 +1,13 @@ package net.corda.flows import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker import net.corda.flows.NotaryChangeFlow.Acceptor import net.corda.flows.NotaryChangeFlow.Instigator +import java.security.PublicKey /** * A flow to be used for changing a state's Notary. This is required since all input states to a transaction @@ -25,11 +25,11 @@ object NotaryChangeFlow : AbstractStateReplacementFlow() { newNotary: Party, progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementFlow.Instigator(originalState, newNotary, progressTracker) { - override fun assembleTx(): Pair> { + override fun assembleTx(): Pair> { val state = originalState.state val tx = TransactionType.NotaryChange.Builder(originalState.state.notary) - val participants: Iterable + val participants: Iterable if (state.encumbrance == null) { val modifiedState = TransactionState(state.data, modification) @@ -54,14 +54,14 @@ object NotaryChangeFlow : AbstractStateReplacementFlow() { * * @return union of all added states' participants */ - private fun resolveEncumbrances(tx: TransactionBuilder): Iterable { + private fun resolveEncumbrances(tx: TransactionBuilder): Iterable { val stateRef = originalState.ref val txId = stateRef.txhash val issuingTx = serviceHub.storageService.validatedTransactions.getTransaction(txId) ?: throw StateReplacementException("Transaction $txId not found") val outputs = issuingTx.tx.outputs - val participants = mutableSetOf() + val participants = mutableSetOf() var nextStateIndex = stateRef.index var newOutputPosition = tx.outputStates().size diff --git a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt index 4ca7be0ca8..88f72d45d3 100644 --- a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt @@ -18,6 +18,7 @@ import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.trace import net.corda.core.utilities.unwrap import java.security.KeyPair +import java.security.PublicKey /** * Classes for manipulating a two party deal or agreement. @@ -43,7 +44,7 @@ object TwoPartyDealFlow { // This object is serialised to the network and is the first flow message the seller sends to the buyer. @CordaSerializable - data class Handshake(val payload: T, val publicKey: CompositeKey) + data class Handshake(val payload: T, val publicKey: PublicKey) @CordaSerializable class SignaturesFromPrimary(val sellerSig: DigitalSignature.WithKey, val notarySigs: List) @@ -92,7 +93,7 @@ object TwoPartyDealFlow { progressTracker.currentStep = AWAITING_PROPOSAL // Make the first message we'll send to kick off the flow. - val hello = Handshake(payload, myKeyPair.public.composite) + val hello = Handshake(payload, myKeyPair.public) val maybeSTX = sendAndReceive(otherParty, hello) return maybeSTX @@ -106,7 +107,7 @@ object TwoPartyDealFlow { progressTracker.nextStep() // Check that the tx proposed by the buyer is valid. - val wtx: WireTransaction = stx.verifySignatures(myKeyPair.public.composite, notaryNode.notaryIdentity.owningKey) + val wtx: WireTransaction = stx.verifySignatures(myKeyPair.public, notaryNode.notaryIdentity.owningKey) logger.trace { "Received partially signed transaction: ${stx.id}" } checkDependencies(stx) @@ -253,9 +254,9 @@ object TwoPartyDealFlow { return sendAndReceive(otherParty, stx).unwrap { it } } - private fun signWithOurKeys(signingPubKeys: List, ptx: TransactionBuilder): SignedTransaction { + private fun signWithOurKeys(signingPubKeys: List, ptx: TransactionBuilder): SignedTransaction { // Now sign the transaction with whatever keys we need to move the cash. - for (publicKey in signingPubKeys.keys) { + for (publicKey in signingPubKeys.expandedCompositeKeys) { val privateKey = serviceHub.keyManagementService.toPrivate(publicKey) ptx.signWith(KeyPair(publicKey, privateKey)) } @@ -264,7 +265,7 @@ object TwoPartyDealFlow { } @Suspendable protected abstract fun validateHandshake(handshake: Handshake): Handshake - @Suspendable protected abstract fun assembleSharedTX(handshake: Handshake): Pair> + @Suspendable protected abstract fun assembleSharedTX(handshake: Handshake): Pair> } @CordaSerializable @@ -297,7 +298,7 @@ object TwoPartyDealFlow { return handshake.copy(payload = autoOffer.copy(dealBeingOffered = deal)) } - override fun assembleSharedTX(handshake: Handshake): Pair> { + override fun assembleSharedTX(handshake: Handshake): Pair> { val deal = handshake.payload.dealBeingOffered val ptx = deal.generateAgreement(handshake.payload.notary) diff --git a/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt b/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt index c91b754e4c..33db142cc2 100644 --- a/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt +++ b/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt @@ -1,12 +1,11 @@ package net.corda.flows import co.paralleluniverse.fibers.Suspendable -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party -import net.corda.core.crypto.composite import net.corda.core.flows.FlowLogic import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.unwrap +import java.security.PublicKey import java.security.cert.Certificate object TxKeyFlowUtilities { @@ -15,7 +14,7 @@ object TxKeyFlowUtilities { * process. */ @Suspendable - fun receiveKey(flow: FlowLogic<*>, otherSide: Party): Pair { + fun receiveKey(flow: FlowLogic<*>, otherSide: Party): Pair { val untrustedKey = flow.receive(otherSide) return untrustedKey.unwrap { // TODO: Verify the certificate connects the given key to the counterparty, once we have certificates @@ -29,8 +28,8 @@ object TxKeyFlowUtilities { * a transaction with the counterparty, in order to avoid a DoS risk. */ @Suspendable - fun provideKey(flow: FlowLogic<*>, otherSide: Party): CompositeKey { - val key = flow.serviceHub.keyManagementService.freshKey().public.composite + fun provideKey(flow: FlowLogic<*>, otherSide: Party): PublicKey { + val key = flow.serviceHub.keyManagementService.freshKey().public // TODO: Generate and sign certificate for the key, once we have signing support for composite keys // (in this case the legal identity key) flow.send(otherSide, ProvidedTransactionKey(key, null)) @@ -38,5 +37,5 @@ object TxKeyFlowUtilities { } @CordaSerializable - data class ProvidedTransactionKey(val key: CompositeKey, val certificate: Certificate?) -} \ No newline at end of file + data class ProvidedTransactionKey(val key: PublicKey, val certificate: Certificate?) +} diff --git a/core/src/main/resources/net/corda/core/node/isolated.jar b/core/src/main/resources/net/corda/core/node/isolated.jar index 0b6d090c58..450d5f0cdc 100644 Binary files a/core/src/main/resources/net/corda/core/node/isolated.jar and b/core/src/main/resources/net/corda/core/node/isolated.jar differ diff --git a/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt b/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt index 0ed02db3bb..816469e38b 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt @@ -1,7 +1,6 @@ package net.corda.core.contracts import net.corda.contracts.asset.Cash -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.utilities.DUMMY_PUBKEY_1 import net.corda.core.utilities.DUMMY_PUBKEY_2 @@ -9,6 +8,7 @@ import net.corda.testing.MEGA_CORP import net.corda.testing.ledger import net.corda.testing.transaction import org.junit.Test +import java.security.PublicKey import java.time.Instant import java.time.temporal.ChronoUnit @@ -40,7 +40,7 @@ class TransactionEncumbranceTests { data class State( val validFrom: Instant ) : ContractState { - override val participants: List = emptyList() + override val participants: List = emptyList() override val contract: Contract = TEST_TIMELOCK_ID } } diff --git a/core/src/test/kotlin/net/corda/core/contracts/TransactionGraphSearchTests.kt b/core/src/test/kotlin/net/corda/core/contracts/TransactionGraphSearchTests.kt index 2ac1841a62..aee51ffd46 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/TransactionGraphSearchTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/TransactionGraphSearchTests.kt @@ -1,6 +1,5 @@ package net.corda.core.contracts -import net.corda.core.crypto.composite import net.corda.core.crypto.newSecureRandom import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -32,7 +31,7 @@ class TransactionGraphSearchTests { fun buildTransactions(command: CommandData, signer: KeyPair): GraphTransactionStorage { val originTx = TransactionType.General.Builder(DUMMY_NOTARY).apply { addOutputState(DummyState(random31BitValue())) - addCommand(command, signer.public.composite) + addCommand(command, signer.public) signWith(signer) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction(false) diff --git a/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt b/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt index 1e86e3b0f0..33e004fd08 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt @@ -1,9 +1,10 @@ package net.corda.core.contracts import net.corda.contracts.asset.DUMMY_CASH_ISSUER_KEY +import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash -import net.corda.core.crypto.composite +import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.signWithECDSA import net.corda.core.serialization.SerializedBytes import net.corda.core.transactions.LedgerTransaction @@ -22,6 +23,48 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith class TransactionTests { + + private fun makeSigned(wtx: WireTransaction, vararg keys: KeyPair): SignedTransaction { + val bytes: SerializedBytes = wtx.serialized + return SignedTransaction(bytes, keys.map { it.signWithECDSA(wtx.id.bytes) }) + } + + @Test + fun `signed transaction missing signatures - CompositeKey`() { + val ak = generateKeyPair() + val bk = generateKeyPair() + val ck = generateKeyPair() + val apub = ak.public + val bpub = bk.public + val cpub = ck.public + val c1 = CompositeKey.Builder().addKeys(apub, bpub).build(2) + val compKey = CompositeKey.Builder().addKeys(c1, cpub).build(1) + val wtx = WireTransaction( + inputs = listOf(StateRef(SecureHash.randomSHA256(), 0)), + attachments = emptyList(), + outputs = emptyList(), + commands = emptyList(), + notary = DUMMY_NOTARY, + signers = listOf(compKey, DUMMY_KEY_1.public, DUMMY_KEY_2.public), + type = TransactionType.General, + timestamp = null + ) + assertEquals( + setOf(compKey, DUMMY_KEY_2.public), + assertFailsWith { makeSigned(wtx, DUMMY_KEY_1).verifySignatures() }.missing + ) + + assertEquals( + setOf(compKey, DUMMY_KEY_2.public), + assertFailsWith { makeSigned(wtx, DUMMY_KEY_1, ak).verifySignatures() }.missing + ) + makeSigned(wtx, DUMMY_KEY_1, DUMMY_KEY_2, ak, bk).verifySignatures() + makeSigned(wtx, DUMMY_KEY_1, DUMMY_KEY_2, ck).verifySignatures() + makeSigned(wtx, DUMMY_KEY_1, DUMMY_KEY_2, ak, bk, ck).verifySignatures() + makeSigned(wtx, DUMMY_KEY_1, DUMMY_KEY_2, ak).verifySignatures(compKey) + makeSigned(wtx, DUMMY_KEY_1, ak).verifySignatures(compKey, DUMMY_KEY_2.public) // Mixed allowed to be missing. + } + @Test fun `signed transaction missing signatures`() { val wtx = WireTransaction( @@ -30,31 +73,29 @@ class TransactionTests { outputs = emptyList(), commands = emptyList(), notary = DUMMY_NOTARY, - signers = listOf(DUMMY_KEY_1.public.composite, DUMMY_KEY_2.public.composite), + signers = listOf(DUMMY_KEY_1.public, DUMMY_KEY_2.public), type = TransactionType.General, timestamp = null ) - val bytes: SerializedBytes = wtx.serialized - fun make(vararg keys: KeyPair) = SignedTransaction(bytes, keys.map { it.signWithECDSA(wtx.id.bytes) }) - assertFailsWith { make().verifySignatures() } + assertFailsWith { makeSigned(wtx).verifySignatures() } assertEquals( - setOf(DUMMY_KEY_1.public.composite), - assertFailsWith { make(DUMMY_KEY_2).verifySignatures() }.missing + setOf(DUMMY_KEY_1.public), + assertFailsWith { makeSigned(wtx, DUMMY_KEY_2).verifySignatures() }.missing ) assertEquals( - setOf(DUMMY_KEY_2.public.composite), - assertFailsWith { make(DUMMY_KEY_1).verifySignatures() }.missing + setOf(DUMMY_KEY_2.public), + assertFailsWith { makeSigned(wtx, DUMMY_KEY_1).verifySignatures() }.missing ) assertEquals( - setOf(DUMMY_KEY_2.public.composite), - assertFailsWith { make(DUMMY_CASH_ISSUER_KEY).verifySignatures(DUMMY_KEY_1.public.composite) }.missing + setOf(DUMMY_KEY_2.public), + assertFailsWith { makeSigned(wtx, DUMMY_CASH_ISSUER_KEY).verifySignatures(DUMMY_KEY_1.public) }.missing ) - make(DUMMY_KEY_1).verifySignatures(DUMMY_KEY_2.public.composite) - make(DUMMY_KEY_2).verifySignatures(DUMMY_KEY_1.public.composite) + makeSigned(wtx, DUMMY_KEY_1).verifySignatures(DUMMY_KEY_2.public) + makeSigned(wtx, DUMMY_KEY_2).verifySignatures(DUMMY_KEY_1.public) - make(DUMMY_KEY_1, DUMMY_KEY_2).verifySignatures() + makeSigned(wtx, DUMMY_KEY_1, DUMMY_KEY_2).verifySignatures() } @Test @@ -65,7 +106,7 @@ class TransactionTests { val commands = emptyList>() val attachments = emptyList() val id = SecureHash.randomSHA256() - val signers = listOf(DUMMY_NOTARY_KEY.public.composite) + val signers = listOf(DUMMY_NOTARY_KEY.public) val timestamp: Timestamp? = null val transaction: LedgerTransaction = LedgerTransaction( inputs, @@ -92,7 +133,7 @@ class TransactionTests { val commands = emptyList>() val attachments = emptyList() val id = SecureHash.randomSHA256() - val signers = listOf(DUMMY_NOTARY_KEY.public.composite) + val signers = listOf(DUMMY_NOTARY_KEY.public) val timestamp: Timestamp? = null val transaction: LedgerTransaction = LedgerTransaction( inputs, @@ -119,7 +160,7 @@ class TransactionTests { val commands = emptyList>() val attachments = emptyList() val id = SecureHash.randomSHA256() - val signers = listOf(DUMMY_NOTARY_KEY.public.composite) + val signers = listOf(DUMMY_NOTARY_KEY.public) val timestamp: Timestamp? = null val transaction: LedgerTransaction = LedgerTransaction( inputs, diff --git a/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt b/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt index 9a323334c2..a7d6f01639 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt @@ -3,6 +3,8 @@ package net.corda.core.crypto import net.corda.core.serialization.OpaqueBytes import org.junit.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse import kotlin.test.assertTrue class CompositeKeyTests { @@ -10,9 +12,9 @@ class CompositeKeyTests { val bobKey = generateKeyPair() val charlieKey = generateKeyPair() - val alicePublicKey = CompositeKey.Leaf(aliceKey.public) - val bobPublicKey = CompositeKey.Leaf(bobKey.public) - val charliePublicKey = CompositeKey.Leaf(charlieKey.public) + val alicePublicKey = aliceKey.public + val bobPublicKey = bobKey.public + val charliePublicKey = charlieKey.public val message = OpaqueBytes("Transaction".toByteArray()) @@ -54,8 +56,35 @@ class CompositeKeyTests { val aliceAndBobOrCharlie = CompositeKey.Builder().addKeys(aliceAndBob, charliePublicKey).build(threshold = 1) val encoded = aliceAndBobOrCharlie.toBase58String() - val decoded = CompositeKey.parseFromBase58(encoded) + val decoded = parsePublicKeyBase58(encoded) assertEquals(decoded, aliceAndBobOrCharlie) } + + @Test + fun `tree canonical form`() { + assertEquals(CompositeKey.Builder().addKeys(alicePublicKey).build(), alicePublicKey) + val node1 = CompositeKey.Builder().addKeys(alicePublicKey, bobPublicKey).build(1) // threshold = 1 + val node2 = CompositeKey.Builder().addKeys(alicePublicKey, bobPublicKey).build(2) // threshold = 2 + assertFalse(node2.isFulfilledBy(alicePublicKey)) + // Ordering by weight. + val tree1 = CompositeKey.Builder().addKey(node1, 13).addKey(node2, 27).build() + val tree2 = CompositeKey.Builder().addKey(node2, 27).addKey(node1, 13).build() + assertEquals(tree1, tree2) + assertEquals(tree1.hashCode(), tree2.hashCode()) + + // Ordering by node, weights the same. + val tree3 = CompositeKey.Builder().addKeys(node1, node2).build() + val tree4 = CompositeKey.Builder().addKeys(node2, node1).build() + assertEquals(tree3, tree4) + assertEquals(tree3.hashCode(), tree4.hashCode()) + + // Duplicate node cases. + val tree5 = CompositeKey.Builder().addKey(node1, 3).addKey(node1, 14).build() + val tree6 = CompositeKey.Builder().addKey(node1, 14).addKey(node1, 3).build() + assertEquals(tree5, tree6) + + // Chain of single nodes should throw. + assertEquals(CompositeKey.Builder().addKeys(tree1).build(), tree1) + } } diff --git a/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt b/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt index 29741c83fa..4956ecc1f5 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt @@ -15,6 +15,7 @@ import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP_PUBKEY import net.corda.testing.ledger import org.junit.Test +import java.security.PublicKey import kotlin.test.* class PartialMerkleTreeTest { @@ -99,7 +100,7 @@ class PartialMerkleTreeTest { is TransactionState<*> -> elem.data.participants[0].keys == DUMMY_PUBKEY_1.keys is Command -> MEGA_CORP_PUBKEY in elem.signers is Timestamp -> true - is CompositeKey -> elem == MEGA_CORP_PUBKEY + is PublicKey -> elem == MEGA_CORP_PUBKEY else -> false } } diff --git a/core/src/test/kotlin/net/corda/core/crypto/PartyTest.kt b/core/src/test/kotlin/net/corda/core/crypto/PartyTest.kt index f68f790d10..f95ffa93b1 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/PartyTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/PartyTest.kt @@ -8,8 +8,8 @@ import kotlin.test.assertNotEquals class PartyTest { @Test fun `equality`() { - val key = entropyToKeyPair(BigInteger.valueOf(20170207L)).public.composite - val differentKey = entropyToKeyPair(BigInteger.valueOf(7201702L)).public.composite + val key = entropyToKeyPair(BigInteger.valueOf(20170207L)).public + val differentKey = entropyToKeyPair(BigInteger.valueOf(7201702L)).public val anonymousParty = AnonymousParty(key) val party = Party("test key", key) assertEquals(party, anonymousParty) diff --git a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt index 735dd7bff9..a0ba0eed78 100644 --- a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt +++ b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt @@ -2,7 +2,6 @@ package net.corda.core.flows import net.corda.contracts.asset.Cash import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.getOrThrow @@ -27,6 +26,7 @@ import java.util.concurrent.ExecutionException import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue +import java.security.* class ContractUpgradeFlowTest { lateinit var mockNet: MockNetwork @@ -175,15 +175,15 @@ class ContractUpgradeFlowTest { class CashV2 : UpgradedContract { override val legacyContract = Cash::class.java - data class State(override val amount: Amount>, val owners: List) : FungibleAsset { - override val owner: CompositeKey = owners.first() + data class State(override val amount: Amount>, val owners: List) : FungibleAsset { + override val owner: PublicKey = owners.first() override val exitKeys = (owners + amount.token.issuer.party.owningKey).toSet() override val contract = CashV2() override val participants = owners - override fun move(newAmount: Amount>, newOwner: CompositeKey) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner)) + override fun move(newAmount: Amount>, newOwner: PublicKey) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner)) override fun toString() = "${Emoji.bagOfCash}New Cash($amount at ${amount.token.issuer} owned by $owner)" - override fun withNewOwner(newOwner: CompositeKey) = Pair(Cash.Commands.Move(), copy(owners = listOf(newOwner))) + override fun withNewOwner(newOwner: PublicKey) = Pair(Cash.Commands.Move(), copy(owners = listOf(newOwner))) } override fun upgrade(state: Cash.State) = CashV2.State(state.amount.times(1000), listOf(state.owner)) diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt index edfbf46c7d..2bca0400d6 100644 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt +++ b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt @@ -1,11 +1,11 @@ package net.corda.core.flows import co.paralleluniverse.fibers.Suspendable -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.node.PluginServiceHub import net.corda.core.utilities.ProgressTracker import net.corda.flows.TxKeyFlowUtilities +import java.security.PublicKey import java.security.cert.Certificate /** @@ -19,7 +19,7 @@ object TxKeyFlow { } class Requester(val otherSide: Party, - override val progressTracker: ProgressTracker) : FlowLogic>() { + override val progressTracker: ProgressTracker) : FlowLogic>() { constructor(otherSide: Party) : this(otherSide, tracker()) companion object { @@ -29,7 +29,7 @@ object TxKeyFlow { } @Suspendable - override fun call(): Pair { + override fun call(): Pair { progressTracker.currentStep = AWAITING_KEY return TxKeyFlowUtilities.receiveKey(this, otherSide) } @@ -40,7 +40,7 @@ object TxKeyFlow { * counterparty and as the result from the flow. */ class Provider(val otherSide: Party, - override val progressTracker: ProgressTracker) : FlowLogic() { + override val progressTracker: ProgressTracker) : FlowLogic() { constructor(otherSide: Party) : this(otherSide, tracker()) companion object { @@ -50,7 +50,7 @@ object TxKeyFlow { } @Suspendable - override fun call(): CompositeKey { + override fun call(): PublicKey { progressTracker.currentStep == SENDING_KEY return TxKeyFlowUtilities.provideKey(this, otherSide) } diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt index 40c070f438..5432b2202d 100644 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt @@ -1,6 +1,5 @@ package net.corda.core.flows -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.utilities.DUMMY_NOTARY import net.corda.testing.ALICE @@ -9,6 +8,7 @@ import net.corda.testing.MOCK_IDENTITY_SERVICE import net.corda.testing.node.MockNetwork import org.junit.Before import org.junit.Test +import java.security.PublicKey import kotlin.test.assertNotNull class TxKeyFlowUtilitiesTests { @@ -36,7 +36,7 @@ class TxKeyFlowUtilitiesTests { val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bobKey)) // Get the results - val actual: CompositeKey = requesterFlow.resultFuture.get().first + val actual: PublicKey = requesterFlow.resultFuture.get().first assertNotNull(actual) } -} \ No newline at end of file +} diff --git a/core/src/test/kotlin/net/corda/core/node/AttachmentClassLoaderTests.kt b/core/src/test/kotlin/net/corda/core/node/AttachmentClassLoaderTests.kt index ba4fcdcc1a..95516e58b5 100644 --- a/core/src/test/kotlin/net/corda/core/node/AttachmentClassLoaderTests.kt +++ b/core/src/test/kotlin/net/corda/core/node/AttachmentClassLoaderTests.kt @@ -2,7 +2,6 @@ package net.corda.core.node import com.esotericsoftware.kryo.Kryo import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.node.services.AttachmentStorage @@ -18,6 +17,7 @@ import org.junit.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.net.URLClassLoader +import java.security.PublicKey import java.util.jar.JarOutputStream import java.util.zip.ZipEntry import kotlin.test.assertEquals @@ -39,7 +39,7 @@ class AttachmentClassLoaderTests { class AttachmentDummyContract : Contract { data class State(val magicNumber: Int = 0) : ContractState { override val contract = ATTACHMENT_TEST_PROGRAM_ID - override val participants: List + override val participants: List get() = listOf() } diff --git a/core/src/test/kotlin/net/corda/core/node/VaultUpdateTests.kt b/core/src/test/kotlin/net/corda/core/node/VaultUpdateTests.kt index 8964357beb..a5e5dbd951 100644 --- a/core/src/test/kotlin/net/corda/core/node/VaultUpdateTests.kt +++ b/core/src/test/kotlin/net/corda/core/node/VaultUpdateTests.kt @@ -1,11 +1,11 @@ package net.corda.core.node import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.node.services.Vault import net.corda.core.utilities.DUMMY_NOTARY import org.junit.Test +import java.security.PublicKey import kotlin.test.assertEquals @@ -20,7 +20,7 @@ class VaultUpdateTests { } private class DummyState : ContractState { - override val participants: List + override val participants: List get() = emptyList() override val contract = VaultUpdateTests.DummyContract } diff --git a/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt b/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt index 8be0537665..8108ac17f3 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt @@ -1,9 +1,7 @@ package net.corda.core.serialization import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash -import net.corda.core.crypto.composite import net.corda.core.seconds import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.* @@ -11,6 +9,7 @@ import net.corda.testing.MINI_CORP import net.corda.testing.generateStateRef import org.junit.Before import org.junit.Test +import java.security.PublicKey import java.security.SignatureException import java.util.* import kotlin.test.assertEquals @@ -28,12 +27,12 @@ class TransactionSerializationTests { data class State( val deposit: PartyAndReference, val amount: Amount, - override val owner: CompositeKey) : OwnableState { + override val owner: PublicKey) : OwnableState { override val contract: Contract = TEST_PROGRAM_ID - override val participants: List + override val participants: List get() = listOf(owner) - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) } interface Commands : CommandData { @@ -47,7 +46,7 @@ class TransactionSerializationTests { val fakeStateRef = generateStateRef() val inputState = StateAndRef(TransactionState(TestCash.State(depositRef, 100.POUNDS, DUMMY_PUBKEY_1), DUMMY_NOTARY), fakeStateRef) val outputState = TransactionState(TestCash.State(depositRef, 600.POUNDS, DUMMY_PUBKEY_1), DUMMY_NOTARY) - val changeState = TransactionState(TestCash.State(depositRef, 400.POUNDS, DUMMY_KEY_1.public.composite), DUMMY_NOTARY) + val changeState = TransactionState(TestCash.State(depositRef, 400.POUNDS, DUMMY_KEY_1.public), DUMMY_NOTARY) lateinit var tx: TransactionBuilder @@ -55,7 +54,7 @@ class TransactionSerializationTests { @Before fun setup() { tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems( - inputState, outputState, changeState, Command(TestCash.Commands.Move(), arrayListOf(DUMMY_KEY_1.public.composite)) + inputState, outputState, changeState, Command(TestCash.Commands.Move(), arrayListOf(DUMMY_KEY_1.public)) ) } @@ -94,7 +93,7 @@ class TransactionSerializationTests { // If the signature was replaced in transit, we don't like it. assertFailsWith(SignatureException::class) { val tx2 = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState, outputState, changeState, - Command(TestCash.Commands.Move(), DUMMY_KEY_2.public.composite)) + Command(TestCash.Commands.Move(), DUMMY_KEY_2.public)) tx2.signWith(DUMMY_NOTARY_KEY) tx2.signWith(DUMMY_KEY_2) diff --git a/core/src/test/kotlin/net/corda/core/testing/Generators.kt b/core/src/test/kotlin/net/corda/core/testing/Generators.kt index 9fd14dedfc..8c53f1c186 100644 --- a/core/src/test/kotlin/net/corda/core/testing/Generators.kt +++ b/core/src/test/kotlin/net/corda/core/testing/Generators.kt @@ -33,27 +33,22 @@ class PrivateKeyGenerator : Generator(PrivateKey::class.java) { } } +// TODO add CompositeKeyGenerator that actually does something useful. class PublicKeyGenerator : Generator(PublicKey::class.java) { override fun generate(random: SourceOfRandomness, status: GenerationStatus): PublicKey { return entropyToKeyPair(random.nextBigInteger(32)).public } } -class CompositeKeyGenerator : Generator(CompositeKey::class.java) { - override fun generate(random: SourceOfRandomness, status: GenerationStatus): CompositeKey { - return entropyToKeyPair(random.nextBigInteger(32)).public.composite - } -} - class AnonymousPartyGenerator : Generator(AnonymousParty::class.java) { override fun generate(random: SourceOfRandomness, status: GenerationStatus): AnonymousParty { - return AnonymousParty(CompositeKeyGenerator().generate(random, status)) + return AnonymousParty(PublicKeyGenerator().generate(random, status)) } } class PartyGenerator : Generator(Party::class.java) { override fun generate(random: SourceOfRandomness, status: GenerationStatus): Party { - return Party(StringGenerator().generate(random, status), CompositeKeyGenerator().generate(random, status)) + return Party(StringGenerator().generate(random, status), PublicKeyGenerator().generate(random, status)) } } diff --git a/docs/source/contract-upgrade.rst b/docs/source/contract-upgrade.rst index aa34df8915..9b8b9ed9d6 100644 --- a/docs/source/contract-upgrade.rst +++ b/docs/source/contract-upgrade.rst @@ -86,35 +86,10 @@ Bank A and Bank B decided to upgrade the contract to ``DummyContractV2`` 1. Developer will create a new contract extending the ``UpgradedContract`` class, and a new state object ``DummyContractV2.State`` referencing the new contract. -.. container:: codeset - - .. sourcecode:: kotlin - - class DummyContractV2 : UpgradedContract { - override val legacyContract = DummyContract::class.java - - data class State(val magicNumber: Int = 0, val owners: List) : ContractState { - override val contract = DUMMY_V2_PROGRAM_ID - override val participants: List = owners - } - - interface Commands : CommandData { - class Create : TypeOnlyCommandData(), Commands - class Move : TypeOnlyCommandData(), Commands - } - - override fun upgrade(state: DummyContract.State): DummyContractV2.State { - return DummyContractV2.State(state.magicNumber, state.participants) - } - - override fun verify(tx: TransactionForContract) { - if (tx.commands.any { it.value is UpgradeCommand }) ContractUpgradeFlow.verify(tx) - // Other verifications. - } - - // The "empty contract" - override val legalContractReference: SecureHash = SecureHash.sha256("") - } +.. literalinclude:: /../../core/src/main/kotlin/net/corda/core/contracts/DummyContractV2.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 2. Bank A will instruct its node to accept the contract upgrade to ``DummyContractV2`` for the contract state. diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt index cb2190a265..5969ee57e7 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt @@ -62,7 +62,7 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash override val contract: TradeApprovalContract = TradeApprovalContract()) : LinearState { val parties: List get() = listOf(source, counterparty) - override val participants: List get() = parties.map { it.owningKey } + override val participants: List get() = parties.map { it.owningKey } override fun isRelevant(ourKeys: Set): Boolean { return participants.any { it.containsAny(ourKeys) } diff --git a/docs/source/flow-state-machines.rst b/docs/source/flow-state-machines.rst index 908d4be29f..f83681771f 100644 --- a/docs/source/flow-state-machines.rst +++ b/docs/source/flow-state-machines.rst @@ -121,7 +121,7 @@ each side. data class SellerTradeInfo( val assetForSale: StateAndRef, val price: Amount, - val sellerOwnerKey: CompositeKey + val sellerOwnerKey: PublicKey ) data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey, diff --git a/docs/source/key-concepts-core-types.rst b/docs/source/key-concepts-core-types.rst index dc930342ed..724861ac44 100644 --- a/docs/source/key-concepts-core-types.rst +++ b/docs/source/key-concepts-core-types.rst @@ -19,7 +19,7 @@ A number of interfaces then extend ``ContractState``, representing standardised of state such as: ``OwnableState`` - A state which has an owner (represented as a ``CompositeKey``, discussed later). Exposes the owner and a function + A state which has an owner (represented as a ``PublicKey`` which can be a ``CompositeKey``, discussed later). Exposes the owner and a function for replacing the owner e.g. when an asset is sold. ``SchedulableState`` @@ -90,7 +90,7 @@ keys under their control. Parties can be represented either in full (including name) or pseudonymously, using the ``Party`` or ``AnonymousParty`` classes respectively. For example, in a transaction sent to your node as part of a chain of custody it is important you can convince yourself of the transaction's validity, but equally important that you don't learn anything about who was -involved in that transaction. In these cases ``AnonymousParty`` should be used, which contains a composite public key +involved in that transaction. In these cases ``AnonymousParty`` should be used, which contains a public key (may be a composite key) without any identifying information about who owns it. In contrast, for internal processing where extended details of a party are required, the ``Party`` class should be used. The identity service provides functionality for resolving anonymous parties to full parties. diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt index 582586dbe6..1b850c23f3 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt @@ -2,11 +2,11 @@ package net.corda.contracts.universal import net.corda.core.contracts.BusinessCalendar import net.corda.core.contracts.Tenor -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.serialization.CordaSerializable import java.lang.reflect.Type import java.math.BigDecimal +import java.security.PublicKey import java.time.Instant import java.time.LocalDate import java.util.* @@ -153,7 +153,7 @@ operator fun Perceivable.div(n: Double) = PerceivableOperation(this, operator fun Perceivable.plus(n: Int) = PerceivableOperation(this, Operation.PLUS, const(n)) operator fun Perceivable.minus(n: Int) = PerceivableOperation(this, Operation.MINUS, const(n)) -data class TerminalEvent(val reference: Party, val source: CompositeKey) : Perceivable +data class TerminalEvent(val reference: Party, val source: PublicKey) : Perceivable // todo: holidays data class Interest(val amount: Perceivable, val dayCountConvention: String, diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/PrettyPrint.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/PrettyPrint.kt index 65860c85c1..b16582c74a 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/PrettyPrint.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/PrettyPrint.kt @@ -1,8 +1,8 @@ package net.corda.contracts.universal -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import java.math.BigDecimal +import java.security.PublicKey import java.time.Instant private class PrettyPrint(arr : Arrangement) { @@ -41,7 +41,7 @@ private class PrettyPrint(arr : Arrangement) { return rv } - val partyMap = mutableMapOf() + val partyMap = mutableMapOf() val usedPartyNames = mutableSetOf() fun createPartyName(party : Party) : String diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt index c0ff6828c3..58fb977d48 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt @@ -1,17 +1,17 @@ package net.corda.contracts.universal import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.transactions.TransactionBuilder import java.math.BigDecimal +import java.security.PublicKey import java.time.Instant val UNIVERSAL_PROGRAM_ID = UniversalContract() class UniversalContract : Contract { - data class State(override val participants: List, + data class State(override val participants: List, val details: Arrangement) : ContractState { override val contract = UNIVERSAL_PROGRAM_ID } @@ -316,7 +316,7 @@ class UniversalContract : Contract { override val legalContractReference: SecureHash get() = throw UnsupportedOperationException() - fun generateIssue(tx: TransactionBuilder, arrangement: Arrangement, at: PartyAndReference, notary: CompositeKey) { + fun generateIssue(tx: TransactionBuilder, arrangement: Arrangement, at: PartyAndReference, notary: PublicKey) { check(tx.inputStates().isEmpty()) tx.addOutputState(State(listOf(notary), arrangement)) tx.addCommand(Commands.Issue(), at.party.owningKey) diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt index f64b9ac829..8b4ca6705f 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt @@ -3,8 +3,8 @@ package net.corda.contracts.universal import com.google.common.collect.ImmutableSet import com.google.common.collect.Sets import net.corda.core.contracts.Frequency -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import java.security.PublicKey import java.time.Instant import java.time.LocalDate @@ -23,20 +23,20 @@ private fun signingParties(perceivable: Perceivable) : ImmutableSet throw IllegalArgumentException("signingParties " + perceivable) } -private fun liablePartiesVisitor(arrangement: Arrangement): ImmutableSet = +private fun liablePartiesVisitor(arrangement: Arrangement): ImmutableSet = when (arrangement) { - is Zero -> ImmutableSet.of() + is Zero -> ImmutableSet.of() is Obligation -> ImmutableSet.of(arrangement.from.owningKey) is And -> - arrangement.arrangements.fold(ImmutableSet.builder(), { builder, k -> builder.addAll(liablePartiesVisitor(k)) }).build() + arrangement.arrangements.fold(ImmutableSet.builder(), { builder, k -> builder.addAll(liablePartiesVisitor(k)) }).build() is Actions -> - arrangement.actions.fold(ImmutableSet.builder(), { builder, k -> builder.addAll(liablePartiesVisitor(k)) }).build() + arrangement.actions.fold(ImmutableSet.builder(), { builder, k -> builder.addAll(liablePartiesVisitor(k)) }).build() is RollOut -> liablePartiesVisitor(arrangement.template) - is Continuation -> ImmutableSet.of() + is Continuation -> ImmutableSet.of() else -> throw IllegalArgumentException("liableParties " + arrangement) } -private fun liablePartiesVisitor(action: Action): ImmutableSet { +private fun liablePartiesVisitor(action: Action): ImmutableSet { val actors = signingParties(action.condition) return if (actors.size != 1) liablePartiesVisitor(action.arrangement) @@ -45,7 +45,7 @@ private fun liablePartiesVisitor(action: Action): ImmutableSet { } /** Returns list of potentially liable parties for a given contract */ -fun liableParties(contract: Arrangement): Set = liablePartiesVisitor(contract) +fun liableParties(contract: Arrangement): Set = liablePartiesVisitor(contract) private fun involvedPartiesVisitor(action: Action): Set = Sets.union(involvedPartiesVisitor(action.arrangement), signingParties(action.condition)).immutableCopy() diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt index 4c733af6da..f6f6015b8b 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt @@ -1,7 +1,6 @@ package net.corda.contracts.universal import net.corda.core.crypto.Party -import net.corda.core.crypto.composite import net.corda.core.crypto.generateKeyPair import org.junit.Test import java.util.* @@ -11,7 +10,7 @@ val acmeCorp = Party("ACME Corporation", generateKeyPair().public) val highStreetBank = Party("High Street Bank", generateKeyPair().public) val momAndPop = Party("Mom and Pop", generateKeyPair().public) -val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public.composite) +val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public) // Currencies diff --git a/finance/isolated/src/main/kotlin/net/corda/contracts/AnotherDummyContract.kt b/finance/isolated/src/main/kotlin/net/corda/contracts/AnotherDummyContract.kt index 113a13ea9e..6a2a60e846 100644 --- a/finance/isolated/src/main/kotlin/net/corda/contracts/AnotherDummyContract.kt +++ b/finance/isolated/src/main/kotlin/net/corda/contracts/AnotherDummyContract.kt @@ -1,10 +1,10 @@ package net.corda.contracts.isolated import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey // The dummy contract doesn't do anything useful. It exists for testing purposes. @@ -13,7 +13,7 @@ val ANOTHER_DUMMY_PROGRAM_ID = AnotherDummyContract() class AnotherDummyContract : Contract, net.corda.core.node.DummyContractBackdoor { data class State(val magicNumber: Int = 0) : ContractState { override val contract = ANOTHER_DUMMY_PROGRAM_ID - override val participants: List + override val participants: List get() = emptyList() } diff --git a/finance/src/main/java/net/corda/contracts/ICommercialPaperState.java b/finance/src/main/java/net/corda/contracts/ICommercialPaperState.java index 36e45581da..a907811919 100644 --- a/finance/src/main/java/net/corda/contracts/ICommercialPaperState.java +++ b/finance/src/main/java/net/corda/contracts/ICommercialPaperState.java @@ -1,8 +1,8 @@ package net.corda.contracts; import net.corda.core.contracts.*; -import net.corda.core.crypto.*; +import java.security.PublicKey; import java.time.*; import java.util.*; @@ -12,7 +12,7 @@ import java.util.*; * ultimately either language can be used against a common test framework (and therefore can be used for real). */ public interface ICommercialPaperState extends ContractState { - ICommercialPaperState withOwner(CompositeKey newOwner); + ICommercialPaperState withOwner(PublicKey newOwner); ICommercialPaperState withFaceValue(Amount> newFaceValue); diff --git a/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java b/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java index b32e85ab3b..41a9ae3ea5 100644 --- a/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java +++ b/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.*; import java.time.*; import java.util.*; import java.util.stream.*; +import java.security.PublicKey; import static kotlin.collections.CollectionsKt.*; import static net.corda.core.contracts.ContractsDSL.*; @@ -31,14 +32,14 @@ public class JavaCommercialPaper implements Contract { @SuppressWarnings("unused") public static class State implements OwnableState, ICommercialPaperState { private PartyAndReference issuance; - private CompositeKey owner; + private PublicKey owner; private Amount> faceValue; private Instant maturityDate; public State() { } // For serialization - public State(PartyAndReference issuance, CompositeKey owner, Amount> faceValue, + public State(PartyAndReference issuance, PublicKey owner, Amount> faceValue, Instant maturityDate) { this.issuance = issuance; this.owner = owner; @@ -50,13 +51,13 @@ public class JavaCommercialPaper implements Contract { return new State(this.issuance, this.owner, this.faceValue, this.maturityDate); } - public ICommercialPaperState withOwner(CompositeKey newOwner) { + public ICommercialPaperState withOwner(PublicKey newOwner) { return new State(this.issuance, newOwner, this.faceValue, this.maturityDate); } @NotNull @Override - public Pair withNewOwner(@NotNull CompositeKey newOwner) { + public Pair withNewOwner(@NotNull PublicKey newOwner) { return new Pair<>(new Commands.Move(), new State(this.issuance, newOwner, this.faceValue, this.maturityDate)); } @@ -73,7 +74,7 @@ public class JavaCommercialPaper implements Contract { } @NotNull - public CompositeKey getOwner() { + public PublicKey getOwner() { return owner; } @@ -114,12 +115,12 @@ public class JavaCommercialPaper implements Contract { } public State withoutOwner() { - return new State(issuance, CryptoUtilities.getNullCompositeKey(), faceValue, maturityDate); + return new State(issuance, NullPublicKey.INSTANCE, faceValue, maturityDate); } @NotNull @Override - public List getParticipants() { + public List getParticipants() { return ImmutableList.of(this.owner); } } @@ -316,7 +317,7 @@ public class JavaCommercialPaper implements Contract { tx.addCommand(new Command(new Commands.Redeem(), paper.getState().getData().getOwner())); } - public void generateMove(TransactionBuilder tx, StateAndRef paper, CompositeKey newOwner) { + public void generateMove(TransactionBuilder tx, StateAndRef paper, PublicKey newOwner) { tx.addInputState(paper); tx.addOutputState(new TransactionState<>(new State(paper.getState().getData().getIssuance(), newOwner, paper.getState().getData().getFaceValue(), paper.getState().getData().getMaturityDate()), paper.getState().getNotary(), paper.getState().getEncumbrance())); tx.addCommand(new Command(new Commands.Move(), paper.getState().getData().getOwner())); diff --git a/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt b/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt index 4be06d8b2c..eaaf912c03 100644 --- a/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt +++ b/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt @@ -7,9 +7,9 @@ import net.corda.core.contracts.clauses.AnyOf import net.corda.core.contracts.clauses.Clause import net.corda.core.contracts.clauses.GroupClauseVerifier import net.corda.core.contracts.clauses.verifyClause -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.toBase58String import net.corda.core.node.services.VaultService import net.corda.core.random63BitValue import net.corda.core.schemas.MappedSchema @@ -18,6 +18,7 @@ import net.corda.core.schemas.QueryableState import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.Emoji import net.corda.schemas.CommercialPaperSchemaV1 +import java.security.PublicKey import java.time.Instant import java.util.* @@ -59,22 +60,22 @@ class CommercialPaper : Contract { data class State( val issuance: PartyAndReference, - override val owner: CompositeKey, + override val owner: PublicKey, val faceValue: Amount>, val maturityDate: Instant ) : OwnableState, QueryableState, ICommercialPaperState { override val contract = CP_PROGRAM_ID - override val participants: List + override val participants: List get() = listOf(owner) val token: Issued get() = Issued(issuance, Terms(faceValue.token, maturityDate)) - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) override fun toString() = "${Emoji.newspaper}CommercialPaper(of $faceValue redeemable on $maturityDate by '$issuance', owned by $owner)" // Although kotlin is smart enough not to need these, as we are using the ICommercialPaperState, we need to declare them explicitly for use later, - override fun withOwner(newOwner: CompositeKey): ICommercialPaperState = copy(owner = newOwner) + override fun withOwner(newOwner: PublicKey): ICommercialPaperState = copy(owner = newOwner) override fun withFaceValue(newFaceValue: Amount>): ICommercialPaperState = copy(faceValue = newFaceValue) override fun withMaturityDate(newMaturityDate: Instant): ICommercialPaperState = copy(maturityDate = newMaturityDate) @@ -199,7 +200,7 @@ class CommercialPaper : Contract { /** * Updates the given partial transaction with an input/output/command to reassign ownership of the paper. */ - fun generateMove(tx: TransactionBuilder, paper: StateAndRef, newOwner: CompositeKey) { + fun generateMove(tx: TransactionBuilder, paper: StateAndRef, newOwner: PublicKey) { tx.addInputState(paper) tx.addOutputState(TransactionState(paper.state.data.copy(owner = newOwner), paper.state.notary)) tx.addCommand(Commands.Move(), paper.state.data.owner) @@ -222,8 +223,8 @@ class CommercialPaper : Contract { } } -infix fun CommercialPaper.State.`owned by`(owner: CompositeKey) = copy(owner = owner) +infix fun CommercialPaper.State.`owned by`(owner: PublicKey) = copy(owner = owner) infix fun CommercialPaper.State.`with notary`(notary: Party) = TransactionState(this, notary) -infix fun ICommercialPaperState.`owned by`(newOwner: CompositeKey) = withOwner(newOwner) +infix fun ICommercialPaperState.`owned by`(newOwner: PublicKey) = withOwner(newOwner) diff --git a/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt b/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt index e95e3678f1..6fa402c245 100644 --- a/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt +++ b/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt @@ -2,13 +2,13 @@ package net.corda.contracts import net.corda.contracts.asset.sumCashBy import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey -import net.corda.core.crypto.NullCompositeKey +import net.corda.core.crypto.NullPublicKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.node.services.VaultService import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.Emoji +import java.security.PublicKey import java.time.Instant import java.util.* @@ -26,19 +26,19 @@ class CommercialPaperLegacy : Contract { data class State( val issuance: PartyAndReference, - override val owner: CompositeKey, + override val owner: PublicKey, val faceValue: Amount>, val maturityDate: Instant ) : OwnableState, ICommercialPaperState { override val contract = CP_LEGACY_PROGRAM_ID override val participants = listOf(owner) - fun withoutOwner() = copy(owner = NullCompositeKey) - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(owner = newOwner)) + fun withoutOwner() = copy(owner = NullPublicKey) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) override fun toString() = "${Emoji.newspaper}CommercialPaper(of $faceValue redeemable on $maturityDate by '$issuance', owned by $owner)" // Although kotlin is smart enough not to need these, as we are using the ICommercialPaperState, we need to declare them explicitly for use later, - override fun withOwner(newOwner: CompositeKey): ICommercialPaperState = copy(owner = newOwner) + override fun withOwner(newOwner: PublicKey): ICommercialPaperState = copy(owner = newOwner) override fun withFaceValue(newFaceValue: Amount>): ICommercialPaperState = copy(faceValue = newFaceValue) override fun withMaturityDate(newMaturityDate: Instant): ICommercialPaperState = copy(maturityDate = newMaturityDate) @@ -117,7 +117,7 @@ class CommercialPaperLegacy : Contract { return TransactionBuilder(notary = notary).withItems(state, Command(Commands.Issue(), issuance.party.owningKey)) } - fun generateMove(tx: TransactionBuilder, paper: StateAndRef, newOwner: CompositeKey) { + fun generateMove(tx: TransactionBuilder, paper: StateAndRef, newOwner: PublicKey) { tx.addInputState(paper) tx.addOutputState(paper.state.data.withOwner(newOwner)) tx.addCommand(Command(Commands.Move(), paper.state.data.owner)) diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt b/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt index cea84f6cc0..4b160d1681 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt @@ -17,6 +17,7 @@ import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.Emoji import net.corda.schemas.CashSchemaV1 import java.math.BigInteger +import java.security.PublicKey import java.util.* ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -84,21 +85,21 @@ class Cash : OnLedgerAsset() { override val amount: Amount>, /** There must be a MoveCommand signed by this key to claim the amount. */ - override val owner: CompositeKey + override val owner: PublicKey ) : FungibleAsset, QueryableState { - constructor(deposit: PartyAndReference, amount: Amount, owner: CompositeKey) + constructor(deposit: PartyAndReference, amount: Amount, owner: PublicKey) : this(Amount(amount.quantity, Issued(deposit, amount.token)), owner) override val exitKeys = setOf(owner, amount.token.issuer.party.owningKey) override val contract = CASH_PROGRAM_ID override val participants = listOf(owner) - override fun move(newAmount: Amount>, newOwner: CompositeKey): FungibleAsset + override fun move(newAmount: Amount>, newOwner: PublicKey): FungibleAsset = copy(amount = amount.copy(newAmount.quantity), owner = newOwner) override fun toString() = "${Emoji.bagOfCash}Cash($amount at ${amount.token.issuer} owned by $owner)" - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) /** Object Relational Mapping support. */ override fun generateMappedObject(schema: MappedSchema): PersistentState { @@ -145,13 +146,13 @@ class Cash : OnLedgerAsset() { /** * Puts together an issuance transaction from the given template, that starts out being owned by the given pubkey. */ - fun generateIssue(tx: TransactionBuilder, tokenDef: Issued, pennies: Long, owner: CompositeKey, notary: Party) + fun generateIssue(tx: TransactionBuilder, tokenDef: Issued, pennies: Long, owner: PublicKey, notary: Party) = generateIssue(tx, Amount(pennies, tokenDef), owner, notary) /** * Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey. */ - fun generateIssue(tx: TransactionBuilder, amount: Amount>, owner: CompositeKey, notary: Party) { + fun generateIssue(tx: TransactionBuilder, amount: Amount>, owner: PublicKey, notary: Party) { check(tx.inputStates().isEmpty()) check(tx.outputStates().map { it.data }.sumCashOrNull() == null) require(amount.quantity > 0) @@ -160,7 +161,7 @@ class Cash : OnLedgerAsset() { tx.addCommand(generateIssueCommand(), at.party.owningKey) } - override fun deriveState(txState: TransactionState, amount: Amount>, owner: CompositeKey) + override fun deriveState(txState: TransactionState, amount: Amount>, owner: PublicKey) = txState.copy(data = txState.data.copy(amount = amount, owner = owner)) override fun generateExitCommand(amount: Amount>) = Commands.Exit(amount) @@ -178,7 +179,7 @@ class Cash : OnLedgerAsset() { * if there are none, or if any of the cash states cannot be added together (i.e. are * different currencies or issuers). */ -fun Iterable.sumCashBy(owner: CompositeKey): Amount> = filterIsInstance().filter { it.owner == owner }.map { it.amount }.sumOrThrow() +fun Iterable.sumCashBy(owner: PublicKey): Amount> = filterIsInstance().filter { it.owner == owner }.map { it.amount }.sumOrThrow() /** * Sums the cash states in the list, throwing an exception if there are none, or if any of the cash @@ -194,12 +195,12 @@ fun Iterable.sumCashOrZero(currency: Issued): Amount().map { it.amount }.sumOrZero(currency) } -fun Cash.State.ownedBy(owner: CompositeKey) = copy(owner = owner) +fun Cash.State.ownedBy(owner: PublicKey) = copy(owner = owner) fun Cash.State.issuedBy(party: AbstractParty) = copy(amount = Amount(amount.quantity, amount.token.copy(issuer = amount.token.issuer.copy(party = party.toAnonymous())))) fun Cash.State.issuedBy(deposit: PartyAndReference) = copy(amount = Amount(amount.quantity, amount.token.copy(issuer = deposit))) fun Cash.State.withDeposit(deposit: PartyAndReference): Cash.State = copy(amount = amount.copy(token = amount.token.copy(issuer = deposit))) -infix fun Cash.State.`owned by`(owner: CompositeKey) = ownedBy(owner) +infix fun Cash.State.`owned by`(owner: PublicKey) = ownedBy(owner) infix fun Cash.State.`issued by`(party: AbstractParty) = issuedBy(party) infix fun Cash.State.`issued by`(deposit: PartyAndReference) = issuedBy(deposit) infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = withDeposit(deposit) @@ -209,8 +210,8 @@ infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = wi /** A randomly generated key. */ val DUMMY_CASH_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) } /** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */ -val DUMMY_CASH_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public.composite).ref(1) } +val DUMMY_CASH_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public).ref(1) } /** An extension property that lets you write 100.DOLLARS.CASH */ -val Amount.CASH: Cash.State get() = Cash.State(Amount(quantity, Issued(DUMMY_CASH_ISSUER, token)), NullCompositeKey) +val Amount.CASH: Cash.State get() = Cash.State(Amount(quantity, Issued(DUMMY_CASH_ISSUER, token)), NullPublicKey) /** An extension property that lets you get a cash state from an issued token, under the [NullPublicKey] */ -val Amount>.STATE: Cash.State get() = Cash.State(this, NullCompositeKey) +val Amount>.STATE: Cash.State get() = Cash.State(this, NullPublicKey) diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt b/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt index 34d2e38e21..e8d31c23f8 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt @@ -7,12 +7,12 @@ import net.corda.core.contracts.* import net.corda.core.contracts.clauses.AnyOf import net.corda.core.contracts.clauses.GroupClauseVerifier import net.corda.core.contracts.clauses.verifyClause -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.crypto.newSecureRandom import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey import java.util.* ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -96,21 +96,21 @@ class CommodityContract : OnLedgerAsset>, /** There must be a MoveCommand signed by this key to claim the amount */ - override val owner: CompositeKey + override val owner: PublicKey ) : FungibleAsset { - constructor(deposit: PartyAndReference, amount: Amount, owner: CompositeKey) + constructor(deposit: PartyAndReference, amount: Amount, owner: PublicKey) : this(Amount(amount.quantity, Issued(deposit, amount.token)), owner) override val contract = COMMODITY_PROGRAM_ID override val exitKeys = Collections.singleton(owner) override val participants = listOf(owner) - override fun move(newAmount: Amount>, newOwner: CompositeKey): FungibleAsset + override fun move(newAmount: Amount>, newOwner: PublicKey): FungibleAsset = copy(amount = amount.copy(newAmount.quantity), owner = newOwner) override fun toString() = "Commodity($amount at ${amount.token.issuer} owned by $owner)" - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) } // Just for grouping @@ -147,13 +147,13 @@ class CommodityContract : OnLedgerAsset, pennies: Long, owner: CompositeKey, notary: Party) + fun generateIssue(tx: TransactionBuilder, tokenDef: Issued, pennies: Long, owner: PublicKey, notary: Party) = generateIssue(tx, Amount(pennies, tokenDef), owner, notary) /** * Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey. */ - fun generateIssue(tx: TransactionBuilder, amount: Amount>, owner: CompositeKey, notary: Party) { + fun generateIssue(tx: TransactionBuilder, amount: Amount>, owner: PublicKey, notary: Party) { check(tx.inputStates().isEmpty()) check(tx.outputStates().map { it.data }.sumCashOrNull() == null) val at = amount.token.issuer @@ -162,7 +162,7 @@ class CommodityContract : OnLedgerAsset, amount: Amount>, owner: CompositeKey) + override fun deriveState(txState: TransactionState, amount: Amount>, owner: PublicKey) = txState.copy(data = txState.data.copy(amount = amount, owner = owner)) override fun generateExitCommand(amount: Amount>) = Commands.Exit(amount) diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt b/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt index 9bf01f945d..df7f164c6d 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt @@ -14,6 +14,7 @@ import net.corda.core.utilities.NonEmptySet import net.corda.core.utilities.TEST_TX_TIME import net.corda.core.utilities.nonEmptySetOf import java.math.BigInteger +import java.security.PublicKey import java.time.Duration import java.time.Instant import java.util.* @@ -273,23 +274,23 @@ class Obligation

: Contract { val template: Terms

, val quantity: Long, /** The public key of the entity the contract pays to */ - val beneficiary: CompositeKey + val beneficiary: PublicKey ) : FungibleAsset>, NettableState, MultilateralNetState

> { constructor(lifecycle: Lifecycle = Lifecycle.NORMAL, obligor: Party, template: Terms

, quantity: Long, - beneficiary: CompositeKey) + beneficiary: PublicKey) : this(lifecycle, obligor.toAnonymous(), template, quantity, beneficiary) override val amount: Amount>> = Amount(quantity, Issued(obligor.ref(0), template)) override val contract = OBLIGATION_PROGRAM_ID - override val exitKeys: Collection = setOf(beneficiary) + override val exitKeys: Collection = setOf(beneficiary) val dueBefore: Instant = template.dueBefore - override val participants: List = listOf(obligor.owningKey, beneficiary) - override val owner: CompositeKey = beneficiary + override val participants: List = listOf(obligor.owningKey, beneficiary) + override val owner: PublicKey = beneficiary - override fun move(newAmount: Amount>>, newOwner: CompositeKey): State

+ override fun move(newAmount: Amount>>, newOwner: PublicKey): State

= copy(quantity = newAmount.quantity, beneficiary = newOwner) override fun toString() = when (lifecycle) { @@ -322,7 +323,7 @@ class Obligation

: Contract { } } - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Move(), copy(beneficiary = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(beneficiary = newOwner)) } // Just for grouping @@ -428,7 +429,7 @@ class Obligation

: Contract { * and same parties involved). */ fun generateCloseOutNetting(tx: TransactionBuilder, - signer: CompositeKey, + signer: PublicKey, vararg states: State

) { val netState = states.firstOrNull()?.bilateralNetState @@ -456,7 +457,7 @@ class Obligation

: Contract { */ @Suppress("unused") fun generateExit(tx: TransactionBuilder, amountIssued: Amount>>, - assetStates: List>>): CompositeKey + assetStates: List>>): PublicKey = Clauses.ConserveAmount

().generateExit(tx, amountIssued, assetStates, deriveState = { state, amount, owner -> state.copy(data = state.data.move(amount, owner)) }, generateMoveCommand = { -> Commands.Move() }, @@ -470,7 +471,7 @@ class Obligation

: Contract { obligor: AbstractParty, issuanceDef: Terms

, pennies: Long, - beneficiary: CompositeKey, + beneficiary: PublicKey, notary: Party) { check(tx.inputStates().isEmpty()) check(tx.outputStates().map { it.data }.sumObligationsOrNull

() == null) @@ -486,7 +487,7 @@ class Obligation

: Contract { "all states are in the normal lifecycle state " by (states.all { it.lifecycle == Lifecycle.NORMAL }) } val groups = states.groupBy { it.multilateralNetState } - val partyLookup = HashMap() + val partyLookup = HashMap() val signers = states.map { it.beneficiary }.union(states.map { it.obligor.owningKey }).toSet() // Create a lookup table of the party that each public key represents. @@ -532,7 +533,7 @@ class Obligation

: Contract { // Produce a new set of states val groups = statesAndRefs.groupBy { it.state.data.amount.token } for ((_, stateAndRefs) in groups) { - val partiesUsed = ArrayList() + val partiesUsed = ArrayList() stateAndRefs.forEach { stateAndRef -> val outState = stateAndRef.state.data.copy(lifecycle = lifecycle) tx.addInputState(stateAndRef) @@ -577,7 +578,7 @@ class Obligation

: Contract { val template: Terms

= issuanceDef.product val obligationTotal: Amount

= Amount(states.map { it.data }.sumObligations

().quantity, template.product) var obligationRemaining: Amount

= obligationTotal - val assetSigners = HashSet() + val assetSigners = HashSet() statesAndRefs.forEach { tx.addInputState(it) } @@ -629,8 +630,8 @@ class Obligation

: Contract { * * @return a map of obligor/beneficiary pairs to the balance due. */ -fun

extractAmountsDue(product: Obligation.Terms

, states: Iterable>): Map, Amount>> { - val balances = HashMap, Amount>>() +fun

extractAmountsDue(product: Obligation.Terms

, states: Iterable>): Map, Amount>> { + val balances = HashMap, Amount>>() states.forEach { state -> val key = Pair(state.obligor.owningKey, state.beneficiary) @@ -644,8 +645,8 @@ fun

extractAmountsDue(product: Obligation.Terms

, states: Iterable netAmountsDue(balances: Map, Amount

>): Map, Amount

> { - val nettedBalances = HashMap, Amount

>() +fun

netAmountsDue(balances: Map, Amount

>): Map, Amount

> { + val nettedBalances = HashMap, Amount

>() balances.forEach { balance -> val (obligor, beneficiary) = balance.key @@ -669,8 +670,8 @@ fun

netAmountsDue(balances: Map, Amou * @param balances payments due, indexed by obligor and beneficiary. Zero balances are stripped from the map before being * returned. */ -fun

sumAmountsDue(balances: Map, Amount

>): Map { - val sum = HashMap() +fun

sumAmountsDue(balances: Map, Amount

>): Map { + val sum = HashMap() // Fill the map with zeroes initially balances.keys.forEach { @@ -711,20 +712,20 @@ fun

Iterable.sumObligationsOrZero(issuanceDef: Issued>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrZero(issuanceDef) infix fun Obligation.State.at(dueBefore: Instant) = copy(template = template.copy(dueBefore = dueBefore)) -infix fun Obligation.State.between(parties: Pair) = copy(obligor = parties.first.toAnonymous(), beneficiary = parties.second) -infix fun Obligation.State.`owned by`(owner: CompositeKey) = copy(beneficiary = owner) +infix fun Obligation.State.between(parties: Pair) = copy(obligor = parties.first.toAnonymous(), beneficiary = parties.second) +infix fun Obligation.State.`owned by`(owner: PublicKey) = copy(beneficiary = owner) infix fun Obligation.State.`issued by`(party: AbstractParty) = copy(obligor = party.toAnonymous()) // For Java users: -@Suppress("unused") fun Obligation.State.ownedBy(owner: CompositeKey) = copy(beneficiary = owner) +@Suppress("unused") fun Obligation.State.ownedBy(owner: PublicKey) = copy(beneficiary = owner) @Suppress("unused") fun Obligation.State.issuedBy(party: AnonymousParty) = copy(obligor = party) /** A randomly generated key. */ val DUMMY_OBLIGATION_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) } /** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */ -val DUMMY_OBLIGATION_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_OBLIGATION_ISSUER_KEY.public.composite) } +val DUMMY_OBLIGATION_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_OBLIGATION_ISSUER_KEY.public) } val Issued.OBLIGATION_DEF: Obligation.Terms get() = Obligation.Terms(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(this), TEST_TX_TIME) val Amount>.OBLIGATION: Obligation.State - get() = Obligation.State(Obligation.Lifecycle.NORMAL, DUMMY_OBLIGATION_ISSUER.toAnonymous(), token.OBLIGATION_DEF, quantity, NullCompositeKey) + get() = Obligation.State(Obligation.Lifecycle.NORMAL, DUMMY_OBLIGATION_ISSUER.toAnonymous(), token.OBLIGATION_DEF, quantity, NullPublicKey) diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt b/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt index 1aa5c96ffb..8550ad17bd 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt @@ -2,8 +2,8 @@ package net.corda.contracts.asset import net.corda.contracts.clause.AbstractConserveAmount import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -40,7 +40,7 @@ abstract class OnLedgerAsset> : C */ @Throws(InsufficientBalanceException::class) fun generateExit(tx: TransactionBuilder, amountIssued: Amount>, - assetStates: List>): CompositeKey { + assetStates: List>): PublicKey { return conserveClause.generateExit( tx, amountIssued, @@ -60,5 +60,5 @@ abstract class OnLedgerAsset> : C * implementations to have fields in their state which we don't know about here, and we simply leave them untouched * when sending out "change" from spending/exiting. */ - abstract fun deriveState(txState: TransactionState, amount: Amount>, owner: CompositeKey): TransactionState + abstract fun deriveState(txState: TransactionState, amount: Amount>, owner: PublicKey): TransactionState } diff --git a/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt b/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt index 55818d9521..459eacc92e 100644 --- a/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt +++ b/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt @@ -2,8 +2,8 @@ package net.corda.contracts.clause import net.corda.core.contracts.* import net.corda.core.contracts.clauses.Clause -import net.corda.core.crypto.CompositeKey import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace import java.util.* @@ -59,9 +59,9 @@ abstract class AbstractConserveAmount, C : CommandData, T : @Throws(InsufficientBalanceException::class) fun generateExit(tx: TransactionBuilder, amountIssued: Amount>, assetStates: List>, - deriveState: (TransactionState, Amount>, CompositeKey) -> TransactionState, + deriveState: (TransactionState, Amount>, PublicKey) -> TransactionState, generateMoveCommand: () -> CommandData, - generateExitCommand: (Amount>) -> CommandData): CompositeKey { + generateExitCommand: (Amount>) -> CommandData): PublicKey { val owner = assetStates.map { it.state.data.owner }.toSet().singleOrNull() ?: throw InsufficientBalanceException(amountIssued) val currency = amountIssued.token.product val amount = Amount(amountIssued.quantity, currency) @@ -104,7 +104,7 @@ abstract class AbstractConserveAmount, C : CommandData, T : val outputAmount: Amount> = outputs.sumFungibleOrZero(groupingKey) // If we want to remove assets from the ledger, that must be signed for by the issuer and owner. - val exitKeys: Set = inputs.flatMap { it.exitKeys }.toSet() + val exitKeys: Set = inputs.flatMap { it.exitKeys }.toSet() val exitCommand = matchedCommands.select>(parties = null, signers = exitKeys).filter { it.value.amount.token == groupingKey }.singleOrNull() val amountExitingLedger: Amount> = exitCommand?.value?.amount ?: Amount(0, groupingKey) diff --git a/finance/src/main/kotlin/net/corda/contracts/clause/Net.kt b/finance/src/main/kotlin/net/corda/contracts/clause/Net.kt index 3d5ebdc689..befd05f9e6 100644 --- a/finance/src/main/kotlin/net/corda/contracts/clause/Net.kt +++ b/finance/src/main/kotlin/net/corda/contracts/clause/Net.kt @@ -6,7 +6,7 @@ import net.corda.contracts.asset.extractAmountsDue import net.corda.contracts.asset.sumAmountsDue import net.corda.core.contracts.* import net.corda.core.contracts.clauses.Clause -import net.corda.core.crypto.CompositeKey +import java.security.PublicKey /** * Common interface for the state subsets used when determining nettability of two or more states. Exposes the @@ -22,7 +22,7 @@ interface NetState

{ * Bilateral states are used in close-out netting. */ data class BilateralNetState

( - val partyKeys: Set, + val partyKeys: Set, override val template: Obligation.Terms

) : NetState

diff --git a/finance/src/main/kotlin/net/corda/contracts/testing/DummyDealContract.kt b/finance/src/main/kotlin/net/corda/contracts/testing/DummyDealContract.kt index 01aab6b086..86e887b3ec 100644 --- a/finance/src/main/kotlin/net/corda/contracts/testing/DummyDealContract.kt +++ b/finance/src/main/kotlin/net/corda/contracts/testing/DummyDealContract.kt @@ -4,10 +4,7 @@ import net.corda.core.contracts.Contract import net.corda.core.contracts.DealState import net.corda.core.contracts.TransactionForContract import net.corda.core.contracts.UniqueIdentifier -import net.corda.core.crypto.AnonymousParty -import net.corda.core.crypto.CompositeKey -import net.corda.core.crypto.Party -import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.* import net.corda.core.transactions.TransactionBuilder import java.security.PublicKey @@ -18,7 +15,7 @@ class DummyDealContract : Contract { data class State( override val contract: Contract = DummyDealContract(), - override val participants: List = listOf(), + override val participants: List = listOf(), override val linearId: UniqueIdentifier = UniqueIdentifier(), override val ref: String, override val parties: List = listOf()) : DealState { diff --git a/finance/src/main/kotlin/net/corda/contracts/testing/DummyLinearContract.kt b/finance/src/main/kotlin/net/corda/contracts/testing/DummyLinearContract.kt index 4c56463ecc..3671bf637d 100644 --- a/finance/src/main/kotlin/net/corda/contracts/testing/DummyLinearContract.kt +++ b/finance/src/main/kotlin/net/corda/contracts/testing/DummyLinearContract.kt @@ -6,6 +6,7 @@ import net.corda.core.contracts.clauses.FilterOn import net.corda.core.contracts.clauses.verifyClause import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.containsAny import java.security.PublicKey class DummyLinearContract : Contract { @@ -19,7 +20,7 @@ class DummyLinearContract : Contract { data class State( override val linearId: UniqueIdentifier = UniqueIdentifier(), override val contract: Contract = DummyLinearContract(), - override val participants: List = listOf(), + override val participants: List = listOf(), val nonce: SecureHash = SecureHash.randomSHA256()) : LinearState { override fun isRelevant(ourKeys: Set): Boolean { diff --git a/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt b/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt index 978e0e1f87..9a9e1a326c 100644 --- a/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt +++ b/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt @@ -9,9 +9,7 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.Issued import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.TransactionType -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party -import net.corda.core.crypto.composite import net.corda.core.node.ServiceHub import net.corda.core.node.services.Vault import net.corda.core.serialization.OpaqueBytes @@ -19,6 +17,7 @@ import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY_KEY import java.security.KeyPair +import java.security.PublicKey import java.util.* fun ServiceHub.fillWithSomeTestDeals(dealIds: List) { @@ -26,7 +25,7 @@ fun ServiceHub.fillWithSomeTestDeals(dealIds: List) { val transactions: List = dealIds.map { // Issue a deal state val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply { - addOutputState(DummyDealContract.State(ref = it, participants = listOf(freshKey.public.composite))) + addOutputState(DummyDealContract.State(ref = it, participants = listOf(freshKey.public))) signWith(freshKey) signWith(DUMMY_NOTARY_KEY) } @@ -41,7 +40,7 @@ fun ServiceHub.fillWithSomeTestLinearStates(numberToCreate: Int) { for (i in 1..numberToCreate) { // Issue a deal state val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply { - addOutputState(DummyLinearContract.State(participants = listOf(freshKey.public.composite))) + addOutputState(DummyLinearContract.State(participants = listOf(freshKey.public))) signWith(freshKey) signWith(DUMMY_NOTARY_KEY) } @@ -65,12 +64,12 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount, atMostThisManyStates: Int = 10, rng: Random = Random(), ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 1 })), - ownedBy: CompositeKey? = null, + ownedBy: PublicKey? = null, issuedBy: PartyAndReference = DUMMY_CASH_ISSUER, issuerKey: KeyPair = DUMMY_CASH_ISSUER_KEY): Vault { val amounts = calculateRandomlySizedAmounts(howMuch, atLeastThisManyStates, atMostThisManyStates, rng) - val myKey: CompositeKey = ownedBy ?: myInfo.legalIdentity.owningKey + val myKey: PublicKey = ownedBy ?: myInfo.legalIdentity.owningKey // We will allocate one state to one transaction, for simplicities sake. val cash = Cash() diff --git a/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt b/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt index 5ec7052c07..ca154d2fa7 100644 --- a/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt @@ -5,7 +5,7 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.InsufficientBalanceException import net.corda.core.contracts.TransactionType import net.corda.core.crypto.Party -import net.corda.core.crypto.keys +import net.corda.core.crypto.expandedCompositeKeys import net.corda.core.crypto.toStringShort import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder @@ -44,7 +44,7 @@ open class CashPaymentFlow( } progressTracker.currentStep = SIGNING_TX - keysForSigning.keys.forEach { + keysForSigning.expandedCompositeKeys.forEach { val key = serviceHub.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}") builder.signWith(KeyPair(it, key)) } diff --git a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt index 5b44a10c76..08e8830177 100644 --- a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt @@ -16,6 +16,7 @@ import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.trace import net.corda.core.utilities.unwrap import java.security.KeyPair +import java.security.PublicKey import java.util.* /** @@ -50,7 +51,7 @@ object TwoPartyTradeFlow { data class SellerTradeInfo( val assetForSale: StateAndRef, val price: Amount, - val sellerOwnerKey: CompositeKey + val sellerOwnerKey: PublicKey ) @CordaSerializable @@ -95,7 +96,7 @@ object TwoPartyTradeFlow { private fun receiveAndCheckProposedTransaction(): SignedTransaction { progressTracker.currentStep = AWAITING_PROPOSAL - val myPublicKey = myKeyPair.public.composite + val myPublicKey = myKeyPair.public // Make the first message we'll send to kick off the flow. val hello = SellerTradeInfo(assetToSell, price, myPublicKey) // What we get back from the other side is a transaction that *might* be valid and acceptable to us, @@ -198,9 +199,9 @@ object TwoPartyTradeFlow { } } - private fun signWithOurKeys(cashSigningPubKeys: List, ptx: TransactionBuilder): SignedTransaction { + private fun signWithOurKeys(cashSigningPubKeys: List, ptx: TransactionBuilder): SignedTransaction { // Now sign the transaction with whatever keys we need to move the cash. - for (publicKey in cashSigningPubKeys.keys) { + for (publicKey in cashSigningPubKeys.expandedCompositeKeys) { val privateKey = serviceHub.keyManagementService.toPrivate(publicKey) ptx.signWith(KeyPair(publicKey, privateKey)) } @@ -208,7 +209,7 @@ object TwoPartyTradeFlow { return ptx.toSignedTransaction(checkSufficientSignatures = false) } - private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair> { + private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair> { val ptx = TransactionType.General.Builder(notary) // Add input and output states for the movement of cash, by using the Cash contract to generate the states @@ -222,7 +223,7 @@ object TwoPartyTradeFlow { // reveal who the owner actually is. The key management service is expected to derive a unique key from some // initial seed in order to provide privacy protection. val freshKey = serviceHub.keyManagementService.freshKey() - val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public.composite) + val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public) tx.addOutputState(state, tradeRequest.assetForSale.state.notary) tx.addCommand(command, tradeRequest.assetForSale.state.data.owner) diff --git a/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt b/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt index 5c283cb715..09bf473d81 100644 --- a/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt @@ -4,7 +4,7 @@ import net.corda.contracts.asset.* import net.corda.contracts.testing.fillWithSomeTestCash import net.corda.core.contracts.* import net.corda.core.crypto.Party -import net.corda.core.crypto.composite +import net.corda.core.crypto.SecureHash import net.corda.core.days import net.corda.core.node.services.Vault import net.corda.core.node.services.VaultService @@ -271,8 +271,8 @@ class CommercialPaperTestsGeneric { // Alice pays $9000 to BigCorp to own some of their debt. moveTX = run { val ptx = TransactionType.General.Builder(DUMMY_NOTARY) - aliceVaultService.generateSpend(ptx, 9000.DOLLARS, bigCorpServices.key.public.composite) - CommercialPaper().generateMove(ptx, issueTX.tx.outRef(0), aliceServices.key.public.composite) + aliceVaultService.generateSpend(ptx, 9000.DOLLARS, bigCorpServices.key.public) + CommercialPaper().generateMove(ptx, issueTX.tx.outRef(0), aliceServices.key.public) ptx.signWith(bigCorpServices.key) ptx.signWith(aliceServices.key) ptx.signWith(DUMMY_NOTARY_KEY) diff --git a/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt b/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt index 9ecdfe7e2d..e468e5993e 100644 --- a/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt @@ -24,6 +24,7 @@ import org.junit.Before import org.junit.Test import java.io.Closeable import java.security.KeyPair +import java.security.PublicKey import java.util.* import kotlin.test.* @@ -458,7 +459,7 @@ class CashTests { // Spend tx generation val OUR_KEY: KeyPair by lazy { generateKeyPair() } - val OUR_PUBKEY_1: CompositeKey get() = OUR_KEY.public.composite + val OUR_PUBKEY_1: PublicKey get() = OUR_KEY.public val THEIR_PUBKEY_1 = DUMMY_PUBKEY_2 @@ -484,7 +485,7 @@ class CashTests { return tx.toWireTransaction() } - fun makeSpend(amount: Amount, dest: CompositeKey): WireTransaction { + fun makeSpend(amount: Amount, dest: PublicKey): WireTransaction { val tx = TransactionType.General.Builder(DUMMY_NOTARY) databaseTransaction(database) { vault.generateSpend(tx, amount, dest) diff --git a/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt b/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt index 299373871a..6e1f6514f1 100644 --- a/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt @@ -2,13 +2,13 @@ package net.corda.contracts.asset import net.corda.contracts.asset.Obligation.Lifecycle import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey -import net.corda.core.crypto.NullCompositeKey +import net.corda.core.crypto.NullPublicKey import net.corda.core.crypto.SecureHash import net.corda.core.serialization.OpaqueBytes import net.corda.core.utilities.* import net.corda.testing.* import org.junit.Test +import java.security.PublicKey import java.time.Duration import java.time.temporal.ChronoUnit import java.util.* @@ -506,7 +506,7 @@ class ObligationTests { val oneUnitFcoj = Amount(1, defaultFcoj) val obligationDef = Obligation.Terms(nonEmptySetOf(CommodityContract().legalContractReference), nonEmptySetOf(defaultFcoj), TEST_TX_TIME) val oneUnitFcojObligation = Obligation.State(Obligation.Lifecycle.NORMAL, ALICE, - obligationDef, oneUnitFcoj.quantity, NullCompositeKey) + obligationDef, oneUnitFcoj.quantity, NullPublicKey) // Try settling a simple commodity obligation ledger { unverifiedTransaction { @@ -819,7 +819,7 @@ class ObligationTests { val fiveKDollarsFromMegaToMini = Obligation.State(Lifecycle.NORMAL, MEGA_CORP, megaCorpDollarSettlement, 5000.DOLLARS.quantity, MINI_CORP_PUBKEY) val amount = fiveKDollarsFromMegaToMini.amount - val expected = mapOf(Pair(Pair(MEGA_CORP_PUBKEY, MINI_CORP_PUBKEY), Amount(amount.quantity, amount.token.product))) + val expected: Map, Amount>> = mapOf(Pair(Pair(MEGA_CORP_PUBKEY, MINI_CORP_PUBKEY), Amount(amount.quantity, amount.token.product))) val actual = extractAmountsDue(megaCorpDollarSettlement, listOf(fiveKDollarsFromMegaToMini)) assertEquals(expected, actual) } @@ -827,23 +827,23 @@ class ObligationTests { @Test fun `netting equal balances due between parties`() { // Now try it with two balances, which cancel each other out - val balanced = mapOf( + val balanced: Map, Amount> = mapOf( Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP)), Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) - val expected: Map, Amount> = emptyMap() // Zero balances are stripped before returning - val actual = netAmountsDue(balanced) + val expected: Map, Amount> = emptyMap() // Zero balances are stripped before returning + val actual: Map, Amount> = netAmountsDue(balanced) assertEquals(expected, actual) } @Test fun `netting difference balances due between parties`() { // Now try it with two balances, which cancel each other out - val balanced = mapOf( + val balanced: Map, Amount> = mapOf( Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP)), Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(200000000, GBP)) ) - val expected = mapOf( + val expected: Map, Amount> = mapOf( Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) val actual = netAmountsDue(balanced) @@ -852,16 +852,16 @@ class ObligationTests { @Test fun `summing empty balances due between parties`() { - val empty = emptyMap, Amount>() - val expected = emptyMap() + val empty = emptyMap, Amount>() + val expected = emptyMap() val actual = sumAmountsDue(empty) assertEquals(expected, actual) } @Test fun `summing balances due between parties`() { - val simple = mapOf(Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP))) - val expected = mapOf(Pair(ALICE_PUBKEY, -100000000L), Pair(BOB_PUBKEY, 100000000L)) + val simple: Map, Amount> = mapOf(Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP))) + val expected: Map = mapOf(Pair(ALICE_PUBKEY, -100000000L), Pair(BOB_PUBKEY, 100000000L)) val actual = sumAmountsDue(simple) assertEquals(expected, actual) } @@ -869,11 +869,11 @@ class ObligationTests { @Test fun `summing balances due between parties which net to zero`() { // Now try it with two balances, which cancel each other out - val balanced = mapOf( + val balanced: Map, Amount> = mapOf( Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP)), Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) - val expected: Map = emptyMap() // Zero balances are stripped before returning + val expected: Map = emptyMap() // Zero balances are stripped before returning val actual = sumAmountsDue(balanced) assertEquals(expected, actual) } diff --git a/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt b/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt index ceff5ec698..1deab780cd 100644 --- a/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt +++ b/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt @@ -25,7 +25,7 @@ class ContractStateGenerator : Generator(ContractState::class.jav override fun generate(random: SourceOfRandomness, status: GenerationStatus): ContractState { return Cash.State( amount = AmountGenerator(IssuedGenerator(CurrencyGenerator())).generate(random, status), - owner = CompositeKeyGenerator().generate(random, status) + owner = PublicKeyGenerator().generate(random, status) ) } } @@ -58,8 +58,8 @@ class CommandDataGenerator : Generator(CommandData::class.java) { class CommandGenerator : Generator(Command::class.java) { override fun generate(random: SourceOfRandomness, status: GenerationStatus): Command { val signersGenerator = ArrayListGenerator() - signersGenerator.addComponentGenerators(listOf(CompositeKeyGenerator())) - return Command(CommandDataGenerator().generate(random, status), CompositeKeyGenerator().generate(random, status)) + signersGenerator.addComponentGenerators(listOf(PublicKeyGenerator())) + return Command(CommandDataGenerator().generate(random, status), PublicKeyGenerator().generate(random, status)) } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisMessagingComponent.kt b/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisMessagingComponent.kt index 900f8b0ac2..af48164958 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisMessagingComponent.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisMessagingComponent.kt @@ -2,7 +2,7 @@ package net.corda.nodeapi import com.google.common.annotations.VisibleForTesting import com.google.common.net.HostAndPort -import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.toBase58String import net.corda.core.messaging.MessageRecipientGroup import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.SingleMessageRecipient @@ -11,6 +11,7 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.nodeapi.config.SSLConfiguration import java.security.KeyStore +import java.security.PublicKey /** * The base class for Artemis services that defines shared data structures and SSL transport configuration. @@ -76,11 +77,11 @@ abstract class ArtemisMessagingComponent : SingletonSerializeAsToken() { @CordaSerializable data class NodeAddress(override val queueName: String, override val hostAndPort: HostAndPort) : ArtemisPeerAddress { companion object { - fun asPeer(peerIdentity: CompositeKey, hostAndPort: HostAndPort): NodeAddress { + fun asPeer(peerIdentity: PublicKey, hostAndPort: HostAndPort): NodeAddress { return NodeAddress("$PEERS_PREFIX${peerIdentity.toBase58String()}", hostAndPort) } - fun asService(serviceIdentity: CompositeKey, hostAndPort: HostAndPort): NodeAddress { + fun asService(serviceIdentity: PublicKey, hostAndPort: HostAndPort): NodeAddress { return NodeAddress("$SERVICES_PREFIX${serviceIdentity.toBase58String()}", hostAndPort) } } @@ -95,7 +96,7 @@ abstract class ArtemisMessagingComponent : SingletonSerializeAsToken() { * * @param identity The service identity's owning key. */ - data class ServiceAddress(val identity: CompositeKey) : ArtemisAddress, MessageRecipientGroup { + data class ServiceAddress(val identity: PublicKey) : ArtemisAddress, MessageRecipientGroup { override val queueName: String = "$SERVICES_PREFIX${identity.toBase58String()}" } diff --git a/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt b/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt index e977e0e4ba..7a40588f09 100644 --- a/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt +++ b/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt @@ -28,6 +28,7 @@ import org.junit.Assert import org.junit.Before import org.junit.Test import rx.Observable +import java.security.PublicKey import sun.misc.MessageUtils.where import java.time.Instant import java.util.* @@ -80,12 +81,12 @@ class VaultSchemaTest { private class VaultNoopContract : Contract { override val legalContractReference = SecureHash.sha256("") - data class VaultNoopState(override val owner: CompositeKey) : OwnableState { + data class VaultNoopState(override val owner: PublicKey) : OwnableState { override val contract = VaultNoopContract() - override val participants: List + override val participants: List get() = listOf(owner) - override fun withNewOwner(newOwner: CompositeKey) = Pair(Commands.Create(), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Create(), copy(owner = newOwner)) } interface Commands : CommandData { @@ -114,7 +115,7 @@ class VaultSchemaTest { val commands = emptyList>() val attachments = emptyList() val id = SecureHash.randomSHA256() - val signers = listOf(DUMMY_NOTARY_KEY.public.composite) + val signers = listOf(DUMMY_NOTARY_KEY.public) val timestamp: Timestamp? = null transaction = LedgerTransaction( inputs, @@ -146,7 +147,7 @@ class VaultSchemaTest { val commands = emptyList>() val attachments = emptyList() val id = SecureHash.randomSHA256() - val signers = listOf(DUMMY_NOTARY_KEY.public.composite) + val signers = listOf(DUMMY_NOTARY_KEY.public) val timestamp: Timestamp? = null return LedgerTransaction( inputs, @@ -634,7 +635,7 @@ class VaultSchemaTest { @Test fun insertWithBigCompositeKey() { - val keys = (1..314).map { generateKeyPair().public.composite } + val keys = (1..314).map { generateKeyPair().public } val bigNotaryKey = CompositeKey.Builder().addKeys(keys).build() val vaultStEntity = VaultStatesEntity().apply { txId = SecureHash.randomSHA256().toString() diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt index a150acd75b..496f98f7e3 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt @@ -4,8 +4,8 @@ import co.paralleluniverse.fibers.Suspendable import com.google.common.net.HostAndPort import net.corda.client.rpc.CordaRPCClientImpl import net.corda.core.crypto.Party -import net.corda.core.crypto.composite import net.corda.core.crypto.generateKeyPair +import net.corda.core.crypto.toBase58String import net.corda.core.flows.FlowLogic import net.corda.core.getOrThrow import net.corda.core.messaging.CordaRPCOps @@ -90,7 +90,7 @@ abstract class MQSecurityTest : NodeBasedTest() { @Test fun `create queue for unknown peer`() { - val invalidPeerQueue = "$PEERS_PREFIX${generateKeyPair().public.composite.toBase58String()}" + val invalidPeerQueue = "$PEERS_PREFIX${generateKeyPair().public.toBase58String()}" assertAllQueueCreationAttacksFail(invalidPeerQueue) } diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index 5b13c0723e..b60ef5c511 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -4,7 +4,6 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.UpgradedContract -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.flows.StateMachineRunId @@ -27,6 +26,7 @@ import net.corda.node.utilities.databaseTransaction import org.jetbrains.exposed.sql.Database import rx.Observable import java.io.InputStream +import java.security.PublicKey import java.time.Instant import java.util.* @@ -142,7 +142,7 @@ class CordaRPCOpsImpl( } override fun waitUntilRegisteredWithNetworkMap() = services.networkMapCache.mapServiceRegistered - override fun partyFromKey(key: CompositeKey) = services.identityService.partyFromKey(key) + override fun partyFromKey(key: PublicKey) = services.identityService.partyFromKey(key) override fun partyFromName(name: String) = services.identityService.partyFromName(name) override fun registeredFlows(): List = services.flowLogicRefFactory.flowWhitelist.keys.sorted() diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index 9ade992c8f..badfc37de5 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -2,12 +2,12 @@ package net.corda.node.services.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.AnonymousParty -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.node.services.IdentityService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace +import java.security.PublicKey import java.util.* import java.util.concurrent.ConcurrentHashMap import javax.annotation.concurrent.ThreadSafe @@ -21,7 +21,7 @@ class InMemoryIdentityService : SingletonSerializeAsToken(), IdentityService { private val log = loggerFor() } - private val keyToParties = ConcurrentHashMap() + private val keyToParties = ConcurrentHashMap() private val nameToParties = ConcurrentHashMap() override fun registerIdentity(party: Party) { @@ -33,7 +33,7 @@ class InMemoryIdentityService : SingletonSerializeAsToken(), IdentityService { // We give the caller a copy of the data set to avoid any locking problems override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) - override fun partyFromKey(key: CompositeKey): Party? = keyToParties[key] + override fun partyFromKey(key: PublicKey): Party? = keyToParties[key] override fun partyFromName(name: String): Party? = nameToParties[name] override fun partyFromAnonymous(party: AnonymousParty): Party? = partyFromKey(party.owningKey) override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party) diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 029f9a7bfd..cb74e856f1 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -279,7 +279,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, when { queueName.startsWith(PEERS_PREFIX) -> try { - val identity = CompositeKey.parseFromBase58(queueName.substring(PEERS_PREFIX.length)) + val identity = parsePublicKeyBase58(queueName.substring(PEERS_PREFIX.length)) val nodeInfo = networkMapCache.getNodeByLegalIdentityKey(identity) if (nodeInfo != null) { deployBridgeToPeer(nodeInfo) @@ -291,7 +291,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, } queueName.startsWith(SERVICES_PREFIX) -> try { - val identity = CompositeKey.parseFromBase58(queueName.substring(SERVICES_PREFIX.length)) + val identity = parsePublicKeyBase58(queueName.substring(SERVICES_PREFIX.length)) val nodeInfos = networkMapCache.getNodesByAdvertisedServiceIdentityKey(identity) // Create a bridge for each node advertising the service. for (nodeInfo in nodeInfos) { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt index 998c2074af..e0c5d463dd 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt @@ -3,7 +3,6 @@ package net.corda.node.services.messaging import com.google.common.net.HostAndPort import com.google.common.util.concurrent.ListenableFuture import net.corda.core.ThreadBox -import net.corda.core.crypto.CompositeKey import net.corda.core.messaging.* import net.corda.core.node.NodeVersionInfo import net.corda.core.node.services.PartyInfo @@ -45,6 +44,7 @@ import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import javax.annotation.concurrent.ThreadSafe +import java.security.PublicKey // TODO: Stop the wallet explorer and other clients from using this class and get rid of persistentInbox @@ -70,7 +70,7 @@ import javax.annotation.concurrent.ThreadSafe class NodeMessagingClient(override val config: NodeConfiguration, nodeVersionInfo: NodeVersionInfo, val serverHostPort: HostAndPort, - val myIdentity: CompositeKey?, + val myIdentity: PublicKey?, val nodeExecutor: AffinityExecutor, val database: Database, val networkMapRegistrationFuture: ListenableFuture, diff --git a/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt index 995dbff480..3b6e50afb5 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt @@ -4,7 +4,6 @@ import com.google.common.annotations.VisibleForTesting import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture import net.corda.core.bufferUntilSubscribed -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.map import net.corda.core.messaging.MessagingService @@ -28,6 +27,7 @@ import net.corda.node.utilities.bufferUntilDatabaseCommit import net.corda.node.utilities.wrapWithDatabaseTransaction import rx.Observable import rx.subjects.PublishSubject +import java.security.PublicKey import java.security.SignatureException import java.util.* import javax.annotation.concurrent.ThreadSafe @@ -52,7 +52,7 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach override val mapServiceRegistered: ListenableFuture get() = _registrationFuture private var registeredForPush = false - protected var registeredNodes: MutableMap = Collections.synchronizedMap(HashMap()) + protected var registeredNodes: MutableMap = Collections.synchronizedMap(HashMap()) override fun getPartyInfo(party: Party): PartyInfo? { val node = registeredNodes[party.owningKey] @@ -69,7 +69,7 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach return null } - override fun getNodeByLegalIdentityKey(compositeKey: CompositeKey): NodeInfo? = registeredNodes[compositeKey] + override fun getNodeByLegalIdentityKey(identityKey: PublicKey): NodeInfo? = registeredNodes[identityKey] override fun track(): Pair, Observable> { synchronized(_changed) { diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt index 8b9027fa4f..041fd4a8b1 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt @@ -2,10 +2,7 @@ package net.corda.node.services.network import com.google.common.annotations.VisibleForTesting import net.corda.core.ThreadBox -import net.corda.core.crypto.DigitalSignature -import net.corda.core.crypto.Party -import net.corda.core.crypto.SignedData -import net.corda.core.crypto.signWithECDSA +import net.corda.core.crypto.* import net.corda.core.messaging.MessageHandlerRegistration import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.SingleMessageRecipient @@ -311,7 +308,7 @@ data class NodeRegistration(val node: NodeInfo, val serial: Long, val type: AddO */ fun toWire(privateKey: PrivateKey): WireNodeRegistration { val regSerialized = this.serialize() - val regSig = privateKey.signWithECDSA(regSerialized.bytes, node.legalIdentity.owningKey.singleKey) + val regSig = privateKey.signWithECDSA(regSerialized.bytes, node.legalIdentity.owningKey) return WireNodeRegistration(regSerialized, regSig) } diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt index e598519696..e59582d553 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt @@ -17,6 +17,8 @@ import net.corda.core.crypto.AbstractParty import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.containsAny +import net.corda.core.crypto.toBase58String import net.corda.core.node.ServiceHub import net.corda.core.node.services.StatesNotAvailableException import net.corda.core.node.services.Vault @@ -177,7 +179,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P override fun states(clazzes: Set>, statuses: EnumSet, includeSoftLockedStates: Boolean): Iterable> { val stateAndRefs = session.withTransaction(TransactionIsolation.REPEATABLE_READ) { - var query = select(VaultSchema.VaultStates::class) + val query = select(VaultSchema.VaultStates::class) .where(VaultSchema.VaultStates::stateStatus `in` statuses) // TODO: temporary fix to continue supporting track() function (until becomes Typed) if (!clazzes.map { it.name }.contains(ContractState::class.java.name)) @@ -442,8 +444,8 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P @Suspendable override fun generateSpend(tx: TransactionBuilder, amount: Amount, - to: CompositeKey, - onlyFromParties: Set?): Pair> { + to: PublicKey, + onlyFromParties: Set?): Pair> { // Discussion // // This code is analogous to the Wallet.send() set of methods in bitcoinj, and has the same general outline. @@ -520,7 +522,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P return Pair(tx, keysUsed) } - private fun deriveState(txState: TransactionState, amount: Amount>, owner: CompositeKey) + private fun deriveState(txState: TransactionState, amount: Amount>, owner: PublicKey) = txState.copy(data = txState.data.copy(amount = amount, owner = owner)) /** diff --git a/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt b/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt index 5873b52fe6..783dd398f8 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt @@ -3,7 +3,6 @@ package net.corda.node.utilities import co.paralleluniverse.strands.Strand import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.crypto.parsePublicKeyBase58 import net.corda.core.crypto.toBase58String @@ -260,8 +259,7 @@ fun rx.Observable.wrapWithDatabaseTransaction(db: Database? = null) } // Composite columns for use with below Exposed helpers. -data class PartyColumns(val name: Column, val owningKey: Column) - +data class PartyColumns(val name: Column, val owningKey: Column) data class StateRefColumns(val txId: Column, val index: Column) data class TxnNoteColumns(val txId: Column, val note: Column) @@ -269,10 +267,8 @@ data class TxnNoteColumns(val txId: Column, val note: Column * [Table] column helpers for use with Exposed, as per [varchar] etc. */ fun Table.publicKey(name: String) = this.registerColumn(name, PublicKeyColumnType) - -fun Table.compositeKey(name: String) = this.registerColumn(name, CompositeKeyColumnType) fun Table.secureHash(name: String) = this.registerColumn(name, SecureHashColumnType) -fun Table.party(nameColumnName: String, keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.compositeKey(keyColumnName)) +fun Table.party(nameColumnName: String, keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName)) fun Table.uuidString(name: String) = this.registerColumn(name, UUIDStringColumnType) fun Table.localDate(name: String) = this.registerColumn(name, LocalDateColumnType) fun Table.localDateTime(name: String) = this.registerColumn(name, LocalDateTimeColumnType) @@ -283,23 +279,17 @@ fun Table.txnNote(txIdColumnName: String, txnNoteColumnName: String) = TxnNoteCo /** * [ColumnType] for marshalling to/from database on behalf of [PublicKey]. */ +// TODO Rethink how we store CompositeKeys in db. Currently they are stored as Base58 strings and as we don't know the size +// of a CompositeKey they could be CLOB fields. Given the time to fetch these types and that they are unsuitable as table keys, +// having a shorter primary key (such as SHA256 hash or a UUID generated on demand) that references a common composite key table may make more sense. object PublicKeyColumnType : ColumnType() { - override fun sqlType(): String = "VARCHAR(255)" + override fun sqlType(): String = "VARCHAR" override fun valueFromDB(value: Any): Any = parsePublicKeyBase58(value.toString()) override fun notNullValueToDB(value: Any): Any = if (value is PublicKey) value.toBase58String() else value } -/** - * [ColumnType] for marshalling to/from database on behalf of [CompositeKey]. - */ -object CompositeKeyColumnType : ColumnType() { - override fun sqlType(): String = "VARCHAR" - override fun valueFromDB(value: Any): Any = CompositeKey.parseFromBase58(value.toString()) - override fun notNullValueToDB(value: Any): Any = if (value is CompositeKey) value.toBase58String() else value -} - /** * [ColumnType] for marshalling to/from database on behalf of [SecureHash]. */ diff --git a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt index 9b6b311425..927fd2669b 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt @@ -2,7 +2,6 @@ package net.corda.node.utilities import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party -import net.corda.core.crypto.composite import net.corda.core.crypto.generateKeyPair import net.corda.core.serialization.serialize import net.corda.core.utilities.loggerFor @@ -22,13 +21,13 @@ object ServiceIdentityGenerator { * @param dirs List of node directories to place the generated identity and key pairs in. * @param serviceId The service id of the distributed service. * @param serviceName The legal name of the distributed service. - * @param threshold The threshold for the generated group [CompositeKey.Node]. + * @param threshold The threshold for the generated group [CompositeKey]. */ fun generateToDisk(dirs: List, serviceId: String, serviceName: String, threshold: Int = 1) { log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" } val keyPairs = (1..dirs.size).map { generateKeyPair() } - val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public.composite }).build(threshold) + val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold) val notaryParty = Party(serviceName, notaryKey).serialize() keyPairs.zip(dirs) { keyPair, dir -> diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index eafcca17dd..102515fd3a 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -2,6 +2,8 @@ package net.corda.node import net.corda.contracts.asset.Cash import net.corda.core.contracts.* +import net.corda.core.crypto.isFulfilledBy +import net.corda.core.crypto.keys import net.corda.core.flows.StateMachineRunId import net.corda.core.messaging.StateMachineUpdate import net.corda.core.messaging.startFlow diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 59f7d61414..771f94d991 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -40,6 +40,7 @@ import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.math.BigInteger import java.security.KeyPair +import java.security.PublicKey import java.util.* import java.util.concurrent.Future import java.util.jar.JarOutputStream @@ -257,7 +258,7 @@ class TwoPartyTradeFlowTests { } val extraKey = bobNode.keyManagement.freshKey() - val bobsFakeCash = fillUpForBuyer(false, extraKey.public.composite, + val bobsFakeCash = fillUpForBuyer(false, extraKey.public, DUMMY_CASH_ISSUER.party, notaryNode.info.notaryIdentity).second val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, bobNode.services.legalIdentityKey, extraKey) @@ -357,7 +358,7 @@ class TwoPartyTradeFlowTests { attachment(ByteArrayInputStream(stream.toByteArray())) } - val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite, + val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public, DUMMY_CASH_ISSUER.party, notaryNode.info.notaryIdentity).second insertFakeTransactions(bobsFakeCash, bobNode, notaryNode) @@ -458,7 +459,7 @@ class TwoPartyTradeFlowTests { val bobKey = bobNode.services.legalIdentityKey val issuer = MEGA_CORP.ref(1, 2, 3) - val bobsBadCash = fillUpForBuyer(bobError, bobKey.public.composite, DUMMY_CASH_ISSUER.party, + val bobsBadCash = fillUpForBuyer(bobError, bobKey.public, DUMMY_CASH_ISSUER.party, notaryNode.info.notaryIdentity).second val alicesFakePaper = databaseTransaction(aliceNode.database) { fillUpForSeller(aliceError, aliceNode.info.legalIdentity.owningKey, @@ -505,7 +506,7 @@ class TwoPartyTradeFlowTests { private fun LedgerDSL.fillUpForBuyer( withError: Boolean, - owner: CompositeKey, + owner: PublicKey, issuer: AnonymousParty, notary: Party): Pair, List> { val interimOwnerKey = MEGA_CORP_PUBKEY @@ -551,7 +552,7 @@ class TwoPartyTradeFlowTests { private fun LedgerDSL.fillUpForSeller( withError: Boolean, - owner: CompositeKey, + owner: PublicKey, amount: Amount>, attachmentID: SecureHash?, notary: Party): Pair, List> { diff --git a/node/src/test/kotlin/net/corda/node/services/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/InMemoryIdentityServiceTests.kt index 6417754abd..18aa843aa0 100644 --- a/node/src/test/kotlin/net/corda/node/services/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/InMemoryIdentityServiceTests.kt @@ -1,7 +1,6 @@ package net.corda.node.services import net.corda.core.crypto.Party -import net.corda.core.crypto.composite import net.corda.core.crypto.generateKeyPair import net.corda.node.services.identity.InMemoryIdentityService import net.corda.testing.ALICE @@ -51,7 +50,7 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by name`() { val service = InMemoryIdentityService() - val identities = listOf("Node A", "Node B", "Node C").map { Party(it, generateKeyPair().public.composite) } + val identities = listOf("Node A", "Node B", "Node C").map { Party(it, generateKeyPair().public) } assertNull(service.partyFromName(identities.first().name)) identities.forEach { service.registerIdentity(it) } identities.forEach { assertEquals(it, service.partyFromName(it.name)) } diff --git a/node/src/test/kotlin/net/corda/node/services/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/NodeSchedulerServiceTest.kt index aedded4d74..a51645be66 100644 --- a/node/src/test/kotlin/net/corda/node/services/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/NodeSchedulerServiceTest.kt @@ -1,8 +1,6 @@ package net.corda.node.services import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey -import net.corda.core.crypto.composite import net.corda.core.days import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogicRef @@ -113,7 +111,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { } class TestState(val flowLogicRef: FlowLogicRef, val instant: Instant) : LinearState, SchedulableState { - override val participants: List + override val participants: List get() = throw UnsupportedOperationException() override val linearId = UniqueIdentifier() @@ -272,7 +270,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { val state = TestState(factory.create(TestFlowLogic::class.java, increment), instant) val usefulTX = TransactionType.General.Builder(null).apply { addOutputState(state, DUMMY_NOTARY) - addCommand(Command(), freshKey.public.composite) + addCommand(Command(), freshKey.public) signWith(freshKey) }.toSignedTransaction() val txHash = usefulTX.id diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt index f55b9ecc3a..e95f16a9f7 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt @@ -6,6 +6,7 @@ import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef import net.corda.core.contracts.TransactionType import net.corda.core.crypto.DigitalSignature +import net.corda.core.crypto.keys import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.core.seconds diff --git a/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt b/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt index e90a5efd51..b39b97db00 100644 --- a/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt @@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.* import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import net.corda.core.crypto.containsAny import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogicRefFactory import net.corda.core.node.CordaPluginRegistry @@ -44,7 +45,7 @@ class ScheduledFlowTests { } } - override val participants: List = listOf(source.owningKey, destination.owningKey) + override val participants: List = listOf(source.owningKey, destination.owningKey) override fun isRelevant(ourKeys: Set): Boolean { return participants.any { it.containsAny(ourKeys) } diff --git a/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt index 14989ae104..317f62567e 100644 --- a/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt @@ -3,7 +3,7 @@ package net.corda.node.services import com.google.common.util.concurrent.ListenableFuture import net.corda.core.contracts.* import net.corda.core.crypto.DigitalSignature -import net.corda.core.crypto.composite +import net.corda.core.crypto.keys import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.core.transactions.SignedTransaction @@ -54,7 +54,7 @@ class ValidatingNotaryServiceTests { } @Test fun `should report error for missing signatures`() { - val expectedMissingKey = MEGA_CORP_KEY.public.composite + val expectedMissingKey = MEGA_CORP_KEY.public val stx = run { val inputState = issueState(clientNode) diff --git a/node/src/test/kotlin/net/corda/node/services/VaultWithCashTest.kt b/node/src/test/kotlin/net/corda/node/services/VaultWithCashTest.kt index 9c028eff0d..3f878d7b56 100644 --- a/node/src/test/kotlin/net/corda/node/services/VaultWithCashTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/VaultWithCashTest.kt @@ -6,7 +6,6 @@ import net.corda.contracts.testing.fillWithSomeTestCash import net.corda.contracts.testing.fillWithSomeTestDeals import net.corda.contracts.testing.fillWithSomeTestLinearStates import net.corda.core.contracts.* -import net.corda.core.crypto.composite import net.corda.core.node.services.VaultService import net.corda.core.node.services.consumedStates import net.corda.core.node.services.unconsumedStates @@ -82,7 +81,7 @@ class VaultWithCashTest { val state = w[0].state.data assertEquals(30.45.DOLLARS `issued by` DUMMY_CASH_ISSUER, state.amount) - assertEquals(services.key.public.composite, state.owner) + assertEquals(services.key.public, state.owner) assertEquals(34.70.DOLLARS `issued by` DUMMY_CASH_ISSUER, (w[2].state.data).amount) assertEquals(34.85.DOLLARS `issued by` DUMMY_CASH_ISSUER, (w[1].state.data).amount) @@ -95,7 +94,7 @@ class VaultWithCashTest { // A tx that sends us money. val freshKey = services.keyManagementService.freshKey() val usefulTX = TransactionType.General.Builder(null).apply { - Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public.composite, DUMMY_NOTARY) + Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY) signWith(MEGA_CORP_KEY) }.toSignedTransaction() @@ -113,7 +112,7 @@ class VaultWithCashTest { // A tx that doesn't send us anything. val irrelevantTX = TransactionType.General.Builder(DUMMY_NOTARY).apply { - Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_KEY.public.composite, DUMMY_NOTARY) + Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_KEY.public, DUMMY_NOTARY) signWith(MEGA_CORP_KEY) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() @@ -137,7 +136,7 @@ class VaultWithCashTest { services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 10, 10, Random(0L), issuedBy = MEGA_CORP.ref(1), issuerKey = MEGA_CORP_KEY, - ownedBy = freshKey.public.composite) + ownedBy = freshKey.public) println("Cash balance: ${vault.cashBalances[USD]}") assertThat(vault.unconsumedStates()).hasSize(10) @@ -226,8 +225,8 @@ class VaultWithCashTest { // Issue a linear state val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply { - addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public.composite))) - addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public.composite))) + addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public))) + addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public))) signWith(freshKey) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() @@ -247,7 +246,7 @@ class VaultWithCashTest { // Issue a linear state val dummyIssue = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply { - addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public.composite))) + addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public))) signWith(freshKey) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() @@ -259,7 +258,7 @@ class VaultWithCashTest { // Move the same state val dummyMove = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply { - addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public.composite))) + addOutputState(net.corda.contracts.testing.DummyLinearContract.State(linearId = linearId, participants = listOf(freshKey.public))) addInputState(dummyIssue.tx.outRef(0)) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() @@ -276,7 +275,7 @@ class VaultWithCashTest { val freshKey = services.keyManagementService.freshKey() databaseTransaction(database) { - services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L), ownedBy = freshKey.public.composite) + services.fillWithSomeTestCash(100.DOLLARS, DUMMY_NOTARY, 3, 3, Random(0L), ownedBy = freshKey.public) services.fillWithSomeTestCash(100.SWISS_FRANCS, DUMMY_NOTARY, 2, 2, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, DUMMY_NOTARY, 1, 1, Random(0L)) val cash = vault.unconsumedStates() @@ -320,8 +319,8 @@ class VaultWithCashTest { // Create a txn consuming different contract types val dummyMove = TransactionType.General.Builder(notary = DUMMY_NOTARY).apply { - addOutputState(net.corda.contracts.testing.DummyLinearContract.State(participants = listOf(freshKey.public.composite))) - addOutputState(net.corda.contracts.testing.DummyDealContract.State(ref = "999", participants = listOf(freshKey.public.composite))) + addOutputState(net.corda.contracts.testing.DummyLinearContract.State(participants = listOf(freshKey.public))) + addOutputState(net.corda.contracts.testing.DummyDealContract.State(ref = "999", participants = listOf(freshKey.public))) addInputState(linearStates.first()) addInputState(deals.first()) signWith(DUMMY_NOTARY_KEY) diff --git a/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt index 6f7f777340..ed9fe6ae4c 100644 --- a/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt @@ -9,6 +9,7 @@ import net.corda.core.contracts.TransactionType import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.NullPublicKey import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.toBase58String import net.corda.core.node.services.Vault import net.corda.core.serialization.serialize import net.corda.core.serialization.storageKryo diff --git a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt index 3a77aa0626..68cb7d959c 100644 --- a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt @@ -5,7 +5,7 @@ import com.google.common.net.HostAndPort import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture -import net.corda.core.crypto.composite +import com.typesafe.config.ConfigFactory.empty import net.corda.core.crypto.generateKeyPair import net.corda.core.messaging.Message import net.corda.core.messaging.RPCOps @@ -225,7 +225,7 @@ class ArtemisMessagingTests { config, MOCK_NODE_VERSION_INFO, server, - identity.public.composite, + identity.public, ServiceAffinityExecutor("ArtemisMessagingTests", 1), database, networkMapRegistrationFuture, diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt index 0344ff0d24..22f1f739a7 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt @@ -4,7 +4,6 @@ import net.corda.contracts.asset.Cash import net.corda.contracts.asset.DUMMY_CASH_ISSUER import net.corda.contracts.testing.fillWithSomeTestCash import net.corda.core.contracts.* -import net.corda.core.crypto.composite import net.corda.core.node.services.StatesNotAvailableException import net.corda.core.node.services.TxWritableStorageService import net.corda.core.node.services.VaultService @@ -406,7 +405,7 @@ class NodeVaultServiceTest { // Issue a txn to Send us some Money val usefulTX = TransactionType.General.Builder(null).apply { - Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public.composite, DUMMY_NOTARY) + Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY) signWith(MEGA_CORP_KEY) }.toSignedTransaction() @@ -419,7 +418,7 @@ class NodeVaultServiceTest { // Issue more Money (GBP) val anotherTX = TransactionType.General.Builder(null).apply { - Cash().generateIssue(this, 200.POUNDS `issued by` MEGA_CORP.ref(1), freshKey.public.composite, DUMMY_NOTARY) + Cash().generateIssue(this, 200.POUNDS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY) signWith(MEGA_CORP_KEY) }.toSignedTransaction() diff --git a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt index 75f34f0722..7547ad625c 100644 --- a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt +++ b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt @@ -3,6 +3,7 @@ package net.corda.irs import com.google.common.net.HostAndPort import com.google.common.util.concurrent.Futures import net.corda.client.rpc.CordaRPCClient +import net.corda.core.crypto.toBase58String import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.irs.api.NodeInterestRates diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt index fe88c4710c..3698e18a85 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt @@ -6,6 +6,7 @@ import net.corda.core.contracts.* import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.MerkleTreeException import net.corda.core.crypto.Party +import net.corda.core.crypto.keys import net.corda.core.crypto.signWithECDSA import net.corda.core.flows.FlowLogic import net.corda.core.math.CubicSplineInterpolator diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt index d72ccf3395..04a8bea1ca 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt @@ -679,7 +679,7 @@ class InterestRateSwap : Contract { override val ref = common.tradeID - override val participants: List + override val participants: List get() = parties.map { it.owningKey } override fun isRelevant(ourKeys: Set): Boolean { diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt index ac95c4c897..79a853ca38 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt @@ -3,8 +3,9 @@ package net.corda.irs.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.TransientProperty import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import net.corda.core.crypto.keys +import net.corda.core.crypto.toBase58String import net.corda.core.flows.FlowLogic import net.corda.core.node.NodeInfo import net.corda.core.node.PluginServiceHub @@ -17,6 +18,7 @@ import net.corda.core.utilities.trace import net.corda.flows.TwoPartyDealFlow import java.math.BigDecimal import java.security.KeyPair +import java.security.PublicKey object FixingFlow { @@ -54,7 +56,7 @@ object FixingFlow { } @Suspendable - override fun assembleSharedTX(handshake: TwoPartyDealFlow.Handshake): Pair> { + override fun assembleSharedTX(handshake: TwoPartyDealFlow.Handshake): Pair> { @Suppress("UNCHECKED_CAST") val fixOf = deal.nextFixingOf()!! @@ -111,8 +113,8 @@ object FixingFlow { } override val myKeyPair: KeyPair get() { - val myCompositeKey = serviceHub.myInfo.legalIdentity.owningKey - val myKeys = dealToFix.state.data.parties.filter { it.owningKey == myCompositeKey }.single().owningKey.keys + val myPublicKey = serviceHub.myInfo.legalIdentity.owningKey + val myKeys = dealToFix.state.data.parties.filter { it.owningKey == myPublicKey }.single().owningKey.keys return serviceHub.keyManagementService.toKeyPair(myKeys) } diff --git a/samples/irs-demo/src/main/resources/simulation/trade.json b/samples/irs-demo/src/main/resources/simulation/trade.json index 26f7e189d2..ba8168b1a9 100644 --- a/samples/irs-demo/src/main/resources/simulation/trade.json +++ b/samples/irs-demo/src/main/resources/simulation/trade.json @@ -1,6 +1,6 @@ { "fixedLeg": { - "fixedRatePayer": "3ThWzJauCq7qLrcX4KuKHxKnxZ6HoxnxU7pFL1HwfCkCJLUfTJ9zN92oxRLxnw", + "fixedRatePayer": "8Kqd4oWdx4KQAVcA8RDJXNvzFMvBkqWTZPhRtg9dSpNs6T6eZ4cGJWA7FWK", "notional": "$25000000", "paymentFrequency": "SemiAnnual", "effectiveDate": "2016-03-11", @@ -22,7 +22,7 @@ "interestPeriodAdjustment": "Adjusted" }, "floatingLeg": { - "floatingRatePayer": "3ThWzJauCq7qLrcX4KndaoA3TXWtoLzUSmQ9ia8xVWxHTmVGjXXXFXm9R9Wh2T", + "floatingRatePayer": "8Kqd4oWdx4KQAVc3Si48msuQrMJPGpA3TnGGuWTqXyoshjL25wzzdxtGyjq", "notional": { "quantity": 2500000000, "token": "USD" diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt index 82e5e759b1..f7b0497bab 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt @@ -4,9 +4,7 @@ import com.opengamma.strata.basics.currency.MultiCurrencyAmount import net.corda.core.contracts.DealState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.filterStatesOfType -import net.corda.core.crypto.AbstractParty -import net.corda.core.crypto.CompositeKey -import net.corda.core.crypto.Party +import net.corda.core.crypto.* import net.corda.core.getOrThrow import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow @@ -43,7 +41,7 @@ class PortfolioApi(val rpc: CordaRPCOps) { * Used as such: withParty(name) { doSomethingWith(it) } */ private fun withParty(partyName: String, func: (Party) -> Response): Response { - val otherParty = rpc.partyFromKey(CompositeKey.parseFromBase58(partyName)) + val otherParty = rpc.partyFromKey(parsePublicKeyBase58(partyName)) return if (otherParty != null) { func(otherParty) } else { diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApiUtils.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApiUtils.kt index 82354cdbe6..49b3322655 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApiUtils.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApiUtils.kt @@ -7,6 +7,7 @@ import com.opengamma.strata.product.swap.SwapLegType import net.corda.core.contracts.hash import net.corda.core.crypto.AbstractParty import net.corda.core.crypto.Party +import net.corda.core.crypto.toBase58String import net.corda.vega.contracts.IRSState import net.corda.vega.contracts.PortfolioState import net.corda.vega.portfolio.Portfolio diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/IRSState.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/IRSState.kt index 2a8abbb0ac..e9d24870d6 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/IRSState.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/IRSState.kt @@ -5,8 +5,8 @@ import net.corda.core.contracts.DealState import net.corda.core.contracts.TransactionType import net.corda.core.contracts.UniqueIdentifier import net.corda.core.crypto.AnonymousParty -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import net.corda.core.crypto.keys import net.corda.core.transactions.TransactionBuilder import java.security.PublicKey @@ -32,6 +32,6 @@ data class IRSState(val swap: SwapData, return TransactionType.General.Builder(notary).withItems(state, Command(OGTrade.Commands.Agree(), parties.map { it.owningKey })) } - override val participants: List + override val participants: List get() = parties.map { it.owningKey } } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioState.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioState.kt index 5663190cff..81296c8a74 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioState.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioState.kt @@ -2,8 +2,8 @@ package net.corda.vega.contracts import net.corda.core.contracts.* import net.corda.core.crypto.AnonymousParty -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party +import net.corda.core.crypto.keys import net.corda.core.flows.FlowLogicRefFactory import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.TransactionBuilder @@ -31,7 +31,7 @@ data class PortfolioState(val portfolio: List, override val ref: String = linearId.toString() val valuer: AnonymousParty get() = parties[0] - override val participants: List + override val participants: List get() = parties.map { it.owningKey } override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity { diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/SwapData.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/SwapData.kt index faf0c50a99..d2aad3935e 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/SwapData.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/SwapData.kt @@ -10,9 +10,10 @@ import com.opengamma.strata.product.swap.SwapTrade import com.opengamma.strata.product.swap.type.FixedIborSwapConvention import com.opengamma.strata.product.swap.type.FixedIborSwapConventions import net.corda.core.crypto.AbstractParty -import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.toBase58String import net.corda.core.serialization.CordaSerializable import java.math.BigDecimal +import java.security.PublicKey import java.time.LocalDate /** @@ -39,8 +40,8 @@ data class FloatingLeg(val _notional: BigDecimal, override val notional: BigDeci @CordaSerializable data class SwapData( val id: Pair, - val buyer: Pair, - val seller: Pair, + val buyer: Pair, + val seller: Pair, val description: String, val tradeDate: LocalDate, val convention: String, @@ -61,7 +62,7 @@ data class SwapData( return getTrade(BuySell.SELL, Pair("party", seller.second)) } - private fun getTrade(buySell: BuySell, party: Pair): SwapTrade { + private fun getTrade(buySell: BuySell, party: Pair): SwapTrade { val tradeInfo = TradeInfo.builder() .id(StandardId.of(id.first, id.second)) .addAttribute(TradeAttributeType.DESCRIPTION, description) diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt index 417a6f1eb7..7f4591a923 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt @@ -1,13 +1,13 @@ package net.corda.vega.flows import net.corda.core.contracts.StateAndRef -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction import net.corda.flows.AbstractStateReplacementFlow import net.corda.flows.StateReplacementException import net.corda.vega.contracts.RevisionedState +import java.security.PublicKey /** * Flow that generates an update on a mutable deal state and commits the resulting transaction reaching consensus @@ -16,7 +16,7 @@ import net.corda.vega.contracts.RevisionedState object StateRevisionFlow { class Requester(curStateRef: StateAndRef>, updatedData: T) : AbstractStateReplacementFlow.Instigator, RevisionedState, T>(curStateRef, updatedData) { - override fun assembleTx(): Pair> { + override fun assembleTx(): Pair> { val state = originalState.state.data val tx = state.generateRevision(originalState.state.notary, originalState, modification) tx.setTime(serviceHub.clock.instant(), 30.seconds) diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt index 8e913d886d..e5dae733d4 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt @@ -13,6 +13,7 @@ import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.ProgressTracker import net.corda.flows.NotaryFlow import net.corda.flows.TwoPartyTradeFlow +import java.security.PublicKey import java.time.Instant import java.util.* @@ -42,7 +43,7 @@ class SellerFlow(val otherParty: Party, val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0] val cpOwnerKey = serviceHub.legalIdentityKey - val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public.composite, notary) + val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, notary) progressTracker.currentStep = TRADING @@ -59,7 +60,7 @@ class SellerFlow(val otherParty: Party, } @Suspendable - fun selfIssueSomeCommercialPaper(ownedBy: CompositeKey, notaryNode: NodeInfo): StateAndRef { + fun selfIssueSomeCommercialPaper(ownedBy: PublicKey, notaryNode: NodeInfo): StateAndRef { // Make a fake company that's issued its own paper. val keyPair = generateKeyPair() val party = Party("Bank of London", keyPair.public) diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 32011babb3..03432c6713 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -31,6 +31,7 @@ import java.net.URL import java.nio.file.Files import java.nio.file.Path import java.security.KeyPair +import java.security.PublicKey import java.util.* import kotlin.reflect.KClass @@ -54,36 +55,36 @@ import kotlin.reflect.KClass // A few dummy values for testing. val MEGA_CORP_KEY: KeyPair by lazy { generateKeyPair() } -val MEGA_CORP_PUBKEY: CompositeKey get() = MEGA_CORP_KEY.public.composite +val MEGA_CORP_PUBKEY: PublicKey get() = MEGA_CORP_KEY.public val MINI_CORP_KEY: KeyPair by lazy { generateKeyPair() } -val MINI_CORP_PUBKEY: CompositeKey get() = MINI_CORP_KEY.public.composite +val MINI_CORP_PUBKEY: PublicKey get() = MINI_CORP_KEY.public val ORACLE_KEY: KeyPair by lazy { generateKeyPair() } -val ORACLE_PUBKEY: CompositeKey get() = ORACLE_KEY.public.composite +val ORACLE_PUBKEY: PublicKey get() = ORACLE_KEY.public val ALICE_KEY: KeyPair by lazy { generateKeyPair() } -val ALICE_PUBKEY: CompositeKey get() = ALICE_KEY.public.composite +val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public val ALICE: Party get() = Party("Alice", ALICE_PUBKEY) val BOB_KEY: KeyPair by lazy { generateKeyPair() } -val BOB_PUBKEY: CompositeKey get() = BOB_KEY.public.composite +val BOB_PUBKEY: PublicKey get() = BOB_KEY.public val BOB: Party get() = Party("Bob", BOB_PUBKEY) val CHARLIE_KEY: KeyPair by lazy { generateKeyPair() } -val CHARLIE_PUBKEY: CompositeKey get() = CHARLIE_KEY.public.composite +val CHARLIE_PUBKEY: PublicKey get() = CHARLIE_KEY.public val CHARLIE: Party get() = Party("Charlie", CHARLIE_PUBKEY) val MEGA_CORP: Party get() = Party("MegaCorp", MEGA_CORP_PUBKEY) val MINI_CORP: Party get() = Party("MiniCorp", MINI_CORP_PUBKEY) val BOC_KEY: KeyPair by lazy { generateKeyPair() } -val BOC_PUBKEY: CompositeKey get() = BOC_KEY.public.composite +val BOC_PUBKEY: PublicKey get() = BOC_KEY.public val BOC: Party get() = Party("BankOfCorda", BOC_PUBKEY) val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() } -val BIG_CORP_PUBKEY: CompositeKey get() = BIG_CORP_KEY.public.composite +val BIG_CORP_PUBKEY: PublicKey get() = BIG_CORP_KEY.public val BIG_CORP: Party get() = Party("BigCorporation", BIG_CORP_PUBKEY) val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference diff --git a/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt b/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt index 6ba1f39974..c8450a5635 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt @@ -129,7 +129,7 @@ data class TestTransactionDSLInterpreter private constructor( transactionBuilder.addAttachment(attachmentId) } - override fun _command(signers: List, commandData: CommandData) { + override fun _command(signers: List, commandData: CommandData) { val command = Command(commandData, signers) transactionBuilder.addCommand(command) } @@ -335,7 +335,7 @@ fun signAll(transactionsToSign: List, extraKeys: List) (ALL_TEST_KEYS + extraKeys).forEach { keyLookup[it.public] = it } - wtx.mustSign.keys.forEach { + wtx.mustSign.expandedCompositeKeys.forEach { val key = keyLookup[it] ?: throw IllegalArgumentException("Missing required key for ${it.toStringShort()}") signatures += key.signWithECDSA(wtx.id) } diff --git a/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt b/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt index 725425ef07..c84ec37447 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt @@ -1,12 +1,12 @@ package net.corda.testing import net.corda.core.contracts.* -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.seconds import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.DUMMY_NOTARY +import java.security.PublicKey import java.time.Duration import java.time.Instant import java.util.* @@ -48,7 +48,7 @@ interface TransactionDSLInterpreter : Verifies, OutputStateLookup { * @param signers The signer public keys. * @param commandData The contents of the command. */ - fun _command(signers: List, commandData: CommandData) + fun _command(signers: List, commandData: CommandData) /** * Adds a timestamp to the transaction. @@ -106,13 +106,13 @@ class TransactionDSL(val interpreter: T) : Tr /** * @see TransactionDSLInterpreter._command */ - fun command(vararg signers: CompositeKey, commandDataClosure: () -> CommandData) = + fun command(vararg signers: PublicKey, commandDataClosure: () -> CommandData) = _command(listOf(*signers), commandDataClosure()) /** * @see TransactionDSLInterpreter._command */ - fun command(signer: CompositeKey, commandData: CommandData) = _command(listOf(signer), commandData) + fun command(signer: PublicKey, commandData: CommandData) = _command(listOf(signer), commandData) /** * Adds a timestamp command to the transaction. diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index 55e2c96c5e..63196aad54 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -67,7 +67,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub { override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException() override val clock: Clock get() = Clock.systemUTC() override val schedulerService: SchedulerService get() = throw UnsupportedOperationException() - override val myInfo: NodeInfo get() = NodeInfo(object : SingleMessageRecipient {}, Party("MegaCorp", key.public.composite), MOCK_VERSION) + override val myInfo: NodeInfo get() = NodeInfo(object : SingleMessageRecipient {}, Party("MegaCorp", key.public), MOCK_VERSION) override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2) fun makeVaultService(dataSourceProps: Properties): VaultService { @@ -80,7 +80,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub { @ThreadSafe class MockIdentityService(val identities: List) : IdentityService, SingletonSerializeAsToken() { - private val keyToParties: Map + private val keyToParties: Map get() = synchronized(identities) { identities.associateBy { it.owningKey } } private val nameToParties: Map get() = synchronized(identities) { identities.associateBy { it.name } } @@ -92,7 +92,7 @@ class MockIdentityService(val identities: List) : IdentityService, Single override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) override fun partyFromAnonymous(party: AnonymousParty): Party? = keyToParties[party.owningKey] override fun partyFromAnonymous(partyRef: PartyAndReference): Party? = partyFromAnonymous(partyRef.party) - override fun partyFromKey(key: CompositeKey): Party? = keyToParties[key] + override fun partyFromKey(key: PublicKey): Party? = keyToParties[key] override fun partyFromName(name: String): Party? = nameToParties[name] } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index 5b3b4b2b6f..1ab7fc886f 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -3,7 +3,6 @@ package net.corda.testing.node import com.codahale.metrics.MetricRegistry import com.google.common.net.HostAndPort import com.google.common.util.concurrent.SettableFuture -import net.corda.core.crypto.composite import net.corda.core.crypto.generateKeyPair import net.corda.core.messaging.RPCOps import net.corda.node.services.RPCUserServiceImpl @@ -41,7 +40,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL config, MOCK_NODE_VERSION_INFO, address, - identity.public.composite, + identity.public, executor, database, networkMapRegistrationFuture, diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt index fa941e7688..1e1c1f5144 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt @@ -27,6 +27,7 @@ import net.corda.client.jfx.model.* import net.corda.client.jfx.utils.* import net.corda.core.contracts.ContractState import net.corda.core.crypto.Party +import net.corda.core.crypto.toBase58String import net.corda.core.node.NodeInfo import net.corda.explorer.model.CordaView import tornadofx.* diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt index 01f14e3c89..07bb3fb55a 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt @@ -25,6 +25,7 @@ import net.corda.core.contracts.* import net.corda.core.crypto.AbstractParty import net.corda.core.crypto.AnonymousParty import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.toBase58String import net.corda.core.crypto.toStringShort import net.corda.core.node.NodeInfo import net.corda.explorer.AmountDiff diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTest.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTest.kt index 77205674f1..02465c21f7 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTest.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTest.kt @@ -1,6 +1,7 @@ package net.corda.loadtest import net.corda.client.mock.Generator +import net.corda.core.crypto.toBase58String import net.corda.node.driver.PortAllocation import net.corda.node.services.network.NetworkMapService import net.corda.node.services.transactions.ValidatingNotaryService diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt index 4e0bd7c9ed..e4aafb28fd 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt @@ -7,6 +7,7 @@ import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.WireTransaction import java.io.ByteArrayInputStream import java.math.BigInteger +import java.security.PublicKey import java.util.* /** @@ -23,7 +24,7 @@ data class GeneratedLedger( ) { val hashTransactionMap: Map by lazy { transactions.associateBy(WireTransaction::id) } val attachmentMap: Map by lazy { attachments.associateBy(Attachment::id) } - val identityMap: Map by lazy { identities.associateBy(Party::owningKey) } + val identityMap: Map by lazy { identities.associateBy(Party::owningKey) } companion object { val empty = GeneratedLedger(emptyList(), emptyMap(), emptySet(), emptySet()) @@ -183,7 +184,7 @@ data class GeneratedLedger( data class GeneratedState( val nonce: Long, - override val participants: List + override val participants: List ) : ContractState { override val contract = DummyContract() } @@ -200,7 +201,7 @@ class GeneratedCommandData( ) : CommandData val keyPairGenerator = Generator.long().map { entropyToKeyPair(BigInteger.valueOf(it)) } -val publicKeyGenerator = keyPairGenerator.map { it.public.composite } +val publicKeyGenerator = keyPairGenerator.map { it.public } val stateGenerator: Generator = Generator.replicatePoisson(2.0, publicKeyGenerator).combine(Generator.long()) { participants, nonce -> GeneratedState(nonce, participants)