From 36d5d0d7b2fae93f34b58bca854bfbb4d790c7d9 Mon Sep 17 00:00:00 2001 From: kasiastreich Date: Wed, 12 Apr 2017 11:13:20 +0100 Subject: [PATCH] Refactor of CompositeKeys to implement PublicKey interface. (#433) * Make CompositeKey implement PublicKey The initial implementation of composite keys as their own distinct class separate from PublicKey means that the keys cannot be used on standard classes such as Certificate. This work is a beginning to modifying CompositeKey to being a PublicKey implementation, although significant further work is required to integrate this properly with the standard Java APIs, especially around verifying signatures using the new key type. * First stage of making CompositeKey implement PublicKey interface. Revert to using PublicKey everywhere we expect a key. * Move algorithm and format into companion object (#432) Move algorithm and format into companion object so that they can be referenced from other classes (i.e. the upcoming signature class). * Add simple invariants to construction of CompositeKey. Builder emits CompositeKeys in simplified normalised form. Forbid keys with single child node, force ordering on children and forbid duplicates on the same level. It's not full semantical normalisation. * Make constructor of CompositeKey private, move NodeWeight inside the class. Add utility function for Kryo deserialization to read list with length constraints. --- .../net/corda/jackson/JacksonSupport.kt | 15 +- .../corda/client/jfx/NodeMonitorModelTest.kt | 22 +-- .../client/jfx/model/NetworkIdentityModel.kt | 6 +- .../net/corda/core/contracts/ContractsDSL.kt | 6 +- .../net/corda/core/contracts/DummyContract.kt | 16 +- .../corda/core/contracts/DummyContractV2.kt | 11 +- .../net/corda/core/contracts/DummyState.kt | 4 +- .../net/corda/core/contracts/FungibleAsset.kt | 8 +- .../net/corda/core/contracts/Structures.kt | 15 +- .../corda/core/contracts/TransactionTypes.kt | 6 +- .../core/contracts/TransactionVerification.kt | 4 +- .../net/corda/core/crypto/AbstractParty.kt | 5 +- .../net/corda/core/crypto/AnonymousParty.kt | 5 +- .../net/corda/core/crypto/CompositeKey.kt | 168 ++++++++++-------- .../net/corda/core/crypto/CryptoUtilities.kt | 47 ++++- .../kotlin/net/corda/core/crypto/Party.kt | 7 +- .../net/corda/core/messaging/CordaRPCOps.kt | 4 +- .../kotlin/net/corda/core/node/ServiceHub.kt | 3 + .../core/node/services/IdentityService.kt | 4 +- .../core/node/services/NetworkMapCache.kt | 10 +- .../net/corda/core/node/services/Services.kt | 14 +- .../serialization/DefaultKryoCustomizer.kt | 3 +- .../net/corda/core/serialization/Kryo.kt | 47 +++-- .../core/transactions/BaseTransaction.kt | 6 +- .../core/transactions/LedgerTransaction.kt | 4 +- .../core/transactions/MerkleTransaction.kt | 5 +- .../core/transactions/SignedTransaction.kt | 21 ++- .../core/transactions/TransactionBuilder.kt | 9 +- .../core/transactions/WireTransaction.kt | 5 +- .../net/corda/core/utilities/ApiUtils.kt | 4 +- .../net/corda/core/utilities/TestConstants.kt | 5 +- .../flows/AbstractStateReplacementFlow.kt | 10 +- .../net/corda/flows/ContractUpgradeFlow.kt | 8 +- .../kotlin/net/corda/flows/FinalityFlow.kt | 1 + .../net/corda/flows/NotaryChangeFlow.kt | 10 +- .../net/corda/flows/TwoPartyDealFlow.kt | 15 +- .../net/corda/flows/TxKeyFlowUtilities.kt | 13 +- .../net/corda/core/node/isolated.jar | Bin 7893 -> 7908 bytes .../contracts/TransactionEncumbranceTests.kt | 4 +- .../contracts/TransactionGraphSearchTests.kt | 3 +- .../corda/core/contracts/TransactionTests.kt | 75 ++++++-- .../corda/core/crypto/CompositeKeyTests.kt | 37 +++- .../core/crypto/PartialMerkleTreeTest.kt | 3 +- .../kotlin/net/corda/core/crypto/PartyTest.kt | 4 +- .../core/flows/ContractUpgradeFlowTest.kt | 10 +- .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 10 +- .../core/flows/TxKeyFlowUtilitiesTests.kt | 6 +- .../core/node/AttachmentClassLoaderTests.kt | 4 +- .../net/corda/core/node/VaultUpdateTests.kt | 4 +- .../TransactionSerializationTests.kt | 15 +- .../net/corda/core/testing/Generators.kt | 11 +- docs/source/contract-upgrade.rst | 33 +--- .../docs/WorkflowTransactionBuildTutorial.kt | 2 +- docs/source/flow-state-machines.rst | 2 +- docs/source/key-concepts-core-types.rst | 4 +- .../corda/contracts/universal/Perceivable.kt | 4 +- .../corda/contracts/universal/PrettyPrint.kt | 4 +- .../contracts/universal/UniversalContract.kt | 6 +- .../net/corda/contracts/universal/Util.kt | 16 +- .../contracts/universal/ContractDefinition.kt | 3 +- .../corda/contracts/AnotherDummyContract.kt | 4 +- .../contracts/ICommercialPaperState.java | 4 +- .../corda/contracts/JavaCommercialPaper.java | 17 +- .../net/corda/contracts/CommercialPaper.kt | 17 +- .../corda/contracts/CommercialPaperLegacy.kt | 14 +- .../kotlin/net/corda/contracts/asset/Cash.kt | 27 +-- .../contracts/asset/CommodityContract.kt | 16 +- .../net/corda/contracts/asset/Obligation.kt | 49 ++--- .../corda/contracts/asset/OnLedgerAsset.kt | 6 +- .../clause/AbstractConserveAmount.kt | 8 +- .../kotlin/net/corda/contracts/clause/Net.kt | 4 +- .../contracts/testing/DummyDealContract.kt | 7 +- .../contracts/testing/DummyLinearContract.kt | 3 +- .../corda/contracts/testing/VaultFiller.kt | 11 +- .../kotlin/net/corda/flows/CashPaymentFlow.kt | 4 +- .../net/corda/flows/TwoPartyTradeFlow.kt | 13 +- .../corda/contracts/CommercialPaperTests.kt | 6 +- .../net/corda/contracts/asset/CashTests.kt | 5 +- .../corda/contracts/asset/ObligationTests.kt | 30 ++-- .../net/corda/contracts/testing/Generators.kt | 6 +- .../nodeapi/ArtemisMessagingComponent.kt | 9 +- .../services/vault/schemas/VaultSchemaTest.kt | 13 +- .../services/messaging/MQSecurityTest.kt | 4 +- .../corda/node/internal/CordaRPCOpsImpl.kt | 4 +- .../identity/InMemoryIdentityService.kt | 6 +- .../messaging/ArtemisMessagingServer.kt | 4 +- .../services/messaging/NodeMessagingClient.kt | 4 +- .../network/InMemoryNetworkMapCache.kt | 6 +- .../services/network/NetworkMapService.kt | 7 +- .../node/services/vault/NodeVaultService.kt | 10 +- .../corda/node/utilities/DatabaseSupport.kt | 22 +-- .../utilities/ServiceIdentityGenerator.kt | 5 +- .../net/corda/node/CordaRPCOpsImplTest.kt | 2 + .../node/messaging/TwoPartyTradeFlowTests.kt | 11 +- .../services/InMemoryIdentityServiceTests.kt | 3 +- .../node/services/NodeSchedulerServiceTest.kt | 6 +- .../corda/node/services/NotaryServiceTests.kt | 1 + .../corda/node/services/ScheduledFlowTests.kt | 3 +- .../services/ValidatingNotaryServiceTests.kt | 4 +- .../corda/node/services/VaultWithCashTest.kt | 23 ++- .../database/RequeryConfigurationTest.kt | 1 + .../messaging/ArtemisMessagingTests.kt | 4 +- .../services/vault/NodeVaultServiceTest.kt | 5 +- .../kotlin/net/corda/irs/IRSDemoTest.kt | 1 + .../net/corda/irs/api/NodeInterestRates.kt | 1 + .../main/kotlin/net/corda/irs/contract/IRS.kt | 2 +- .../kotlin/net/corda/irs/flows/FixingFlow.kt | 10 +- .../src/main/resources/simulation/trade.json | 4 +- .../kotlin/net/corda/vega/api/PortfolioApi.kt | 6 +- .../net/corda/vega/api/PortfolioApiUtils.kt | 1 + .../net/corda/vega/contracts/IRSState.kt | 4 +- .../corda/vega/contracts/PortfolioState.kt | 4 +- .../net/corda/vega/contracts/SwapData.kt | 9 +- .../net/corda/vega/flows/StateRevisionFlow.kt | 4 +- .../net/corda/traderdemo/flow/SellerFlow.kt | 5 +- .../kotlin/net/corda/testing/CoreTestUtils.kt | 17 +- .../main/kotlin/net/corda/testing/TestDSL.kt | 4 +- .../testing/TransactionDSLInterpreter.kt | 8 +- .../net/corda/testing/node/MockServices.kt | 6 +- .../net/corda/testing/node/SimpleNode.kt | 3 +- .../net/corda/explorer/views/Network.kt | 1 + .../corda/explorer/views/TransactionViewer.kt | 1 + .../kotlin/net/corda/loadtest/LoadTest.kt | 1 + .../net/corda/verifier/GeneratedLedger.kt | 7 +- 124 files changed, 707 insertions(+), 606 deletions(-) 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 0b6d090c585b0e9a4d2da725f3644b98aaeff491..450d5f0cdc410c7d295745c7f10af70294592e90 100644 GIT binary patch delta 3340 zcmV+n4fFEVJ>)&GF$aIvUuflrN`wFnN=4ezC0WD5W;fj*w7hhDa{3o^#O-KJ-uObUHnEcN1cyb?foO?EZ{`2A&0D~wqT+n1Io!5^*Aq}|(w*uiIG%$#jMTT>e`=)Y*p=(k%is=>ES~4U>Gt-hrev+l=WKZeVl&z}d z)mW6R(Q2gg$)2~0b+T^Xp4zTN5JqDd0-6|(ztKI2mI#6nL$o2r;J20)li||-`MGH! zmMx@pMlviVuati!%_6io@pdw0TZ)>VR7@@=v8r3Dq7l5RQs$fk8{M@hh}j{AkX$NT z>wHTDN6;3=VYJh6mZYMRpR!9!vcbSI49yfYTRZ7X_GBXH#8ECR!4McyG{w3`3X_?h zIcI$?f)nTt!;h1c{e27O3{Nw3P~_pM={w^$a*Jbkv)O<7#hKjnt=w>SF*6oH4^KrB zDGHFxWF|e$D{G~+qFJ(`NosmbejwQ@FAvi)?7XELS;<(HjVms}E}qIW-0I_2njxIm zOJ!Y?HEV$6RqHi&aPHCL&fSi0-M&{`?_+IgPsmMJ>oi5W``N@Jft3(vvkMepSR6Rj^bp%UXYd;mlryUYqi8iQY}z;?Uy^oxDo^ z&+#^QoS-Y!BO)8Yhq%rsrb*bcWG;{D1(|rrU)Yjr)*VbG)%O`e<4QV}XLK(x^Z+{9^mzsjzTZaQ?R+hJ~mY7DRU_hz&GORBUnQk$8Cf;h@mZ zMp}R3q9{a#cA?+5^L;>w`frD#Q9c^~{gLnXfoP0ua;-YiG|RO{8^{ja+xgZ{n?wrN z?iYhmF&C>Md6S`NIM*I+Y!~DHxX|C!AGtW^?F!IpbF^jWr$C%57-UGkxi41=nuJHn zue8S_?lGEj-Zm6#Jw0PDsY-rAUMKIS$}N9cEYatMVPM}kDTpP81}8dI-(DVPSLw=k zBT7*!?Hl=;DVoabI+i~+ijemZ~Z z0KMb<`$qNys=5HZL-daGPXoQ1XiT3=@+#6O&8w2$4XK|I-ylQ4GCd>iBo3gJ-iikU zwA4aIhY5&#a-f6HqpM8hk??TR7`tR;UDNpXz94nSev8+uPmhB$J<~&(F5d z|I~{+P}SU3ubJ(kImTPHm+Ju{#Hof}LYU`VHmaLkeW9wpkf*OU+Znu%^B#ZHMNiwY zGk>7zB`(azFKuDyS68XX2@Q2@;+h+P3k*VNo}kAo8DzZOdTNri#))^n#K`;>M&ma& zk>Nm_n2b-6y@{C(xNY>K>KVl9&wwxIFzYRk6DV)J$yDzTIMMqXgvU7AyA2`B{rl+u zI|Thd!tbN}_@DTmRQWc;|2KaUMEE-U3j+OkLdi*-49!V7bwT7&pkHV@jY~AXLuY<> z0lp08+&_F=8Qr5l%=4-H3t%P|@W}!Wm}oWesfkV#pPA?~5i}v12%Bg$@t%oeCKjEg z&rKXO(MDI?#Gnc3UrtD>nW%l%AOsRi#;Tzg4SPYqGQT8!Zdjma zt1?$^(YU#}S)g}^nC%p#zRkwCVJ;UO$JL+-L{_D1-K+?lPiOZvFzXt&;>vRDNyn}0 z8ST9;a5n3>3;L4u=3T?Gm2TLK%J3zXe%bLZmy5+wfsl7QinzdI%Z^vHY<+)ewWM3N zCtcep>KUrzR?AcxjtZPK7p1v;)o_iHq(ny5)CfG4&hA8JbPFfvt688|aU^g&hGR$y zG*$IM+-uDRN#Nug0!W}05i7bSq2e&?|>u|aj!CF7aA5vGy9keBu95S z<84B+4WIF{RV+xC(KS1_=ui}ASa*JzxRoe+1fD;1Zc;hcnAC8Vie9o9-7Cy=I^(DQ z2|O7?3Qq~V@G!}nt*pq@YXMHhRLxTjy#n34q1qOGV5&ccK0Hm~1A2e6R5I*>h5>=G z!^c_Mu2K`O3?d#B2&b#YhhrGRGpvgT8NXn7hK6Sa`W`;{8lD%3vKoUg0_lB=kAB;g zl2cYyVB&ZYBQd;y(LFrdYlnuH1>&@H<(AFJZ!zP^5>Jea>ABsf&7o^Pj!C@c7s(W> zU-?BV@Z#amqH4Vp(Wej7zXC@}#)4&DE|=z|DAi1+C-BD@X7Q%LQI^`wR#@0inK=H0Ise?a!BT(N zkOiK6I7tm}$I#^W>aK%g=K-!^o^{CDT`_E;wpYe?Zb>zyS#AZ$7MQrnOe}idiW<>* zB?pKVe8dKLTStGfxW`ejzg7)PJZ9CRG5qXv0x$0c@PmEKO^tCo9W0_0!!j7z@ocSD zW~65n{5IvFP+ARhdg2finh#cB*)H>~FeLE5jXRUEP)BI0rytL-KRZ3Jdxbat@Vz3yTrjxVC4V5yfob5Shr{6E_*!eua#}jDsf6# zwUjkqlw*IJGbFF|35F|>%sQq~yl%LbL5W%a!2u_0*|OTkHBM@$uErd>O=&BGG?!9Fi|v=l9cVNsl2|+IbOdZwsi;*L8xu4PH%INHv%3*I8gK@!)PX*>`!*ny>rRO`MifzzH1%n zk*0g-%b#1vx#pkHln-|{|d`Fj}3ujBj%p6g%3OKTWk$Hm+lGMk>9r`C21Vj7nS z7xjNP;+(`8WCO1zF@wti3X|x;6?)`*>;o4^H+T1J^V-MaSh)6rMkrVDdJU5sL0*8a z{^T_V(Vzb>TJK>tpS-?~{4X0wt>Mq#@OyX*{9O&Vy6Ea#+u%>(@747i8ve2~6&%I* z^v#YV97NOBw+^H4TP!54H8>kEzem?*wyS@cY1@*SSl~b_ojy$s{|F@S;-92Ru2TGe zz=Z#e^!-Q+{zd*>>R2JJf1N`(1GoBvs=s;sq3p9(=O7er;r1L(DV$KKD7>REtZ-7H zL!ndo{L>2WDx6WsD$FRnr_iHtMd7N#w8C2oEdevG(5~>l!UqZ;{ti$}2MGAo>tqIR z1^@u+4wI1<9J2%zf(QvknG!Vb1poj|laCy09r)DiWN!ul0O}3^05<>$0000000000 z0000O4FHqz0Tq+~1Raw}9XSK}69AL(0Tq+~1RayN9XkP5lk*)#1ELlHlK~eMlTaQr W1M?ODlK~epleiui29Fs40000^uwQxr delta 3307 zcmV

5R^J=Hz1F$aHE6twa~B|^Xkr6O(VlB{82vzzYT(DKsp$?0Fv8Q(gc>9h|% z;7kQaXIe^U`p`eA)9Liw%_c-(YSEcw_uPBW`R@1KbMC$S=RYrh0nm>k!zDxI$*gJR z6nYxmQnK7mYPP8>T+Jni4U;da)>x@fSQ~YRJ7+kJ`N0^%%gTSMlGGI=pPXJ?R z55t*SNK383tw6X4bqsQ4km17QfvF5KbWEC7KDn&&MN82PJE<7tr*O?Ad&=ZfC0!@4 z`n<|Vt214UcfHkIr+3Bet8FlZAnJpV(7%_DRc(m#c9g^fdvbOXBpaP=HaR7yW=-93uE`v>A8P}JDKTQnc?(8YAl2itpvM{7MV0)Q z<89$ML0hUzMmmHKab0vwldvVlUK%xXD)CUiC@H$VYhfy>e!vi^lzCd^N>1Sl$(9PM z9y;>r%$61%3pB|JwQ^L$FSj0@2}(yL=fCwRD23&qB$u0#Tu1F##g?}p%SX2!^-H~M zq$z(Y%Ticsm3lqf-}|Jn_jVv07OnB$AA4>e3P;E$*QyhBvrKcij%?rk?QgvlB-3=Q zUfCa(Gm$Ei+ZhN4Gp*tJRypd8O1%xep@CU9%15J(;im1Md{LpGpCSI{bGcH`Bs^4n z?Rf0m6Kt&&xk-_<&25dV6Y3fTHdHpuLV(acglhg7E<-RvY&tf$AzHqrac zowu*5xns9xwvXnBIKbUp_YomMHSh}3oZzxv4JzvkRP_a1eYM$6;eA|mp$30kZ70tC zfreMOG#98y<=Y7F--vG!;p^-#Nc2gCf|EEEhLdtS8<9nhzS~S{7pQ%g*8JW) zJSohUfB3l4x=%mMiLM9pU^eFQ$vh6(XtwdGjdmNK+32w0w;|gI+Nihjo{bYW7M!8a zZ5+1ILR;KMzYXPIP)i30)A(;*?gan-(gch&0-Y?HS`Q(!iKB!Bm3e*0vfWwf zoGTTJOCx`k&l-e4Y|dCT^nzi{=ohEwq{j^kbgWnA$aNamHrESuZW6QXywo??7&dbA zdE0h0Xab={>6q7-1kNVYI~tgD3`=ok+SaJ;RP_vYUJ-aGZ96mioOGuh!?cucSd7Z> zB$a-_b}y6)g+YOUdozrvzytHPTQDtsZn3DFmMec9%P8n6s^eBOr!*WCIGUT4x%o?m zV-zJNQmUdx;NfI?GctqgI2ljP484jXhQkpYLR_HEoi&xfBk6sof^PTi8xn!$f}Al5 zRmNp`T{_arNr4BqD07w;TwBk`T*;ARhMMK>)*0!hcTkW>cHUb>6i3n0fB^0nI5Zg^kJD2x-V zJFiTfr7$`K9^ZFv5*gN*)bJ1$J!LYwXPD_^%1ix8oQfcUhXtP4OY$a{7G&aiAE!d1 z;;DvCf%dIXZHV4C)g3_>PE&Z7-YgakE3bc{M__3GaaOjg#E2vPhS2{ z>*8L<&l#?v;ZcFEy(eG8;{st;qyI%9xnuFsZ)>S&msA;;D4xVX1W#aa8_%}eq2XzP zC@o#QVX=Q-khFGcM{5je!B(a#DMwq+;<*T(!H~ejE~UK=hrzw*E#o^9fsS(m4L5&G zcQ)n9BF~ZY$*HYp(7rn%icvi8mChJ@LV2Yu@Z|nasB#w&=hOS?YJmeqW5&!~C>5ur zBOp=&$9JuDribVA0z=J|eeK>A>+-7XTW2baae~EK^EY|dRW+HsVH8>ly{n3WdrOrWLEFqBsIJqL7msZTaJ&-$GV1T)}dFUhDFr2 z%lPIkiJCOaEf3j%9Ii7Hv#z_K26SH3K4N(fu^!&xVa#rGKvz)7lWLsI2r|}{S{cY^L)$q3H-f! zYcvvQ39S9YRT}i^>a7}yg{yB>A)gyq;|5z+Z}kUy1^}$RsYJ}uj{DS z^X6DxI26;_3G$s(Y3XA?e;Mwey@u>E8X{)r2@)y?uB}RXV@1+HtQJIqnGz z{QoOW!z~Vb+cxgJD{%kilI5C3&Mu3lGN%i2Xl=6OWk14j1>$KtXB2;~7>;RBV$yqX z>`9xJEVprmlh~}QHeGH|+Q=Yt^ApBGWm_a;mz?)8XgtLta9{ZP{xEi)@RtD1o08yw_~fCmut z6@9}n>PbhtZ=PDA*c#u6UA?ve{scZNuV2#e#^zLTK;zRhJB*+oO;gtjjIN(B6E~M(uOjyg+SamN&P>y~ z%tU+#8tL?LYWRQLm%NQHNaI{3_q^g&Vjzg<}dw6qXd;Qs`GWs?eg)syzO2g|`(>D5Mo86y8zjP`IdYNnu>!nnHum zj4CuMysPk@!u$ULP)i302}bNcVFmyI01p5FP)h>@6abU?78J7+6oLo|)A(;*?gan< zW0Rg7Ya9ti>_1@!0000F001`t2><{900000000007Y&oK95a(x9XSH(6O*wVGn2+0 pI{` = 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)