mirror of
https://github.com/corda/corda.git
synced 2025-06-19 07:38:22 +00:00
Replace PublicKey with PublicKeyTree in Party. A single entity can now be identified by more than one key.
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import java.security.PublicKey
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -60,16 +60,16 @@ inline fun <R> requireThat(body: Requirements.() -> R) = R.body()
|
||||
//// Authenticated commands ///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Filters the command list by type, party and public key all at once. */
|
||||
inline fun <reified T : CommandData> Collection<AuthenticatedObject<CommandData>>.select(signer: PublicKey? = null,
|
||||
party: Party? = null) =
|
||||
inline fun <reified T : CommandData> Collection<AuthenticatedObject<CommandData>>.select(signer: PublicKeyTree? = null,
|
||||
party: Party? = null) =
|
||||
filter { it.value is T }.
|
||||
filter { if (signer == null) true else signer in it.signers }.
|
||||
filter { if (party == null) true else party in it.signingParties }.
|
||||
map { AuthenticatedObject(it.signers, it.signingParties, it.value as T) }
|
||||
|
||||
/** Filters the command list by type, parties and public keys all at once. */
|
||||
inline fun <reified T : CommandData> Collection<AuthenticatedObject<CommandData>>.select(signers: Collection<PublicKey>?,
|
||||
parties: Collection<Party>?) =
|
||||
inline fun <reified T : CommandData> Collection<AuthenticatedObject<CommandData>>.select(signers: Collection<PublicKeyTree>?,
|
||||
parties: Collection<Party>?) =
|
||||
filter { it.value is T }.
|
||||
filter { if (signers == null) true else it.signers.containsAll(signers)}.
|
||||
filter { if (parties == null) true else it.signingParties.containsAll(parties) }.
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
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.
|
||||
|
||||
@ -15,12 +15,12 @@ class DummyContract : Contract {
|
||||
val magicNumber: Int
|
||||
}
|
||||
|
||||
data class SingleOwnerState(override val magicNumber: Int = 0, override val owner: PublicKey) : OwnableState, State {
|
||||
data class SingleOwnerState(override val magicNumber: Int = 0, override val owner: PublicKeyTree) : OwnableState, State {
|
||||
override val contract = DUMMY_PROGRAM_ID
|
||||
override val participants: List<PublicKey>
|
||||
override val participants: List<PublicKeyTree>
|
||||
get() = listOf(owner)
|
||||
|
||||
override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner))
|
||||
override fun withNewOwner(newOwner: PublicKeyTree) = Pair(Commands.Move(), copy(owner = newOwner))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,9 +29,9 @@ class DummyContract : Contract {
|
||||
* 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<PublicKey>) : ContractState, State {
|
||||
val owners: List<PublicKeyTree>) : ContractState, State {
|
||||
override val contract = DUMMY_PROGRAM_ID
|
||||
override val participants: List<PublicKey>
|
||||
override val participants: List<PublicKeyTree>
|
||||
get() = owners
|
||||
}
|
||||
|
||||
@ -54,8 +54,8 @@ class DummyContract : Contract {
|
||||
return TransactionType.General.Builder(notary = notary).withItems(state, Command(Commands.Create(), owner.party.owningKey))
|
||||
}
|
||||
|
||||
fun move(prior: StateAndRef<DummyContract.SingleOwnerState>, newOwner: PublicKey) = move(listOf(prior), newOwner)
|
||||
fun move(priors: List<StateAndRef<DummyContract.SingleOwnerState>>, newOwner: PublicKey): TransactionBuilder {
|
||||
fun move(prior: StateAndRef<DummyContract.SingleOwnerState>, newOwner: PublicKeyTree) = move(listOf(prior), newOwner)
|
||||
fun move(priors: List<StateAndRef<DummyContract.SingleOwnerState>>, newOwner: PublicKeyTree): TransactionBuilder {
|
||||
require(priors.size > 0)
|
||||
val priorState = priors[0].state.data
|
||||
val (cmd, state) = priorState.withNewOwner(newOwner)
|
||||
|
@ -1,12 +1,11 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import java.security.PublicKey
|
||||
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
/**
|
||||
* 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<PublicKey>
|
||||
override val participants: List<PublicKeyTree>
|
||||
get() = emptyList()
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import java.security.PublicKey
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
|
||||
class InsufficientBalanceException(val amountMissing: Amount<*>) : Exception() {
|
||||
override fun toString() = "Insufficient balance, missing $amountMissing"
|
||||
@ -26,10 +26,11 @@ interface FungibleAsset<T> : 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<PublicKey>
|
||||
val exitKeys: Collection<PublicKeyTree>
|
||||
/** There must be a MoveCommand signed by this key to claim the amount */
|
||||
override val owner: PublicKey
|
||||
fun move(newAmount: Amount<Issued<T>>, newOwner: PublicKey): FungibleAsset<T>
|
||||
override val owner: PublicKeyTree
|
||||
|
||||
fun move(newAmount: Amount<Issued<T>>, newOwner: PublicKeyTree): FungibleAsset<T>
|
||||
|
||||
// Just for grouping
|
||||
interface Commands : CommandData {
|
||||
|
@ -2,8 +2,8 @@ package net.corda.core.contracts
|
||||
|
||||
import net.corda.core.contracts.clauses.Clause
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.protocols.ProtocolLogicRef
|
||||
import net.corda.core.protocols.ProtocolLogicRefFactory
|
||||
@ -113,7 +113,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<PublicKey>
|
||||
val participants: List<PublicKeyTree>
|
||||
|
||||
/**
|
||||
* All contract states may be _encumbered_ by up to one other state.
|
||||
@ -184,10 +184,10 @@ fun <T> Amount<Issued<T>>.withoutIssuer(): Amount<T> = Amount(quantity, token.pr
|
||||
*/
|
||||
interface OwnableState : ContractState {
|
||||
/** There must be a MoveCommand signed by this key to claim the amount */
|
||||
val owner: PublicKey
|
||||
val owner: PublicKeyTree
|
||||
|
||||
/** Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone */
|
||||
fun withNewOwner(newOwner: PublicKey): Pair<CommandData, OwnableState>
|
||||
fun withNewOwner(newOwner: PublicKeyTree): Pair<CommandData, OwnableState>
|
||||
}
|
||||
|
||||
/** Something which is scheduled to happen at a point in time */
|
||||
@ -351,15 +351,15 @@ abstract class TypeOnlyCommandData : CommandData {
|
||||
}
|
||||
|
||||
/** Command data/content plus pubkey pair: the signature is stored at the end of the serialized bytes */
|
||||
data class Command(val value: CommandData, val signers: List<PublicKey>) {
|
||||
data class Command(val value: CommandData, val signers: List<PublicKeyTree>) {
|
||||
init {
|
||||
require(signers.isNotEmpty())
|
||||
}
|
||||
|
||||
constructor(data: CommandData, key: PublicKey) : this(data, listOf(key))
|
||||
constructor(data: CommandData, key: PublicKeyTree) : 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.map { it.toStringShort() }}"
|
||||
override fun toString() = "${commandDataToString()} with pubkeys ${signers.joinToString()}"
|
||||
}
|
||||
|
||||
/** A common issue command, to enforce that issue commands have a nonce value. */
|
||||
@ -386,7 +386,7 @@ interface NetCommand : CommandData {
|
||||
|
||||
/** Wraps an object that was signed by a public key, which may be a well known/recognised institutional key. */
|
||||
data class AuthenticatedObject<out T : Any>(
|
||||
val signers: List<PublicKey>,
|
||||
val signers: List<PublicKeyTree>,
|
||||
/** If any public keys were recognised, the looked up institutions are available here */
|
||||
val signingParties: List<Party>,
|
||||
val value: T
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
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 */
|
||||
sealed class TransactionType {
|
||||
@ -25,7 +25,7 @@ sealed class TransactionType {
|
||||
}
|
||||
|
||||
/** Check that the list of signers includes all the necessary keys */
|
||||
fun verifySigners(tx: LedgerTransaction): Set<PublicKey> {
|
||||
fun verifySigners(tx: LedgerTransaction): Set<PublicKeyTree> {
|
||||
val notaryKey = tx.inputs.map { it.state.notary.owningKey }.toSet()
|
||||
if (notaryKey.size > 1) throw TransactionVerificationException.MoreThanOneNotary(tx)
|
||||
|
||||
@ -39,7 +39,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<PublicKey>
|
||||
abstract fun getRequiredSigners(tx: LedgerTransaction): Set<PublicKeyTree>
|
||||
|
||||
/** Implement type specific transaction validation logic */
|
||||
abstract fun verifyTransaction(tx: LedgerTransaction)
|
||||
|
@ -1,10 +1,9 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.toStringShort
|
||||
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.
|
||||
@ -94,8 +93,8 @@ class TransactionConflictException(val conflictRef: StateRef, val tx1: LedgerTra
|
||||
sealed class TransactionVerificationException(val tx: LedgerTransaction, cause: Throwable?) : Exception(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<PublicKey>) : TransactionVerificationException(tx, null) {
|
||||
override fun toString() = "Signers missing: ${missing.map { it.toStringShort() }}"
|
||||
class SignersMissing(tx: LedgerTransaction, val missing: List<PublicKeyTree>) : TransactionVerificationException(tx, null) {
|
||||
override fun toString() = "Signers missing: ${missing.joinToString()}"
|
||||
}
|
||||
class InvalidNotaryChange(tx: LedgerTransaction) : TransactionVerificationException(tx, null)
|
||||
class NotaryChangeInWrongTransactionType(tx: LedgerTransaction, val outputNotary: Party) : TransactionVerificationException(tx, null) {
|
||||
|
@ -31,7 +31,8 @@ open class DigitalSignature(bits: ByteArray) : OpaqueBytes(bits) {
|
||||
fun verifyWithECDSA(content: OpaqueBytes) = by.verifyWithECDSA(content.bits, this)
|
||||
}
|
||||
|
||||
class LegallyIdentifiable(val signer: Party, bits: ByteArray) : WithKey(signer.owningKey, 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)
|
||||
}
|
||||
|
||||
object NullPublicKey : PublicKey, Comparable<PublicKey> {
|
||||
@ -42,6 +43,8 @@ object NullPublicKey : PublicKey, Comparable<PublicKey> {
|
||||
override fun toString() = "NULL_KEY"
|
||||
}
|
||||
|
||||
val NullPublicKeyTree = NullPublicKey.tree
|
||||
|
||||
// TODO: Clean up this duplication between Null and Dummy public key
|
||||
class DummyPublicKey(val s: String) : PublicKey, Comparable<PublicKey> {
|
||||
override fun getAlgorithm() = "DUMMY"
|
||||
@ -78,7 +81,7 @@ fun KeyPair.signWithECDSA(bitsToSign: ByteArray) = private.signWithECDSA(bitsToS
|
||||
fun KeyPair.signWithECDSA(bitsToSign: OpaqueBytes) = private.signWithECDSA(bitsToSign.bits, public)
|
||||
fun KeyPair.signWithECDSA(bitsToSign: OpaqueBytes, party: Party) = signWithECDSA(bitsToSign.bits, party)
|
||||
fun KeyPair.signWithECDSA(bitsToSign: ByteArray, party: Party): DigitalSignature.LegallyIdentifiable {
|
||||
check(public == party.owningKey)
|
||||
check(public in party.owningKey.keys)
|
||||
val sig = signWithECDSA(bitsToSign)
|
||||
return DigitalSignature.LegallyIdentifiable(party, sig.bits)
|
||||
}
|
||||
@ -99,8 +102,6 @@ fun PublicKey.toStringShort(): String {
|
||||
} ?: toString()
|
||||
}
|
||||
|
||||
fun Iterable<PublicKey>.toStringsShort(): String = map { it.toStringShort() }.toString()
|
||||
|
||||
/** Creates a [PublicKeyTree] with a single leaf node containing the public key */
|
||||
val PublicKey.tree: PublicKeyTree get() = PublicKeyTree.Leaf(this)
|
||||
|
||||
|
@ -4,10 +4,28 @@ import net.corda.core.contracts.PartyAndReference
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import java.security.PublicKey
|
||||
|
||||
/** A [Party] is well known (name, pubkey) pair. In a real system this would probably be an X.509 certificate. */
|
||||
data class Party(val name: String, val owningKey: 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 [PublicKeyTree], 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.
|
||||
* Her advertised [Party] then has a legal [name] "Alice" and an [owingKey] "pub1 or pub2".
|
||||
*
|
||||
* [Party] is also used for service identities. E.g. Alice may also be running an interest rate oracle on her Corda node,
|
||||
* which requires a separate signing key (and an identifying name). Services can also be distributed – run by a coordinated
|
||||
* cluster of Corda nodes. A [Party] representing a distributed service will have a public key tree composed of the
|
||||
* individual cluster nodes' public keys. Each of the nodes in the cluster will advertise the same group [Party].
|
||||
*
|
||||
* @see PublicKeyTree
|
||||
*/
|
||||
data class Party(val name: String, val owningKey: PublicKeyTree) {
|
||||
/** A helper constructor that converts the given [PublicKey] in to a [PublicKeyTree] with a single node */
|
||||
constructor(name: String, owningKey: PublicKey) : this(name, owningKey.tree)
|
||||
|
||||
override fun toString() = name
|
||||
|
||||
fun ref(bytes: OpaqueBytes) = PartyAndReference(this, bytes)
|
||||
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
|
||||
}
|
||||
}
|
@ -26,10 +26,10 @@ sealed class PublicKeyTree {
|
||||
fun isFulfilledBy(key: PublicKey) = isFulfilledBy(setOf(key))
|
||||
|
||||
/** Returns all [PublicKey]s contained within the tree leaves */
|
||||
abstract fun getKeys(): Set<PublicKey>
|
||||
abstract val keys: Set<PublicKey>
|
||||
|
||||
/** Checks whether any of the given [keys] matches a leaf on the tree */
|
||||
fun containsAny(keys: Iterable<PublicKey>) = getKeys().intersect(keys).isNotEmpty()
|
||||
fun containsAny(otherKeys: Iterable<PublicKey>) = keys.intersect(otherKeys).isNotEmpty()
|
||||
|
||||
// TODO: implement a proper encoding/decoding mechanism
|
||||
fun toBase58String(): String = Base58.encode(this.serialize().bits)
|
||||
@ -42,21 +42,17 @@ sealed class PublicKeyTree {
|
||||
class Leaf(val publicKey: PublicKey) : PublicKeyTree() {
|
||||
override fun isFulfilledBy(keys: Iterable<PublicKey>) = publicKey in keys
|
||||
|
||||
override fun getKeys(): Set<PublicKey> = setOf(publicKey)
|
||||
override val keys: Set<PublicKey>
|
||||
get() = setOf(publicKey)
|
||||
|
||||
// Auto-generated. TODO: remove once data class inheritance is enabled
|
||||
// TODO: remove once data class inheritance is enabled
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
|
||||
other as Leaf
|
||||
|
||||
if (publicKey != other.publicKey) return false
|
||||
|
||||
return true
|
||||
return this === other || other is Leaf && other.publicKey == this.publicKey
|
||||
}
|
||||
|
||||
override fun hashCode() = publicKey.hashCode()
|
||||
|
||||
override fun toString() = publicKey.toStringShort()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +74,8 @@ sealed class PublicKeyTree {
|
||||
return totalWeight >= threshold
|
||||
}
|
||||
|
||||
override fun getKeys(): Set<PublicKey> = children.flatMap { it.getKeys() }.toSet()
|
||||
override val keys: Set<PublicKey>
|
||||
get() = children.flatMap { it.keys }.toSet()
|
||||
|
||||
// Auto-generated. TODO: remove once data class inheritance is enabled
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -100,6 +97,8 @@ sealed class PublicKeyTree {
|
||||
result = 31 * result + children.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString() = "(${children.joinToString()})"
|
||||
}
|
||||
|
||||
/** A helper class for building a [PublicKeyTree.Node]. */
|
||||
@ -119,8 +118,7 @@ sealed class PublicKeyTree {
|
||||
return this
|
||||
}
|
||||
|
||||
fun addLeaves(publicKeys: List<PublicKey>): Builder = addLeaves(*publicKeys.toTypedArray())
|
||||
fun addLeaves(vararg publicKeys: PublicKey) = addKeys(*publicKeys.map { it.tree }.toTypedArray())
|
||||
fun addKeys(publicKeys: List<PublicKeyTree>): Builder = addKeys(*publicKeys.toTypedArray())
|
||||
|
||||
/**
|
||||
* Builds the [PublicKeyTree.Node]. If [threshold] is not specified, it will default to
|
||||
@ -131,7 +129,16 @@ sealed class PublicKeyTree {
|
||||
else Node(threshold ?: children.size, children.toList(), weights.toList())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enclosed [PublicKey] for a [PublicKeyTree] with a single node
|
||||
*
|
||||
* @throws IllegalArgumentException if the [PublicKeyTree] contains more than one node
|
||||
*/
|
||||
val singleKey: PublicKey
|
||||
get() = keys.singleOrNull() ?: throw IllegalStateException("The public key tree has more than one node")
|
||||
}
|
||||
|
||||
/** Returns the set of all [PublicKey]s contained in the leaves of the [PublicKeyTree]s */
|
||||
fun Iterable<PublicKeyTree>.getKeys() = flatMap { it.getKeys() }.toSet()
|
||||
val Iterable<PublicKeyTree>.keys: Set<PublicKey>
|
||||
get() = flatMap { it.keys }.toSet()
|
@ -1,13 +1,13 @@
|
||||
package net.corda.core.node
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TransactionResolutionException
|
||||
import net.corda.core.contracts.TransactionState
|
||||
import net.corda.core.messaging.MessagingService
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.protocols.ProtocolLogic
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import java.security.KeyPair
|
||||
import java.time.Clock
|
||||
|
||||
@ -59,8 +59,11 @@ interface ServiceHub {
|
||||
* Helper property to shorten code for fetching the Node's KeyPair associated with the
|
||||
* public legalIdentity Party from the key management service.
|
||||
* Typical use is during signing in protocols and for unit test signing.
|
||||
*
|
||||
* TODO: legalIdentity can now be composed of multiple keys, should we return a list of keyPairs here? Right now
|
||||
* the logic assumes the legal identity has a public key tree with only one node
|
||||
*/
|
||||
val legalIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.legalIdentity.owningKey)
|
||||
val legalIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.legalIdentity.owningKey.keys)
|
||||
|
||||
/**
|
||||
* Helper property to shorten code for fetching the Node's KeyPair associated with the
|
||||
@ -69,7 +72,7 @@ interface ServiceHub {
|
||||
* an IllegalArgumentException.
|
||||
* Typical use is during signing in protocols and for unit test signing.
|
||||
*/
|
||||
val notaryIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.notaryIdentity.owningKey)
|
||||
val notaryIdentityKey: KeyPair get() = this.keyManagementService.toKeyPair(this.myInfo.notaryIdentity.owningKey.keys)
|
||||
|
||||
}
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.core.node.services
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import java.security.PublicKey
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
|
||||
/**
|
||||
* An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports
|
||||
@ -15,6 +15,6 @@ 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: PublicKey): Party?
|
||||
fun partyFromKey(key: PublicKeyTree): Party?
|
||||
fun partyFromName(name: String): Party?
|
||||
}
|
||||
|
@ -4,12 +4,12 @@ import com.google.common.annotations.VisibleForTesting
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.messaging.MessagingService
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.NodeInfo
|
||||
import org.slf4j.LoggerFactory
|
||||
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,7 +74,7 @@ interface NetworkMapCache {
|
||||
/**
|
||||
* Look up the node info for a public key.
|
||||
*/
|
||||
fun getNodeByPublicKey(publicKey: PublicKey): NodeInfo?
|
||||
fun getNodeByPublicKey(publicKey: PublicKeyTree): NodeInfo?
|
||||
|
||||
/**
|
||||
* Add a network map service; fetches a copy of the latest map from the service and subscribes to any further
|
||||
|
@ -4,7 +4,9 @@ import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import rx.Observable
|
||||
@ -184,8 +186,8 @@ interface VaultService {
|
||||
@Throws(InsufficientBalanceException::class)
|
||||
fun generateSpend(tx: TransactionBuilder,
|
||||
amount: Amount<Currency>,
|
||||
to: PublicKey,
|
||||
onlyFromParties: Set<Party>? = null): Pair<TransactionBuilder, List<PublicKey>>
|
||||
to: PublicKeyTree,
|
||||
onlyFromParties: Set<Party>? = null): Pair<TransactionBuilder, List<PublicKeyTree>>
|
||||
}
|
||||
|
||||
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
||||
@ -201,14 +203,19 @@ inline fun <reified T : DealState> VaultService.dealsWith(party: Party) = linear
|
||||
* The current interface is obviously not usable for those use cases: this is just where we'd put a real signing
|
||||
* interface if/when one is developed.
|
||||
*/
|
||||
|
||||
interface KeyManagementService {
|
||||
/** Returns a snapshot of the current pubkey->privkey mapping. */
|
||||
val keys: Map<PublicKey, PrivateKey>
|
||||
|
||||
fun toPrivate(publicKey: PublicKey) = keys[publicKey] ?: throw IllegalStateException("No private key known for requested public key")
|
||||
// TODO: make toPrivate return null if not found instead of throwing
|
||||
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))
|
||||
|
||||
/** Returns the first [KeyPair] matching any of the [publicKeys] */
|
||||
fun toKeyPair(publicKeys: Iterable<PublicKey>) = publicKeys.first { keys.contains(it) }.let { toKeyPair(it) }
|
||||
|
||||
/** Generates a new random key and adds it to the exposed map. */
|
||||
fun freshKey(): KeyPair
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import com.esotericsoftware.kryo.io.Input
|
||||
import com.esotericsoftware.kryo.io.Output
|
||||
import com.esotericsoftware.kryo.serializers.JavaSerializer
|
||||
import com.esotericsoftware.kryo.serializers.MapSerializer
|
||||
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
||||
import de.javakaffee.kryoserializers.guava.*
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.node.AttachmentsClassLoader
|
||||
@ -18,9 +20,6 @@ import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.core.utilities.NonEmptySetSerializer
|
||||
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
||||
import de.javakaffee.kryoserializers.guava.*
|
||||
import net.corda.core.crypto.*
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||
@ -32,7 +31,6 @@ import java.io.ObjectOutputStream
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
@ -268,7 +266,7 @@ object WireTransactionSerializer : Serializer<WireTransaction>() {
|
||||
val outputs = kryo.readClassAndObject(input) as List<TransactionState<ContractState>>
|
||||
val commands = kryo.readClassAndObject(input) as List<Command>
|
||||
val notary = kryo.readClassAndObject(input) as Party?
|
||||
val signers = kryo.readClassAndObject(input) as List<PublicKey>
|
||||
val signers = kryo.readClassAndObject(input) as List<PublicKeyTree>
|
||||
val transactionType = kryo.readClassAndObject(input) as TransactionType
|
||||
val timestamp = kryo.readClassAndObject(input) as Timestamp?
|
||||
|
||||
|
@ -6,9 +6,7 @@ import com.pholser.junit.quickcheck.generator.java.lang.StringGenerator
|
||||
import com.pholser.junit.quickcheck.generator.java.util.ArrayListGenerator
|
||||
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.entropyToKeyPair
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
@ -41,9 +39,15 @@ class PublicKeyGenerator: Generator<PublicKey>(PublicKey::class.java) {
|
||||
}
|
||||
}
|
||||
|
||||
class PublicKeyTreeGenerator : Generator<PublicKeyTree>(PublicKeyTree::class.java) {
|
||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): PublicKeyTree {
|
||||
return entropyToKeyPair(random.nextBigInteger(32)).public.tree
|
||||
}
|
||||
}
|
||||
|
||||
class PartyGenerator: Generator<Party>(Party::class.java) {
|
||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Party {
|
||||
return Party(StringGenerator().generate(random, status), PublicKeyGenerator().generate(random, status))
|
||||
return Party(StringGenerator().generate(random, status), PublicKeyTreeGenerator().generate(random, status))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ package net.corda.core.transactions
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.Party
|
||||
import java.security.PublicKey
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -25,7 +25,7 @@ abstract class BaseTransaction(
|
||||
* transaction until the transaction is verified by using [LedgerTransaction.verify]. It includes the
|
||||
* notary key, if the notary field is set.
|
||||
*/
|
||||
val mustSign: List<PublicKey>,
|
||||
val mustSign: List<PublicKeyTree>,
|
||||
/**
|
||||
* Pointer to a class that defines the behaviour of this transaction: either normal, or "notary changing".
|
||||
*/
|
||||
|
@ -2,8 +2,8 @@ package net.corda.core.transactions
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* A LedgerTransaction is derived from a [WireTransaction]. It is the result of doing the following operations:
|
||||
@ -27,7 +27,7 @@ class LedgerTransaction(
|
||||
/** The hash of the original serialised WireTransaction. */
|
||||
override val id: SecureHash,
|
||||
notary: Party?,
|
||||
signers: List<PublicKey>,
|
||||
signers: List<PublicKeyTree>,
|
||||
timestamp: Timestamp?,
|
||||
type: TransactionType
|
||||
) : BaseTransaction(inputs, outputs, notary, signers, type, timestamp) {
|
||||
|
@ -3,12 +3,11 @@ package net.corda.core.transactions
|
||||
import net.corda.core.contracts.NamedByHash
|
||||
import net.corda.core.contracts.TransactionResolutionException
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.toStringsShort
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import java.io.FileNotFoundException
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.util.*
|
||||
|
||||
@ -34,9 +33,9 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
/** Lazily calculated access to the deserialised/hashed transaction data. */
|
||||
val tx: WireTransaction by lazy { WireTransaction.deserialize(txBits) }
|
||||
|
||||
class SignaturesMissingException(val missing: Set<PublicKey>, val descriptions: List<String>, override val id: SecureHash) : NamedByHash, SignatureException() {
|
||||
class SignaturesMissingException(val missing: Set<PublicKeyTree>, val descriptions: List<String>, override val id: SecureHash) : NamedByHash, SignatureException() {
|
||||
override fun toString(): String {
|
||||
return "Missing signatures for $descriptions on transaction ${id.prefixChars()} for ${missing.toStringsShort()}"
|
||||
return "Missing signatures for $descriptions on transaction ${id.prefixChars()} for ${missing.joinToString()}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +52,7 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
* @throws SignaturesMissingException if any signatures should have been present but were not.
|
||||
*/
|
||||
@Throws(SignatureException::class)
|
||||
fun verifySignatures(vararg allowedToBeMissing: PublicKey): WireTransaction {
|
||||
fun verifySignatures(vararg allowedToBeMissing: PublicKeyTree): WireTransaction {
|
||||
// Embedded WireTransaction is not deserialised until after we check the signatures.
|
||||
checkSignaturesAreValid()
|
||||
|
||||
@ -83,19 +82,17 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMissingSignatures(): Set<PublicKey> {
|
||||
val requiredKeys = tx.mustSign.toSet()
|
||||
private fun getMissingSignatures(): Set<PublicKeyTree> {
|
||||
val sigKeys = sigs.map { it.by }.toSet()
|
||||
|
||||
if (sigKeys.containsAll(requiredKeys)) return emptySet()
|
||||
return requiredKeys - sigKeys
|
||||
val missing = tx.mustSign.filter { !it.isFulfilledBy(sigKeys) }.toSet()
|
||||
return missing
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<PublicKey>): ArrayList<String> {
|
||||
private fun getMissingKeyDescriptions(missing: Set<PublicKeyTree>): ArrayList<String> {
|
||||
// TODO: We need a much better way of structuring this data
|
||||
val missingElements = ArrayList<String>()
|
||||
this.tx.commands.forEach { command ->
|
||||
|
@ -3,11 +3,7 @@ package net.corda.core.transactions
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.crypto.*
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
@ -35,7 +31,7 @@ open class TransactionBuilder(
|
||||
protected val attachments: MutableList<SecureHash> = arrayListOf(),
|
||||
protected val outputs: MutableList<TransactionState<ContractState>> = arrayListOf(),
|
||||
protected val commands: MutableList<Command> = arrayListOf(),
|
||||
protected val signers: MutableSet<PublicKey> = mutableSetOf(),
|
||||
protected val signers: MutableSet<PublicKeyTree> = mutableSetOf(),
|
||||
protected var timestamp: Timestamp? = null) {
|
||||
|
||||
val time: Timestamp? get() = timestamp
|
||||
@ -124,7 +120,7 @@ open class TransactionBuilder(
|
||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||
*/
|
||||
fun checkSignature(sig: DigitalSignature.WithKey) {
|
||||
require(commands.any { it.signers.contains(sig.by) }) { "Signature key doesn't match any command" }
|
||||
require(commands.any { it.signers.any { sig.by in it.keys } }) { "Signature key doesn't match any command" }
|
||||
sig.verifyWithECDSA(toWireTransaction().id)
|
||||
}
|
||||
|
||||
@ -140,9 +136,9 @@ open class TransactionBuilder(
|
||||
fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction {
|
||||
if (checkSufficientSignatures) {
|
||||
val gotKeys = currentSigs.map { it.by }.toSet()
|
||||
val missing: Set<PublicKey> = signers - gotKeys
|
||||
val missing: Set<PublicKeyTree> = signers.filter { !it.isFulfilledBy(gotKeys) }.toSet()
|
||||
if (missing.isNotEmpty())
|
||||
throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.toStringsShort()}")
|
||||
throw IllegalStateException("Missing signatures on the transaction for the public keys: ${missing.joinToString()}")
|
||||
}
|
||||
val wtx = toWireTransaction()
|
||||
return SignedTransaction(wtx.serialize(), ArrayList(currentSigs), wtx.id)
|
||||
@ -182,8 +178,8 @@ open class TransactionBuilder(
|
||||
commands.add(arg)
|
||||
}
|
||||
|
||||
fun addCommand(data: CommandData, vararg keys: PublicKey) = addCommand(Command(data, listOf(*keys)))
|
||||
fun addCommand(data: CommandData, keys: List<PublicKey>) = addCommand(Command(data, keys))
|
||||
fun addCommand(data: CommandData, vararg keys: PublicKeyTree) = addCommand(Command(data, listOf(*keys)))
|
||||
fun addCommand(data: CommandData, keys: List<PublicKeyTree>) = addCommand(Command(data, keys))
|
||||
|
||||
// Accessors that yield immutable snapshots.
|
||||
fun inputStates(): List<StateRef> = ArrayList(inputs)
|
||||
|
@ -3,6 +3,7 @@ package net.corda.core.transactions
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.indexOfOrThrow
|
||||
import net.corda.core.node.ServiceHub
|
||||
@ -29,7 +30,7 @@ class WireTransaction(
|
||||
/** Ordered list of ([CommandData], [PublicKey]) pairs that instruct the contracts what to do. */
|
||||
val commands: List<Command>,
|
||||
notary: Party?,
|
||||
signers: List<PublicKey>,
|
||||
signers: List<PublicKeyTree>,
|
||||
type: TransactionType,
|
||||
timestamp: Timestamp?
|
||||
) : BaseTransaction(inputs, outputs, notary, signers, type, timestamp) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.core.utilities
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.parsePublicKeyBase58
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.node.ServiceHub
|
||||
import javax.ws.rs.core.Response
|
||||
|
||||
@ -17,7 +17,7 @@ class ApiUtils(val services: ServiceHub) {
|
||||
*/
|
||||
fun withParty(partyKeyStr: String, notFound: (String) -> Response = defaultNotFound, found: (Party) -> Response): Response {
|
||||
return try {
|
||||
val partyKey = parsePublicKeyBase58(partyKeyStr)
|
||||
val partyKey = PublicKeyTree.parseFromBase58(partyKeyStr)
|
||||
val party = services.identityService.partyFromKey(partyKey)
|
||||
if(party == null) notFound("Unknown party") else found(party)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
|
@ -2,20 +2,15 @@
|
||||
package net.corda.core.utilities
|
||||
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.DummyPublicKey
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.entropyToKeyPair
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
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: PublicKey get() = DummyPublicKey("x1")
|
||||
val DUMMY_PUBKEY_2: PublicKey get() = DummyPublicKey("x2")
|
||||
val DUMMY_PUBKEY_1: PublicKeyTree get() = DummyPublicKey("x1").tree
|
||||
val DUMMY_PUBKEY_2: PublicKeyTree get() = DummyPublicKey("x2").tree
|
||||
|
||||
val DUMMY_KEY_1: KeyPair by lazy { generateKeyPair() }
|
||||
val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() }
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.node.recordTransactions
|
||||
import net.corda.core.protocols.ProtocolLogic
|
||||
@ -15,7 +16,6 @@ import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import net.corda.protocols.AbstractStateReplacementProtocol.Acceptor
|
||||
import net.corda.protocols.AbstractStateReplacementProtocol.Instigator
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state.
|
||||
@ -67,10 +67,10 @@ abstract class AbstractStateReplacementProtocol<T> {
|
||||
}
|
||||
|
||||
abstract protected fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal<T>
|
||||
abstract protected fun assembleTx(): Pair<SignedTransaction, List<PublicKey>>
|
||||
abstract protected fun assembleTx(): Pair<SignedTransaction, List<PublicKeyTree>>
|
||||
|
||||
@Suspendable
|
||||
private fun collectSignatures(participants: List<PublicKey>, stx: SignedTransaction): List<DigitalSignature.WithKey> {
|
||||
private fun collectSignatures(participants: List<PublicKeyTree>, stx: SignedTransaction): List<DigitalSignature.WithKey> {
|
||||
val parties = participants.map {
|
||||
val participantNode = serviceHub.networkMapCache.getNodeByPublicKey(it) ?:
|
||||
throw IllegalStateException("Participant $it to state $originalState not found on the network")
|
||||
@ -95,7 +95,7 @@ abstract class AbstractStateReplacementProtocol<T> {
|
||||
val participantSignature = response.unwrap {
|
||||
if (it.sig == null) throw StateReplacementException(it.error!!)
|
||||
else {
|
||||
check(it.sig.by == party.owningKey) { "Not signed by the required participant" }
|
||||
check(party.owningKey.isFulfilledBy(it.sig.by)) { "Not signed by the required participant" }
|
||||
it.sig.verifyWithECDSA(stx.id)
|
||||
it.sig
|
||||
}
|
||||
|
@ -50,5 +50,9 @@ class FinalityProtocol(val transaction: SignedTransaction,
|
||||
}
|
||||
|
||||
private fun needsNotarySignature(stx: SignedTransaction) = stx.tx.notary != null && hasNoNotarySignature(stx)
|
||||
private fun hasNoNotarySignature(stx: SignedTransaction) = stx.tx.notary?.owningKey !in stx.sigs.map { it.by }
|
||||
private fun hasNoNotarySignature(stx: SignedTransaction): Boolean {
|
||||
val notaryKey = stx.tx.notary?.owningKey
|
||||
val signers = stx.sigs.map { it.by }.toSet()
|
||||
return !(notaryKey?.isFulfilledBy(signers) ?: false)
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import net.corda.protocols.NotaryChangeProtocol.Acceptor
|
||||
import net.corda.protocols.NotaryChangeProtocol.Instigator
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* A protocol to be used for changing a state's Notary. This is required since all input states to a transaction
|
||||
@ -36,7 +36,7 @@ object NotaryChangeProtocol: AbstractStateReplacementProtocol<Party>() {
|
||||
override fun assembleProposal(stateRef: StateRef, modification: Party, stx: SignedTransaction): AbstractStateReplacementProtocol.Proposal<Party>
|
||||
= Proposal(stateRef, modification, stx)
|
||||
|
||||
override fun assembleTx(): Pair<SignedTransaction, List<PublicKey>> {
|
||||
override fun assembleTx(): Pair<SignedTransaction, List<PublicKeyTree>> {
|
||||
val state = originalState.state
|
||||
val newState = state.withNotary(modification)
|
||||
val participants = state.data.participants
|
||||
|
@ -1,21 +1,16 @@
|
||||
package net.corda.protocols
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
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.node.services.TimestampChecker
|
||||
import net.corda.core.node.services.UniquenessException
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.core.protocols.ProtocolLogic
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import java.security.PublicKey
|
||||
|
||||
object NotaryProtocol {
|
||||
|
||||
@ -177,5 +172,5 @@ sealed class NotaryError {
|
||||
|
||||
class TransactionInvalid : NotaryError()
|
||||
|
||||
class SignaturesMissing(val missingSigners: Set<PublicKey>) : NotaryError()
|
||||
class SignaturesMissing(val missingSigners: Set<PublicKeyTree>) : NotaryError()
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package net.corda.protocols
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.TransientProperty
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.DealState
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.recordTransactions
|
||||
import net.corda.core.node.services.ServiceType
|
||||
@ -17,9 +16,7 @@ import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import net.corda.core.utilities.trace
|
||||
import java.math.BigDecimal
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* Classes for manipulating a two party deal or agreement.
|
||||
@ -42,7 +39,7 @@ object TwoPartyDealProtocol {
|
||||
}
|
||||
|
||||
// This object is serialised to the network and is the first protocol message the seller sends to the buyer.
|
||||
data class Handshake<out T>(val payload: T, val publicKey: PublicKey)
|
||||
data class Handshake<out T>(val payload: T, val publicKey: PublicKeyTree)
|
||||
|
||||
class SignaturesFromPrimary(val sellerSig: DigitalSignature.WithKey, val notarySig: DigitalSignature.LegallyIdentifiable)
|
||||
|
||||
@ -90,7 +87,7 @@ object TwoPartyDealProtocol {
|
||||
progressTracker.currentStep = AWAITING_PROPOSAL
|
||||
|
||||
// Make the first message we'll send to kick off the protocol.
|
||||
val hello = Handshake(payload, myKeyPair.public)
|
||||
val hello = Handshake(payload, myKeyPair.public.tree)
|
||||
val maybeSTX = sendAndReceive<SignedTransaction>(otherParty, hello)
|
||||
|
||||
return maybeSTX
|
||||
@ -104,7 +101,7 @@ object TwoPartyDealProtocol {
|
||||
progressTracker.nextStep()
|
||||
|
||||
// Check that the tx proposed by the buyer is valid.
|
||||
val wtx: WireTransaction = stx.verifySignatures(myKeyPair.public, notaryNode.notaryIdentity.owningKey)
|
||||
val wtx: WireTransaction = stx.verifySignatures(myKeyPair.public.tree, notaryNode.notaryIdentity.owningKey)
|
||||
logger.trace { "Received partially signed transaction: ${stx.id}" }
|
||||
|
||||
checkDependencies(stx)
|
||||
@ -251,18 +248,18 @@ object TwoPartyDealProtocol {
|
||||
return sendAndReceive<SignaturesFromPrimary>(otherParty, stx).unwrap { it }
|
||||
}
|
||||
|
||||
private fun signWithOurKeys(signingPubKeys: List<PublicKey>, ptx: TransactionBuilder): SignedTransaction {
|
||||
private fun signWithOurKeys(signingPubKeys: List<PublicKeyTree>, ptx: TransactionBuilder): SignedTransaction {
|
||||
// Now sign the transaction with whatever keys we need to move the cash.
|
||||
for (k in signingPubKeys) {
|
||||
val priv = serviceHub.keyManagementService.toPrivate(k)
|
||||
ptx.signWith(KeyPair(k, priv))
|
||||
for (publicKey in signingPubKeys.keys) {
|
||||
val privateKey = serviceHub.keyManagementService.toPrivate(publicKey)
|
||||
ptx.signWith(KeyPair(publicKey, privateKey))
|
||||
}
|
||||
|
||||
return ptx.toSignedTransaction(checkSufficientSignatures = false)
|
||||
}
|
||||
|
||||
@Suspendable protected abstract fun validateHandshake(handshake: Handshake<U>): Handshake<U>
|
||||
@Suspendable protected abstract fun assembleSharedTX(handshake: Handshake<U>): Pair<TransactionBuilder, List<PublicKey>>
|
||||
@Suspendable protected abstract fun assembleSharedTX(handshake: Handshake<U>): Pair<TransactionBuilder, List<PublicKeyTree>>
|
||||
}
|
||||
|
||||
|
||||
@ -295,7 +292,7 @@ object TwoPartyDealProtocol {
|
||||
return handshake.copy(payload = autoOffer.copy(dealBeingOffered = deal))
|
||||
}
|
||||
|
||||
override fun assembleSharedTX(handshake: Handshake<AutoOffer>): Pair<TransactionBuilder, List<PublicKey>> {
|
||||
override fun assembleSharedTX(handshake: Handshake<AutoOffer>): Pair<TransactionBuilder, List<PublicKeyTree>> {
|
||||
val deal = handshake.payload.dealBeingOffered
|
||||
val ptx = deal.generateAgreement(handshake.payload.notary)
|
||||
|
||||
|
Binary file not shown.
@ -1,12 +1,14 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.utilities.DUMMY_PUBKEY_1
|
||||
import net.corda.core.utilities.DUMMY_PUBKEY_2
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.ledger
|
||||
import net.corda.testing.transaction
|
||||
import org.junit.Test
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
@ -42,7 +44,7 @@ class TransactionEncumbranceTests {
|
||||
data class State(
|
||||
val validFrom: Instant
|
||||
) : ContractState {
|
||||
override val participants: List<PublicKey> = emptyList()
|
||||
override val participants: List<PublicKeyTree> = emptyList()
|
||||
override val contract: Contract = TEST_TIMELOCK_ID
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
package net.corda.core.contracts
|
||||
|
||||
import net.corda.core.crypto.newSecureRandom
|
||||
import net.corda.core.crypto.tree
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import net.corda.testing.node.MockTransactionStorage
|
||||
import net.corda.testing.MEGA_CORP_KEY
|
||||
import net.corda.testing.node.MockTransactionStorage
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
import kotlin.test.assertEquals
|
||||
@ -31,7 +32,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)
|
||||
addCommand(command, signer.public.tree)
|
||||
signWith(signer)
|
||||
signWith(DUMMY_NOTARY_KEY)
|
||||
}.toSignedTransaction(false)
|
||||
|
@ -4,6 +4,7 @@ import net.corda.contracts.asset.DUMMY_CASH_ISSUER_KEY
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.signWithECDSA
|
||||
import net.corda.core.crypto.tree
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -29,7 +30,7 @@ class TransactionTests {
|
||||
outputs = emptyList(),
|
||||
commands = emptyList(),
|
||||
notary = DUMMY_NOTARY,
|
||||
signers = listOf(DUMMY_KEY_1.public, DUMMY_KEY_2.public),
|
||||
signers = listOf(DUMMY_KEY_1.public.tree, DUMMY_KEY_2.public.tree),
|
||||
type = TransactionType.General(),
|
||||
timestamp = null
|
||||
)
|
||||
@ -38,20 +39,20 @@ class TransactionTests {
|
||||
assertFailsWith<IllegalArgumentException> { make().verifySignatures() }
|
||||
|
||||
assertEquals(
|
||||
setOf(DUMMY_KEY_1.public),
|
||||
setOf(DUMMY_KEY_1.public.tree),
|
||||
assertFailsWith<SignedTransaction.SignaturesMissingException> { make(DUMMY_KEY_2).verifySignatures() }.missing
|
||||
)
|
||||
assertEquals(
|
||||
setOf(DUMMY_KEY_2.public),
|
||||
setOf(DUMMY_KEY_2.public.tree),
|
||||
assertFailsWith<SignedTransaction.SignaturesMissingException> { make(DUMMY_KEY_1).verifySignatures() }.missing
|
||||
)
|
||||
assertEquals(
|
||||
setOf(DUMMY_KEY_2.public),
|
||||
assertFailsWith<SignedTransaction.SignaturesMissingException> { make(DUMMY_CASH_ISSUER_KEY).verifySignatures(DUMMY_KEY_1.public) }.missing
|
||||
setOf(DUMMY_KEY_2.public.tree),
|
||||
assertFailsWith<SignedTransaction.SignaturesMissingException> { make(DUMMY_CASH_ISSUER_KEY).verifySignatures(DUMMY_KEY_1.public.tree) }.missing
|
||||
)
|
||||
|
||||
make(DUMMY_KEY_1).verifySignatures(DUMMY_KEY_2.public)
|
||||
make(DUMMY_KEY_2).verifySignatures(DUMMY_KEY_1.public)
|
||||
make(DUMMY_KEY_1).verifySignatures(DUMMY_KEY_2.public.tree)
|
||||
make(DUMMY_KEY_2).verifySignatures(DUMMY_KEY_1.public.tree)
|
||||
|
||||
make(DUMMY_KEY_1, DUMMY_KEY_2).verifySignatures()
|
||||
}
|
||||
@ -64,7 +65,7 @@ class TransactionTests {
|
||||
val commands = emptyList<AuthenticatedObject<CommandData>>()
|
||||
val attachments = emptyList<Attachment>()
|
||||
val id = SecureHash.randomSHA256()
|
||||
val signers = listOf(DUMMY_NOTARY_KEY.public)
|
||||
val signers = listOf(DUMMY_NOTARY_KEY.public.tree)
|
||||
val timestamp: Timestamp? = null
|
||||
val transaction: LedgerTransaction = LedgerTransaction(
|
||||
inputs,
|
||||
@ -91,7 +92,7 @@ class TransactionTests {
|
||||
val commands = emptyList<AuthenticatedObject<CommandData>>()
|
||||
val attachments = emptyList<Attachment>()
|
||||
val id = SecureHash.randomSHA256()
|
||||
val signers = listOf(DUMMY_NOTARY_KEY.public)
|
||||
val signers = listOf(DUMMY_NOTARY_KEY.public.tree)
|
||||
val timestamp: Timestamp? = null
|
||||
val transaction: LedgerTransaction = LedgerTransaction(
|
||||
inputs,
|
||||
|
@ -2,6 +2,7 @@ package net.corda.core.node
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.core.serialization.*
|
||||
@ -15,7 +16,6 @@ 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
|
||||
@ -37,7 +37,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<PublicKey>
|
||||
override val participants: List<PublicKeyTree>
|
||||
get() = listOf()
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.corda.core.node
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
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<PublicKey>
|
||||
override val participants: List<PublicKeyTree>
|
||||
get() = emptyList()
|
||||
override val contract = VaultUpdateTests.DummyContract
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.corda.core.serialization
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.tree
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.*
|
||||
@ -9,7 +11,6 @@ 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
|
||||
@ -27,12 +28,12 @@ class TransactionSerializationTests {
|
||||
data class State(
|
||||
val deposit: PartyAndReference,
|
||||
val amount: Amount<Currency>,
|
||||
override val owner: PublicKey) : OwnableState {
|
||||
override val owner: PublicKeyTree) : OwnableState {
|
||||
override val contract: Contract = TEST_PROGRAM_ID
|
||||
override val participants: List<PublicKey>
|
||||
override val participants: List<PublicKeyTree>
|
||||
get() = listOf(owner)
|
||||
|
||||
override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner))
|
||||
override fun withNewOwner(newOwner: PublicKeyTree) = Pair(Commands.Move(), copy(owner = newOwner))
|
||||
}
|
||||
interface Commands : CommandData {
|
||||
class Move() : TypeOnlyCommandData(), Commands
|
||||
@ -45,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), DUMMY_NOTARY)
|
||||
val changeState = TransactionState(TestCash.State(depositRef, 400.POUNDS, DUMMY_KEY_1.public.tree), DUMMY_NOTARY)
|
||||
|
||||
|
||||
lateinit var tx: TransactionBuilder
|
||||
@ -53,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))
|
||||
inputState, outputState, changeState, Command(TestCash.Commands.Move(), arrayListOf(DUMMY_KEY_1.public.tree))
|
||||
)
|
||||
}
|
||||
|
||||
@ -92,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))
|
||||
Command(TestCash.Commands.Move(), DUMMY_KEY_2.public.tree))
|
||||
tx2.signWith(DUMMY_NOTARY_KEY)
|
||||
tx2.signWith(DUMMY_KEY_2)
|
||||
|
||||
|
Reference in New Issue
Block a user