mirror of
https://github.com/corda/corda.git
synced 2025-01-29 15:43:55 +00:00
Move notary service related classes and interfaces in core to interna… (#2827)
* Move notary service related classes and interfaces in core to internal, since we won't be able to stabilise the APIs for writing custom notary services any time soon (the docs already mention it). I left out the wire protocol related classes so we don't accidentally break it.
This commit is contained in:
parent
514287e694
commit
3bf1e803d9
@ -1369,7 +1369,6 @@ public @interface net.corda.core.flows.InitiatingFlow
|
||||
public <init>(List, net.corda.core.crypto.SecureHash)
|
||||
@org.jetbrains.annotations.NotNull public final List getStatesToConsume()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getTransactionId()
|
||||
public final void verifySignature(net.corda.core.flows.NotarisationRequestSignature, net.corda.core.identity.Party)
|
||||
public static final net.corda.core.flows.NotarisationRequest$Companion Companion
|
||||
##
|
||||
public static final class net.corda.core.flows.NotarisationRequest$Companion extends java.lang.Object
|
||||
@ -1483,18 +1482,6 @@ public static final class net.corda.core.flows.NotaryFlow$Client$Companion exten
|
||||
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.flows.NotaryFlow$Client$Companion$VALIDATING extends net.corda.core.utilities.ProgressTracker$Step
|
||||
public static final net.corda.core.flows.NotaryFlow$Client$Companion$VALIDATING INSTANCE
|
||||
##
|
||||
public abstract static class net.corda.core.flows.NotaryFlow$Service extends net.corda.core.flows.FlowLogic
|
||||
public <init>(net.corda.core.flows.FlowSession, net.corda.core.node.services.TrustedAuthorityNotaryService)
|
||||
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.Nullable public Void call()
|
||||
@co.paralleluniverse.fibers.Suspendable protected final void checkNotary(net.corda.core.identity.Party)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.FlowSession getOtherSideSession()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.node.services.TrustedAuthorityNotaryService getService()
|
||||
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.NotNull protected abstract net.corda.core.flows.TransactionParts validateRequest(net.corda.core.flows.NotarisationPayload)
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.flows.NotaryInternalException extends net.corda.core.flows.FlowException
|
||||
public <init>(net.corda.core.flows.NotaryError)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.NotaryError getError()
|
||||
##
|
||||
public final class net.corda.core.flows.ReceiveStateAndRefFlow extends net.corda.core.flows.FlowLogic
|
||||
public <init>(net.corda.core.flows.FlowSession)
|
||||
@co.paralleluniverse.fibers.Suspendable @org.jetbrains.annotations.NotNull public List call()
|
||||
@ -1574,21 +1561,6 @@ public static final class net.corda.core.flows.StateMachineRunId$Companion exten
|
||||
public <init>(String)
|
||||
public <init>(String, Throwable)
|
||||
##
|
||||
public final class net.corda.core.flows.TransactionParts extends java.lang.Object
|
||||
public <init>(net.corda.core.crypto.SecureHash, List, net.corda.core.contracts.TimeWindow, net.corda.core.identity.Party)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash component1()
|
||||
@org.jetbrains.annotations.NotNull public final List component2()
|
||||
@org.jetbrains.annotations.Nullable public final net.corda.core.contracts.TimeWindow component3()
|
||||
@org.jetbrains.annotations.Nullable public final net.corda.core.identity.Party component4()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.TransactionParts copy(net.corda.core.crypto.SecureHash, List, net.corda.core.contracts.TimeWindow, net.corda.core.identity.Party)
|
||||
public boolean equals(Object)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getId()
|
||||
@org.jetbrains.annotations.NotNull public final List getInputs()
|
||||
@org.jetbrains.annotations.Nullable public final net.corda.core.identity.Party getNotary()
|
||||
@org.jetbrains.annotations.Nullable public final net.corda.core.contracts.TimeWindow getTimestamp()
|
||||
public int hashCode()
|
||||
public String toString()
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.flows.UnexpectedFlowEndException extends net.corda.core.CordaRuntimeException implements net.corda.core.flows.IdentifiableException
|
||||
public <init>(String)
|
||||
public <init>(String, Throwable)
|
||||
@ -2052,21 +2024,6 @@ public @interface net.corda.core.node.services.CordaService
|
||||
public abstract boolean isValidatingNotary(net.corda.core.identity.Party)
|
||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.messaging.DataFeed track()
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.node.services.NotaryService extends net.corda.core.serialization.SingletonSerializeAsToken
|
||||
public <init>()
|
||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.flows.FlowLogic createServiceFlow(net.corda.core.flows.FlowSession)
|
||||
@org.jetbrains.annotations.NotNull public abstract java.security.PublicKey getNotaryIdentityKey()
|
||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.node.ServiceHub getServices()
|
||||
public abstract void start()
|
||||
public abstract void stop()
|
||||
public static final void validateTimeWindow(java.time.Clock, net.corda.core.contracts.TimeWindow)
|
||||
public static final net.corda.core.node.services.NotaryService$Companion Companion
|
||||
@org.jetbrains.annotations.NotNull public static final String ID_PREFIX = "corda.notary."
|
||||
##
|
||||
public static final class net.corda.core.node.services.NotaryService$Companion extends java.lang.Object
|
||||
@kotlin.Deprecated @org.jetbrains.annotations.NotNull public final String constructId(boolean, boolean, boolean, boolean)
|
||||
public final void validateTimeWindow(java.time.Clock, net.corda.core.contracts.TimeWindow)
|
||||
##
|
||||
public abstract class net.corda.core.node.services.PartyInfo extends java.lang.Object
|
||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.identity.Party getParty()
|
||||
##
|
||||
@ -2110,48 +2067,6 @@ public final class net.corda.core.node.services.TimeWindowChecker extends java.l
|
||||
@net.corda.core.DoNotImplement public interface net.corda.core.node.services.TransactionVerifierService
|
||||
@org.jetbrains.annotations.NotNull public abstract net.corda.core.concurrent.CordaFuture verify(net.corda.core.transactions.LedgerTransaction)
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.node.services.TrustedAuthorityNotaryService extends net.corda.core.node.services.NotaryService
|
||||
public <init>()
|
||||
public final void commitInputStates(List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.flows.NotarisationRequestSignature, net.corda.core.contracts.TimeWindow)
|
||||
@org.jetbrains.annotations.NotNull protected org.slf4j.Logger getLog()
|
||||
@org.jetbrains.annotations.NotNull protected net.corda.core.node.services.TimeWindowChecker getTimeWindowChecker()
|
||||
@org.jetbrains.annotations.NotNull protected abstract net.corda.core.node.services.UniquenessProvider getUniquenessProvider()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.TransactionSignature sign(net.corda.core.crypto.SecureHash)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.DigitalSignature$WithKey sign(byte[])
|
||||
public final void validateTimeWindow(net.corda.core.contracts.TimeWindow)
|
||||
public static final net.corda.core.node.services.TrustedAuthorityNotaryService$Companion Companion
|
||||
##
|
||||
public static final class net.corda.core.node.services.TrustedAuthorityNotaryService$Companion extends java.lang.Object
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.node.services.UniquenessException extends net.corda.core.CordaException
|
||||
public <init>(net.corda.core.node.services.UniquenessProvider$Conflict)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.node.services.UniquenessProvider$Conflict getError()
|
||||
##
|
||||
public interface net.corda.core.node.services.UniquenessProvider
|
||||
public abstract void commit(List, net.corda.core.crypto.SecureHash, net.corda.core.identity.Party, net.corda.core.flows.NotarisationRequestSignature, net.corda.core.contracts.TimeWindow)
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.node.services.UniquenessProvider$Conflict extends java.lang.Object
|
||||
public <init>(Map)
|
||||
@org.jetbrains.annotations.NotNull public final Map component1()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.node.services.UniquenessProvider$Conflict copy(Map)
|
||||
public boolean equals(Object)
|
||||
@org.jetbrains.annotations.NotNull public final Map getStateHistory()
|
||||
public int hashCode()
|
||||
public String toString()
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.node.services.UniquenessProvider$ConsumingTx extends java.lang.Object
|
||||
public <init>(net.corda.core.crypto.SecureHash, int, net.corda.core.identity.Party)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash component1()
|
||||
public final int component2()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.Party component3()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.node.services.UniquenessProvider$ConsumingTx copy(net.corda.core.crypto.SecureHash, int, net.corda.core.identity.Party)
|
||||
public boolean equals(Object)
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.crypto.SecureHash getId()
|
||||
public final int getInputIndex()
|
||||
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.Party getRequestingParty()
|
||||
public int hashCode()
|
||||
public String toString()
|
||||
##
|
||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.node.services.UnknownAnonymousPartyException extends net.corda.core.CordaException
|
||||
public <init>(String)
|
||||
##
|
||||
|
73
core/src/main/kotlin/net/corda/core/flows/NotaryError.kt
Normal file
73
core/src/main/kotlin/net/corda/core/flows/NotaryError.kt
Normal file
@ -0,0 +1,73 @@
|
||||
package net.corda.core.flows
|
||||
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Exception thrown by the notary service if any issues are encountered while trying to commit a transaction. The
|
||||
* underlying [error] specifies the cause of failure.
|
||||
*/
|
||||
class NotaryException(
|
||||
/** Cause of notarisation failure. */
|
||||
val error: NotaryError,
|
||||
/** Id of the transaction to be notarised. Can be _null_ if an error occurred before the id could be resolved. */
|
||||
val txId: SecureHash? = null
|
||||
) : FlowException("Unable to notarise transaction${txId ?: " "}: $error")
|
||||
|
||||
/** Specifies the cause for notarisation request failure. */
|
||||
@CordaSerializable
|
||||
sealed class NotaryError {
|
||||
/** Occurs when one or more input states have already been consumed by another transaction. */
|
||||
data class Conflict(
|
||||
/** Id of the transaction that was attempted to be notarised. */
|
||||
val txId: SecureHash,
|
||||
/** Specifies which states have already been consumed in another transaction. */
|
||||
val consumedStates: Map<StateRef, StateConsumptionDetails>
|
||||
) : NotaryError() {
|
||||
override fun toString() = "One or more input states have been used in another transaction"
|
||||
}
|
||||
|
||||
/** Occurs when time specified in the [TimeWindow] command is outside the allowed tolerance. */
|
||||
data class TimeWindowInvalid(val currentTime: Instant, val txTimeWindow: TimeWindow) : NotaryError() {
|
||||
override fun toString() = "Current time $currentTime is outside the time bounds specified by the transaction: $txTimeWindow"
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
@Deprecated("Here only for binary compatibility purposes, do not use.")
|
||||
val INSTANCE = TimeWindowInvalid(Instant.EPOCH, TimeWindow.fromOnly(Instant.EPOCH))
|
||||
}
|
||||
}
|
||||
|
||||
/** Occurs when the provided transaction fails to verify. */
|
||||
data class TransactionInvalid(val cause: Throwable) : NotaryError() {
|
||||
override fun toString() = cause.toString()
|
||||
}
|
||||
|
||||
/** Occurs when the transaction sent for notarisation is assigned to a different notary identity. */
|
||||
object WrongNotary : NotaryError()
|
||||
|
||||
/** Occurs when the notarisation request signature does not verify for the provided transaction. */
|
||||
data class RequestSignatureInvalid(val cause: Throwable) : NotaryError() {
|
||||
override fun toString() = "Request signature invalid: $cause"
|
||||
}
|
||||
|
||||
/** Occurs when the notary service encounters an unexpected issue or becomes temporarily unavailable. */
|
||||
data class General(val cause: Throwable) : NotaryError() {
|
||||
override fun toString() = cause.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** Contains information about the consuming transaction for a particular state. */
|
||||
// TODO: include notary timestamp?
|
||||
@CordaSerializable
|
||||
data class StateConsumptionDetails(
|
||||
/**
|
||||
* Hash of the consuming transaction id.
|
||||
*
|
||||
* Note that this is NOT the transaction id itself – revealing it could lead to privacy leaks.
|
||||
*/
|
||||
val hashOfTransactionId: SecureHash
|
||||
)
|
@ -4,22 +4,17 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.DoNotImplement
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.FetchDataFlow
|
||||
import net.corda.core.internal.generateSignature
|
||||
import net.corda.core.internal.validateSignatures
|
||||
import net.corda.core.node.services.NotaryService
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.internal.notary.generateSignature
|
||||
import net.corda.core.internal.notary.validateSignatures
|
||||
import net.corda.core.transactions.ContractUpgradeWireTransaction
|
||||
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 net.corda.core.utilities.unwrap
|
||||
import java.time.Instant
|
||||
import java.util.function.Predicate
|
||||
|
||||
class NotaryFlow {
|
||||
@ -120,144 +115,4 @@ class NotaryFlow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow run by a notary service that handles notarisation requests.
|
||||
*
|
||||
* It checks that the time-window command is valid (if present) and commits the input state, or returns a conflict
|
||||
* if any of the input states have been previously committed.
|
||||
*
|
||||
* Additional transaction validation logic can be added when implementing [validateRequest].
|
||||
*/
|
||||
// See AbstractStateReplacementFlow.Acceptor for why it's Void?
|
||||
abstract class Service(val otherSideSession: FlowSession, val service: TrustedAuthorityNotaryService) : FlowLogic<Void?>() {
|
||||
companion object {
|
||||
// TODO: Determine an appropriate limit and also enforce in the network parameters and the transaction builder.
|
||||
private const val maxAllowedInputs = 10_000
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
override fun call(): Void? {
|
||||
check(serviceHub.myInfo.legalIdentities.any { serviceHub.networkMapCache.isNotary(it) }) {
|
||||
"We are not a notary on the network"
|
||||
}
|
||||
val requestPayload = otherSideSession.receive<NotarisationPayload>().unwrap { it }
|
||||
var txId: SecureHash? = null
|
||||
try {
|
||||
val parts = validateRequest(requestPayload)
|
||||
txId = parts.id
|
||||
checkNotary(parts.notary)
|
||||
service.commitInputStates(parts.inputs, txId, otherSideSession.counterparty, requestPayload.requestSignature, parts.timestamp)
|
||||
signTransactionAndSendResponse(txId)
|
||||
} catch (e: NotaryInternalException) {
|
||||
throw NotaryException(e.error, txId)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** Checks whether the number of input states is too large. */
|
||||
protected fun checkInputs(inputs: List<StateRef>) {
|
||||
if (inputs.size > maxAllowedInputs) {
|
||||
val error = NotaryError.TransactionInvalid(
|
||||
IllegalArgumentException("A transaction cannot have more than $maxAllowedInputs inputs, received: ${inputs.size}")
|
||||
)
|
||||
throw NotaryInternalException(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement custom logic to perform transaction verification based on validity and privacy requirements.
|
||||
*/
|
||||
@Suspendable
|
||||
protected abstract fun validateRequest(requestPayload: NotarisationPayload): TransactionParts
|
||||
|
||||
/** Check if transaction is intended to be signed by this notary. */
|
||||
@Suspendable
|
||||
protected fun checkNotary(notary: Party?) {
|
||||
if (notary?.owningKey != service.notaryIdentityKey) {
|
||||
throw NotaryInternalException(NotaryError.WrongNotary)
|
||||
}
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
private fun signTransactionAndSendResponse(txId: SecureHash) {
|
||||
val signature = service.sign(txId)
|
||||
otherSideSession.send(NotarisationResponse(listOf(signature)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum amount of information needed to notarise a transaction. Note that this does not include
|
||||
* any sensitive transaction details.
|
||||
*/
|
||||
data class TransactionParts(val id: SecureHash, val inputs: List<StateRef>, val timestamp: TimeWindow?, val notary: Party?)
|
||||
|
||||
/**
|
||||
* Exception thrown by the notary service if any issues are encountered while trying to commit a transaction. The
|
||||
* underlying [error] specifies the cause of failure.
|
||||
*/
|
||||
class NotaryException(
|
||||
/** Cause of notarisation failure. */
|
||||
val error: NotaryError,
|
||||
/** Id of the transaction to be notarised. Can be _null_ if an error occurred before the id could be resolved. */
|
||||
val txId: SecureHash? = null
|
||||
) : FlowException("Unable to notarise transaction${txId ?: " "}: $error")
|
||||
|
||||
/** Exception internal to the notary service. Does not get exposed to CorDapps and flows calling [NotaryFlow.Client]. */
|
||||
class NotaryInternalException(val error: NotaryError) : FlowException("Unable to notarise: $error")
|
||||
|
||||
/** Specifies the cause for notarisation request failure. */
|
||||
@CordaSerializable
|
||||
sealed class NotaryError {
|
||||
/** Occurs when one or more input states have already been consumed by another transaction. */
|
||||
data class Conflict(
|
||||
/** Id of the transaction that was attempted to be notarised. */
|
||||
val txId: SecureHash,
|
||||
/** Specifies which states have already been consumed in another transaction. */
|
||||
val consumedStates: Map<StateRef, StateConsumptionDetails>
|
||||
) : NotaryError() {
|
||||
override fun toString() = "One or more input states have been used in another transaction"
|
||||
}
|
||||
|
||||
/** Occurs when time specified in the [TimeWindow] command is outside the allowed tolerance. */
|
||||
data class TimeWindowInvalid(val currentTime: Instant, val txTimeWindow: TimeWindow) : NotaryError() {
|
||||
override fun toString() = "Current time $currentTime is outside the time bounds specified by the transaction: $txTimeWindow"
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
@Deprecated("Here only for binary compatibility purposes, do not use.")
|
||||
val INSTANCE = TimeWindowInvalid(Instant.EPOCH, TimeWindow.fromOnly(Instant.EPOCH))
|
||||
}
|
||||
}
|
||||
|
||||
/** Occurs when the provided transaction fails to verify. */
|
||||
data class TransactionInvalid(val cause: Throwable) : NotaryError() {
|
||||
override fun toString() = cause.toString()
|
||||
}
|
||||
|
||||
/** Occurs when the transaction sent for notarisation is assigned to a different notary identity. */
|
||||
object WrongNotary : NotaryError()
|
||||
|
||||
/** Occurs when the notarisation request signature does not verify for the provided transaction. */
|
||||
data class RequestSignatureInvalid(val cause: Throwable) : NotaryError() {
|
||||
override fun toString() = "Request signature invalid: $cause"
|
||||
}
|
||||
|
||||
/** Occurs when the notary service encounters an unexpected issue or becomes temporarily unavailable. */
|
||||
data class General(val cause: Throwable) : NotaryError() {
|
||||
override fun toString() = cause.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** Contains information about the consuming transaction for a particular state. */
|
||||
// TODO: include notary timestamp?
|
||||
@CordaSerializable
|
||||
data class StateConsumptionDetails(
|
||||
/**
|
||||
* Hash of the consuming transaction id.
|
||||
*
|
||||
* Note that this is NOT the transaction id itself – revealing it could lead to privacy leaks.
|
||||
*/
|
||||
val hashOfTransactionId: SecureHash
|
||||
)
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
package net.corda.core.flows
|
||||
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.CoreTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.SignatureException
|
||||
|
||||
/**
|
||||
* A notarisation request specifies a list of states to consume and the id of the consuming transaction. Its primary
|
||||
@ -36,34 +34,6 @@ class NotarisationRequest(statesToConsume: List<StateRef>, val transactionId: Se
|
||||
|
||||
/** States this request specifies to be consumed. Sorted to ensure the serialized form does not get affected by the state order. */
|
||||
val statesToConsume: List<StateRef> get() = _statesToConsumeSorted // Getter required for AMQP serialization
|
||||
|
||||
/** Verifies the signature against this notarisation request. Checks that the signature is issued by the right party. */
|
||||
fun verifySignature(requestSignature: NotarisationRequestSignature, intendedSigner: Party) {
|
||||
val signature = requestSignature.digitalSignature
|
||||
if (intendedSigner.owningKey != signature.by) {
|
||||
val errorMessage = "Expected a signature by ${intendedSigner.owningKey}, but received by ${signature.by}}"
|
||||
throw NotaryInternalException(NotaryError.RequestSignatureInvalid(IllegalArgumentException(errorMessage)))
|
||||
}
|
||||
// TODO: if requestSignature was generated over an old version of NotarisationRequest, we need to be able to
|
||||
// reserialize it in that version to get the exact same bytes. Modify the serialization logic once that's
|
||||
// available.
|
||||
val expectedSignedBytes = this.serialize().bytes
|
||||
verifyCorrectBytesSigned(signature, expectedSignedBytes)
|
||||
}
|
||||
|
||||
private fun verifyCorrectBytesSigned(signature: DigitalSignature.WithKey, bytes: ByteArray) {
|
||||
try {
|
||||
signature.verify(bytes)
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is InvalidKeyException, is SignatureException -> {
|
||||
val error = NotaryError.RequestSignatureInvalid(e)
|
||||
throw NotaryInternalException(error)
|
||||
}
|
||||
else -> throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
@ -8,11 +8,7 @@ import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.cordapp.CordappConfig
|
||||
import net.corda.core.cordapp.CordappContext
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.NotarisationRequest
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
@ -412,22 +408,6 @@ fun createCordappContext(cordapp: Cordapp, attachmentId: SecureHash?, classLoade
|
||||
return CordappContext(cordapp, attachmentId, classLoader, config)
|
||||
}
|
||||
|
||||
/** Verifies that the correct notarisation request was signed by the counterparty. */
|
||||
fun NotaryFlow.Service.validateRequestSignature(request: NotarisationRequest, signature: NotarisationRequestSignature) {
|
||||
val requestingParty = otherSideSession.counterparty
|
||||
request.verifySignature(signature, requestingParty)
|
||||
}
|
||||
|
||||
/** Creates a signature over the notarisation request using the legal identity key. */
|
||||
fun NotarisationRequest.generateSignature(serviceHub: ServiceHub): NotarisationRequestSignature {
|
||||
val serializedRequest = this.serialize().bytes
|
||||
val signature = with(serviceHub) {
|
||||
val myLegalIdentity = myInfo.legalIdentitiesAndCerts.first().owningKey
|
||||
keyManagementService.sign(serializedRequest, myLegalIdentity)
|
||||
}
|
||||
return NotarisationRequestSignature(signature, serviceHub.myInfo.platformVersion)
|
||||
}
|
||||
|
||||
val PublicKey.hash: SecureHash get() = encoded.sha256()
|
||||
|
||||
/**
|
||||
|
@ -1,36 +0,0 @@
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.flows.NotarisationResponse
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.flows.StateConsumptionDetails
|
||||
import net.corda.core.identity.Party
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Checks that there are sufficient signatures to satisfy the notary signing requirement and validates the signatures
|
||||
* against the given transaction id.
|
||||
*/
|
||||
fun NotarisationResponse.validateSignatures(txId: SecureHash, notary: Party) {
|
||||
val signingKeys = signatures.map { it.by }
|
||||
require(notary.owningKey.isFulfilledBy(signingKeys)) { "Insufficient signatures to fulfill the notary signing requirement for $notary" }
|
||||
signatures.forEach { it.verify(txId) }
|
||||
}
|
||||
|
||||
/** Checks if the provided states were used as inputs in the specified transaction. */
|
||||
fun isConsumedByTheSameTx(txIdHash: SecureHash, consumedStates: Map<StateRef, StateConsumptionDetails>): Boolean {
|
||||
val conflicts = consumedStates.filter { (_, cause) ->
|
||||
cause.hashOfTransactionId != txIdHash
|
||||
}
|
||||
return conflicts.isEmpty()
|
||||
}
|
||||
|
||||
/** Returns [NotaryError.TimeWindowInvalid] if [currentTime] is outside the [timeWindow], and *null* otherwise. */
|
||||
fun validateTimeWindow(currentTime: Instant, timeWindow: TimeWindow?): NotaryError.TimeWindowInvalid? {
|
||||
return if (timeWindow != null && currentTime !in timeWindow) {
|
||||
NotaryError.TimeWindowInvalid(currentTime, timeWindow)
|
||||
} else null
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.corda.core.internal.notary
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import java.security.PublicKey
|
||||
|
||||
abstract class NotaryService : SingletonSerializeAsToken() {
|
||||
abstract val services: ServiceHub
|
||||
abstract val notaryIdentityKey: PublicKey
|
||||
|
||||
abstract fun start()
|
||||
abstract fun stop()
|
||||
|
||||
/**
|
||||
* Produces a notary service flow which has the corresponding sends and receives as [NotaryFlow.Client].
|
||||
* @param otherPartySession client [Party] making the request
|
||||
*/
|
||||
abstract fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?>
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package net.corda.core.internal.notary
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.utilities.unwrap
|
||||
|
||||
/**
|
||||
* A flow run by a notary service that handles notarisation requests.
|
||||
*
|
||||
* It checks that the time-window command is valid (if present) and commits the input state, or returns a conflict
|
||||
* if any of the input states have been previously committed.
|
||||
*
|
||||
* Additional transaction validation logic can be added when implementing [validateRequest].
|
||||
*/
|
||||
// See AbstractStateReplacementFlow.Acceptor for why it's Void?
|
||||
abstract class NotaryServiceFlow(val otherSideSession: FlowSession, val service: TrustedAuthorityNotaryService) : FlowLogic<Void?>() {
|
||||
companion object {
|
||||
// TODO: Determine an appropriate limit and also enforce in the network parameters and the transaction builder.
|
||||
private const val maxAllowedInputs = 10_000
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
override fun call(): Void? {
|
||||
check(serviceHub.myInfo.legalIdentities.any { serviceHub.networkMapCache.isNotary(it) }) {
|
||||
"We are not a notary on the network"
|
||||
}
|
||||
val requestPayload = otherSideSession.receive<NotarisationPayload>().unwrap { it }
|
||||
var txId: SecureHash? = null
|
||||
try {
|
||||
val parts = validateRequest(requestPayload)
|
||||
txId = parts.id
|
||||
checkNotary(parts.notary)
|
||||
service.commitInputStates(parts.inputs, txId, otherSideSession.counterparty, requestPayload.requestSignature, parts.timestamp)
|
||||
signTransactionAndSendResponse(txId)
|
||||
} catch (e: NotaryInternalException) {
|
||||
throw NotaryException(e.error, txId)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** Checks whether the number of input states is too large. */
|
||||
protected fun checkInputs(inputs: List<StateRef>) {
|
||||
if (inputs.size > maxAllowedInputs) {
|
||||
val error = NotaryError.TransactionInvalid(
|
||||
IllegalArgumentException("A transaction cannot have more than $maxAllowedInputs inputs, received: ${inputs.size}")
|
||||
)
|
||||
throw NotaryInternalException(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement custom logic to perform transaction verification based on validity and privacy requirements.
|
||||
*/
|
||||
@Suspendable
|
||||
protected abstract fun validateRequest(requestPayload: NotarisationPayload): TransactionParts
|
||||
|
||||
/** Verifies that the correct notarisation request was signed by the counterparty. */
|
||||
protected fun validateRequestSignature(request: NotarisationRequest, signature: NotarisationRequestSignature) {
|
||||
val requestingParty = otherSideSession.counterparty
|
||||
request.verifySignature(signature, requestingParty)
|
||||
}
|
||||
|
||||
/** Check if transaction is intended to be signed by this notary. */
|
||||
@Suspendable
|
||||
protected fun checkNotary(notary: Party?) {
|
||||
if (notary?.owningKey != service.notaryIdentityKey) {
|
||||
throw NotaryInternalException(NotaryError.WrongNotary)
|
||||
}
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
private fun signTransactionAndSendResponse(txId: SecureHash) {
|
||||
val signature = service.sign(txId)
|
||||
otherSideSession.send(NotarisationResponse(listOf(signature)))
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum amount of information needed to notarise a transaction. Note that this does not include
|
||||
* any sensitive transaction details.
|
||||
*/
|
||||
protected data class TransactionParts(val id: SecureHash, val inputs: List<StateRef>, val timestamp: TimeWindow?, val notary: Party?)
|
||||
}
|
||||
|
||||
/** Exception internal to the notary service. Does not get exposed to CorDapps and flows calling [NotaryFlow.Client]. */
|
||||
class NotaryInternalException(val error: NotaryError) : FlowException("Unable to notarise: $error")
|
@ -0,0 +1,77 @@
|
||||
package net.corda.core.internal.notary
|
||||
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.serialize
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.SignatureException
|
||||
import java.time.Instant
|
||||
|
||||
/** Verifies the signature against this notarisation request. Checks that the signature is issued by the right party. */
|
||||
fun NotarisationRequest.verifySignature(requestSignature: NotarisationRequestSignature, intendedSigner: Party) {
|
||||
val signature = requestSignature.digitalSignature
|
||||
if (intendedSigner.owningKey != signature.by) {
|
||||
val errorMessage = "Expected a signature by ${intendedSigner.owningKey}, but received by ${signature.by}}"
|
||||
throw NotaryInternalException(NotaryError.RequestSignatureInvalid(IllegalArgumentException(errorMessage)))
|
||||
}
|
||||
// TODO: if requestSignature was generated over an old version of NotarisationRequest, we need to be able to
|
||||
// reserialize it in that version to get the exact same bytes. Modify the serialization logic once that's
|
||||
// available.
|
||||
val expectedSignedBytes = this.serialize().bytes
|
||||
verifyCorrectBytesSigned(signature, expectedSignedBytes)
|
||||
}
|
||||
|
||||
private fun verifyCorrectBytesSigned(signature: DigitalSignature.WithKey, bytes: ByteArray) {
|
||||
try {
|
||||
signature.verify(bytes)
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is InvalidKeyException, is SignatureException -> {
|
||||
val error = NotaryError.RequestSignatureInvalid(e)
|
||||
throw NotaryInternalException(error)
|
||||
}
|
||||
else -> throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that there are sufficient signatures to satisfy the notary signing requirement and validates the signatures
|
||||
* against the given transaction id.
|
||||
*/
|
||||
fun NotarisationResponse.validateSignatures(txId: SecureHash, notary: Party) {
|
||||
val signingKeys = signatures.map { it.by }
|
||||
require(notary.owningKey.isFulfilledBy(signingKeys)) { "Insufficient signatures to fulfill the notary signing requirement for $notary" }
|
||||
signatures.forEach { it.verify(txId) }
|
||||
}
|
||||
|
||||
/** Creates a signature over the notarisation request using the legal identity key. */
|
||||
fun NotarisationRequest.generateSignature(serviceHub: ServiceHub): NotarisationRequestSignature {
|
||||
val serializedRequest = this.serialize().bytes
|
||||
val signature = with(serviceHub) {
|
||||
val myLegalIdentity = myInfo.legalIdentitiesAndCerts.first().owningKey
|
||||
keyManagementService.sign(serializedRequest, myLegalIdentity)
|
||||
}
|
||||
return NotarisationRequestSignature(signature, serviceHub.myInfo.platformVersion)
|
||||
}
|
||||
|
||||
/** Checks if the provided states were used as inputs in the specified transaction. */
|
||||
fun isConsumedByTheSameTx(txIdHash: SecureHash, consumedStates: Map<StateRef, StateConsumptionDetails>): Boolean {
|
||||
val conflicts = consumedStates.filter { (_, cause) ->
|
||||
cause.hashOfTransactionId != txIdHash
|
||||
}
|
||||
return conflicts.isEmpty()
|
||||
}
|
||||
|
||||
/** Returns [NotaryError.TimeWindowInvalid] if [currentTime] is outside the [timeWindow], and *null* otherwise. */
|
||||
fun validateTimeWindow(currentTime: Instant, timeWindow: TimeWindow?): NotaryError.TimeWindowInvalid? {
|
||||
return if (timeWindow != null && currentTime !in timeWindow) {
|
||||
NotaryError.TimeWindowInvalid(currentTime, timeWindow)
|
||||
} else null
|
||||
}
|
@ -1,66 +1,13 @@
|
||||
package net.corda.core.node.services
|
||||
package net.corda.core.internal.notary
|
||||
|
||||
import com.google.common.primitives.Booleans
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import org.slf4j.Logger
|
||||
import java.security.PublicKey
|
||||
import java.time.Clock
|
||||
|
||||
abstract class NotaryService : SingletonSerializeAsToken() {
|
||||
companion object {
|
||||
@Deprecated("No longer used")
|
||||
const val ID_PREFIX = "corda.notary."
|
||||
|
||||
@Deprecated("No longer used")
|
||||
fun constructId(validating: Boolean, raft: Boolean = false, bft: Boolean = false, custom: Boolean = false): String {
|
||||
require(Booleans.countTrue(raft, bft, custom) <= 1) { "At most one of raft, bft or custom may be true" }
|
||||
return StringBuffer(ID_PREFIX).apply {
|
||||
append(if (validating) "validating" else "simple")
|
||||
if (raft) append(".raft")
|
||||
if (bft) append(".bft")
|
||||
if (custom) append(".custom")
|
||||
}.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current instant provided by the clock falls within the specified time window. Should only be
|
||||
* used by a notary service flow.
|
||||
*
|
||||
* @throws NotaryInternalException if current time is outside the specified time window. The exception contains
|
||||
* the [NotaryError.TimeWindowInvalid] error.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(NotaryInternalException::class)
|
||||
fun validateTimeWindow(clock: Clock, timeWindow: TimeWindow?) {
|
||||
if (timeWindow == null) return
|
||||
val currentTime = clock.instant()
|
||||
if (currentTime !in timeWindow) {
|
||||
throw NotaryInternalException(
|
||||
NotaryError.TimeWindowInvalid(currentTime, timeWindow)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract val services: ServiceHub
|
||||
abstract val notaryIdentityKey: PublicKey
|
||||
|
||||
abstract fun start()
|
||||
abstract fun stop()
|
||||
|
||||
/**
|
||||
* Produces a notary service flow which has the corresponding sends and receives as [NotaryFlow.Client].
|
||||
* @param otherPartySession client [Party] making the request
|
||||
*/
|
||||
abstract fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?>
|
||||
}
|
||||
|
||||
/**
|
||||
* A base notary service implementation that provides functionality for cases where a signature by a single member
|
||||
@ -74,8 +21,6 @@ abstract class TrustedAuthorityNotaryService : NotaryService() {
|
||||
protected open val log: Logger get() = staticLog
|
||||
protected abstract val uniquenessProvider: UniquenessProvider
|
||||
|
||||
fun validateTimeWindow(t: TimeWindow?) = NotaryService.validateTimeWindow(services.clock, t)
|
||||
|
||||
/**
|
||||
* A NotaryException is thrown if any of the states have been consumed by a different transaction. Note that
|
||||
* this method does not throw an exception when input states are present multiple times within the transaction.
|
||||
@ -113,9 +58,4 @@ abstract class TrustedAuthorityNotaryService : NotaryService() {
|
||||
}
|
||||
|
||||
// TODO: Sign multiple transactions at once by building their Merkle tree and then signing over its root.
|
||||
|
||||
@Deprecated("This property is no longer used")
|
||||
@Suppress("DEPRECATION")
|
||||
protected open val timeWindowChecker: TimeWindowChecker
|
||||
get() = throw UnsupportedOperationException("No default implementation, need to override")
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package net.corda.core.internal.notary
|
||||
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.identity.Party
|
||||
|
||||
/**
|
||||
* A service that records input states of the given transaction and provides conflict information
|
||||
* if any of the inputs have already been used in another transaction.
|
||||
*
|
||||
* A uniqueness provider is expected to be used from within the context of a flow.
|
||||
*/
|
||||
interface UniquenessProvider {
|
||||
/** Commits all input states of the given transaction. */
|
||||
fun commit(
|
||||
states: List<StateRef>,
|
||||
txId: SecureHash,
|
||||
callerIdentity: Party,
|
||||
requestSignature: NotarisationRequestSignature,
|
||||
timeWindow: TimeWindow? = null
|
||||
)
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package net.corda.core.node.services
|
||||
|
||||
import net.corda.core.CordaException
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
|
||||
/**
|
||||
* A service that records input states of the given transaction and provides conflict information
|
||||
* if any of the inputs have already been used in another transaction.
|
||||
*
|
||||
* A uniqueness provider is expected to be used from within the context of a flow.
|
||||
*/
|
||||
interface UniquenessProvider {
|
||||
/** Commits all input states of the given transaction. */
|
||||
fun commit(
|
||||
states: List<StateRef>,
|
||||
txId: SecureHash,
|
||||
callerIdentity: Party,
|
||||
requestSignature: NotarisationRequestSignature,
|
||||
timeWindow: TimeWindow? = null
|
||||
)
|
||||
|
||||
/** Specifies the consuming transaction for every conflicting state. */
|
||||
@CordaSerializable
|
||||
@Deprecated("No longer used due to potential privacy leak")
|
||||
@Suppress("DEPRECATION")
|
||||
data class Conflict(val stateHistory: Map<StateRef, ConsumingTx>)
|
||||
|
||||
/**
|
||||
* Specifies the transaction id, the position of the consumed state in the inputs, and
|
||||
* the caller identity requesting the commit.
|
||||
*/
|
||||
@CordaSerializable
|
||||
@Deprecated("No longer used")
|
||||
data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party)
|
||||
}
|
||||
|
||||
@Deprecated("No longer used due to potential privacy leak")
|
||||
@Suppress("DEPRECATION")
|
||||
class UniquenessException(val error: UniquenessProvider.Conflict) : CordaException(UniquenessException::class.java.name)
|
@ -6,13 +6,17 @@ release, see :doc:`upgrade-notes`.
|
||||
|
||||
Unreleased
|
||||
==========
|
||||
|
||||
|
||||
* Refactor RPC Client Kryo observable serialiser into it's own sub module
|
||||
|
||||
* Fix CORDA-1403 where a property of a class that implemented a generic interface could not be deserialised in
|
||||
a factory without a serialiser as the subtype check for the class instance failed. Fix is to compare the raw
|
||||
type.
|
||||
|
||||
* Due to ongoing work the experimental interfaces for defining custom notary services have been moved to the internal package.
|
||||
CorDapps implementing custom notary services will need to be updated, see ``samples/notary-demo`` for an example.
|
||||
Further changes may be required in the future.
|
||||
|
||||
* Fixed incorrect exception handling in ``NodeVaultService._query()``.
|
||||
|
||||
* Avoided a memory leak deriving from incorrect MappedSchema caching strategy.
|
||||
|
@ -18,6 +18,7 @@ import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.concurrent.map
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.*
|
||||
|
@ -3,9 +3,9 @@ package net.corda.node.internal
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.NotaryService
|
||||
import net.corda.node.services.api.CheckpointStorage
|
||||
import net.corda.node.services.api.StartedNodeServices
|
||||
import net.corda.node.services.messaging.MessagingService
|
||||
|
@ -7,7 +7,9 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.NotaryService
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
import net.corda.core.internal.notary.verifySignature
|
||||
import net.corda.core.schemas.PersistentStateRef
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
|
@ -15,13 +15,17 @@ import bftsmart.tom.util.Extractor
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.flows.NotarisationPayload
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.flows.StateConsumptionDetails
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.declaredField
|
||||
import net.corda.core.internal.isConsumedByTheSameTx
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.core.internal.notary.isConsumedByTheSameTx
|
||||
import net.corda.core.internal.notary.validateTimeWindow
|
||||
import net.corda.core.internal.toTypedArray
|
||||
import net.corda.core.internal.validateTimeWindow
|
||||
import net.corda.core.schemas.PersistentStateRef
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
|
@ -2,15 +2,17 @@ package net.corda.node.services.transactions
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.ComponentGroupEnum
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.internal.validateRequestSignature
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotarisationPayload
|
||||
import net.corda.core.flows.NotarisationRequest
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.core.transactions.ContractUpgradeFilteredTransaction
|
||||
import net.corda.core.transactions.CoreTransaction
|
||||
import net.corda.core.transactions.FilteredTransaction
|
||||
import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
|
||||
class NonValidatingNotaryFlow(otherSideSession: FlowSession, service: TrustedAuthorityNotaryService) : NotaryFlow.Service(otherSideSession, service) {
|
||||
class NonValidatingNotaryFlow(otherSideSession: FlowSession, service: TrustedAuthorityNotaryService) : NotaryServiceFlow(otherSideSession, service) {
|
||||
/**
|
||||
* The received transaction is not checked for contract-validity, as that would require fully
|
||||
* resolving it into a [TransactionForVerification], for which the caller would have to reveal the whole transaction
|
||||
|
@ -6,13 +6,13 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.flows.NotaryInternalException
|
||||
import net.corda.core.flows.StateConsumptionDetails
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.ThreadBox
|
||||
import net.corda.core.internal.isConsumedByTheSameTx
|
||||
import net.corda.core.internal.validateTimeWindow
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.core.internal.notary.UniquenessProvider
|
||||
import net.corda.core.internal.notary.isConsumedByTheSameTx
|
||||
import net.corda.core.internal.notary.validateTimeWindow
|
||||
import net.corda.core.schemas.PersistentStateRef
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import java.security.PublicKey
|
||||
|
||||
/** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
|
||||
@ -12,7 +12,7 @@ class RaftNonValidatingNotaryService(
|
||||
override val notaryIdentityKey: PublicKey,
|
||||
override val uniquenessProvider: RaftUniquenessProvider
|
||||
) : TrustedAuthorityNotaryService() {
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service {
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow {
|
||||
return NonValidatingNotaryFlow(otherPartySession, this)
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,8 @@ import net.corda.core.crypto.sha256
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.flows.StateConsumptionDetails
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.isConsumedByTheSameTx
|
||||
import net.corda.core.internal.validateTimeWindow
|
||||
import net.corda.core.internal.notary.isConsumedByTheSameTx
|
||||
import net.corda.core.internal.notary.validateTimeWindow
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.SerializationFactory
|
||||
import net.corda.core.serialization.deserialize
|
||||
|
@ -17,9 +17,9 @@ import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.flows.NotaryInternalException
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.core.internal.notary.UniquenessProvider
|
||||
import net.corda.core.schemas.PersistentStateRef
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.serialization.serialize
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import java.security.PublicKey
|
||||
|
||||
/** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
|
||||
@ -12,7 +12,7 @@ class RaftValidatingNotaryService(
|
||||
override val notaryIdentityKey: PublicKey,
|
||||
override val uniquenessProvider: RaftUniquenessProvider
|
||||
) : TrustedAuthorityNotaryService() {
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service {
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow {
|
||||
return ValidatingNotaryFlow(otherPartySession, this)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.node.services.api.ServiceHubInternal
|
||||
import java.security.PublicKey
|
||||
|
||||
@ -10,7 +10,7 @@ import java.security.PublicKey
|
||||
class SimpleNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
|
||||
override val uniquenessProvider = PersistentUniquenessProvider(services.clock)
|
||||
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service = NonValidatingNotaryFlow(otherPartySession, this)
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow = NonValidatingNotaryFlow(otherPartySession, this)
|
||||
|
||||
override fun start() {}
|
||||
override fun stop() {}
|
||||
|
@ -3,10 +3,14 @@ package net.corda.node.services.transactions
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotarisationPayload
|
||||
import net.corda.core.flows.NotarisationRequest
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.internal.ResolveTransactionsFlow
|
||||
import net.corda.core.internal.validateRequestSignature
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionWithSignatures
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
@ -18,7 +22,7 @@ import java.security.SignatureException
|
||||
* has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was
|
||||
* indeed valid.
|
||||
*/
|
||||
class ValidatingNotaryFlow(otherSideSession: FlowSession, service: TrustedAuthorityNotaryService) : NotaryFlow.Service(otherSideSession, service) {
|
||||
class ValidatingNotaryFlow(otherSideSession: FlowSession, service: TrustedAuthorityNotaryService) : NotaryServiceFlow(otherSideSession, service) {
|
||||
/**
|
||||
* Fully resolves the received transaction and its dependencies, runs contract verification logic and checks that
|
||||
* the transaction in question has all required signatures apart from the notary's.
|
||||
|
@ -1,8 +1,8 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.flows.NotaryFlow
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.node.services.api.ServiceHubInternal
|
||||
import java.security.PublicKey
|
||||
|
||||
@ -10,7 +10,7 @@ import java.security.PublicKey
|
||||
class ValidatingNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
|
||||
override val uniquenessProvider = PersistentUniquenessProvider(services.clock)
|
||||
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service = ValidatingNotaryFlow(otherPartySession, this)
|
||||
override fun createServiceFlow(otherPartySession: FlowSession): NotaryServiceFlow = ValidatingNotaryFlow(otherPartySession, this)
|
||||
|
||||
override fun start() {}
|
||||
override fun stop() {}
|
||||
|
@ -6,8 +6,8 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.flows.NotarisationRequestSignature
|
||||
import net.corda.core.flows.NotaryError
|
||||
import net.corda.core.flows.NotaryInternalException
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.node.internal.configureDatabase
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
|
@ -7,7 +7,7 @@ import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.generateSignature
|
||||
import net.corda.core.internal.notary.generateSignature
|
||||
import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.deserialize
|
||||
|
@ -5,10 +5,11 @@ import net.corda.core.contracts.TimeWindow
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.internal.ResolveTransactionsFlow
|
||||
import net.corda.core.internal.validateRequestSignature
|
||||
import net.corda.core.internal.notary.NotaryInternalException
|
||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||
import net.corda.core.internal.notary.TrustedAuthorityNotaryService
|
||||
import net.corda.core.node.AppServiceHub
|
||||
import net.corda.core.node.services.CordaService
|
||||
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionWithSignatures
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
@ -36,7 +37,7 @@ class MyCustomValidatingNotaryService(override val services: AppServiceHub, over
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
// START 2
|
||||
class MyValidatingNotaryFlow(otherSide: FlowSession, service: MyCustomValidatingNotaryService) : NotaryFlow.Service(otherSide, service) {
|
||||
class MyValidatingNotaryFlow(otherSide: FlowSession, service: MyCustomValidatingNotaryService) : NotaryServiceFlow(otherSide, service) {
|
||||
/**
|
||||
* The received transaction is checked for contract-validity, for which the caller also has to to reveal the whole
|
||||
* transaction dependency chain.
|
||||
|
Loading…
x
Reference in New Issue
Block a user