FlowException can be thrown from within UntrustworthyData.unwrap for better Java interop, and more checked exception annotations relating to flows

This commit is contained in:
Shams Asari 2017-02-01 11:28:50 +00:00 committed by Chris Rankin
parent c2f1e05dc0
commit e44159504c
26 changed files with 55 additions and 22 deletions

2
.gitignore vendored
View File

@ -11,7 +11,6 @@ tags
.gradle
local.properties
/docs/build/doctrees
# General build files
**/build/*
@ -34,7 +33,6 @@ lib/dokka.jar
.idea/libraries
.idea/shelf
.idea/dataSources
.idea/modules.xml
# if you remove the above rule, at least ignore the following:

View File

@ -17,6 +17,7 @@ sealed class TransactionType {
*
* Note: Presence of _signatures_ is not checked, only the public keys to be signed for.
*/
@Throws(TransactionVerificationException::class)
fun verify(tx: LedgerTransaction) {
require(tx.notary != null || tx.timestamp == null) { "Transactions with timestamps must be notarised." }
val duplicates = detectDuplicateInputs(tx)

View File

@ -3,6 +3,7 @@ package net.corda.core.contracts
import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.Party
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException
import net.corda.core.transactions.LedgerTransaction
import java.util.*
@ -85,30 +86,35 @@ data class TransactionForContract(val inputs: List<ContractState>,
data class InOutGroup<out T : ContractState, out K : Any>(val inputs: List<T>, val outputs: List<T>, val groupingKey: K)
}
class TransactionResolutionException(val hash: SecureHash) : Exception() {
override fun toString() = "Transaction resolution failure for $hash"
class TransactionResolutionException(val hash: SecureHash) : FlowException() {
override fun toString(): String = "Transaction resolution failure for $hash"
}
class AttachmentResolutionException(val hash : SecureHash) : FlowException() {
override fun toString(): String = "Attachment resolution failure for $hash"
}
class TransactionConflictException(val conflictRef: StateRef, val tx1: LedgerTransaction, val tx2: LedgerTransaction) : Exception()
sealed class TransactionVerificationException(val tx: LedgerTransaction, cause: Throwable?) : Exception(cause) {
sealed class TransactionVerificationException(val tx: LedgerTransaction, cause: Throwable?) : FlowException(cause) {
class ContractRejection(tx: LedgerTransaction, val contract: Contract, cause: Throwable?) : TransactionVerificationException(tx, cause)
class MoreThanOneNotary(tx: LedgerTransaction) : TransactionVerificationException(tx, null)
class SignersMissing(tx: LedgerTransaction, val missing: List<CompositeKey>) : TransactionVerificationException(tx, null) {
override fun toString() = "Signers missing: ${missing.joinToString()}"
override fun toString(): String = "Signers missing: ${missing.joinToString()}"
}
class DuplicateInputStates(tx: LedgerTransaction, val duplicates: Set<StateRef>) : TransactionVerificationException(tx, null) {
override fun toString() = "Duplicate inputs: ${duplicates.joinToString()}"
override fun toString(): String = "Duplicate inputs: ${duplicates.joinToString()}"
}
class InvalidNotaryChange(tx: LedgerTransaction) : TransactionVerificationException(tx, null)
class NotaryChangeInWrongTransactionType(tx: LedgerTransaction, val outputNotary: Party) : TransactionVerificationException(tx, null) {
override fun toString(): String = "Found unexpected notary change in transaction. Tx notary: ${tx.notary}, found: ${outputNotary}"
override fun toString(): String {
return "Found unexpected notary change in transaction. Tx notary: ${tx.notary}, found: $outputNotary"
}
}
class TransactionMissingEncumbranceException(tx: LedgerTransaction, val missing: Int, val inOut: Direction) : TransactionVerificationException(tx, null) {
override val message: String?
get() = "Missing required encumbrance ${missing} in ${inOut}"
override val message: String get() = "Missing required encumbrance $missing in $inOut"
}
enum class Direction {
INPUT,

View File

@ -9,5 +9,8 @@ package net.corda.core.flows
* [FlowException] (or a subclass) can be a valid expected response from a flow, particularly ones which act as a service.
* It is recommended a [FlowLogic] document the [FlowException] types it can throw.
*/
open class FlowException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null)
: Exception(message, cause)
open class FlowException(override val message: String?, override val cause: Throwable?) : Exception() {
constructor(message: String?) : this(message, null)
constructor(cause: Throwable?) : this(cause?.toString(), cause)
constructor() : this(null, null)
}

View File

@ -54,6 +54,7 @@ class LedgerTransaction(
*
* @throws TransactionVerificationException if anything goes wrong.
*/
@Throws(TransactionVerificationException::class)
fun verify() = type.verify(this)
// TODO: When we upgrade to Kotlin 1.1 we can make this a data class again and have the compiler generate these.

View File

@ -1,5 +1,6 @@
package net.corda.core.transactions
import net.corda.core.contracts.AttachmentResolutionException
import net.corda.core.contracts.NamedByHash
import net.corda.core.contracts.TransactionResolutionException
import net.corda.core.crypto.CompositeKey
@ -8,7 +9,6 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.signWithECDSA
import net.corda.core.node.ServiceHub
import net.corda.core.serialization.SerializedBytes
import java.io.FileNotFoundException
import java.security.KeyPair
import java.security.SignatureException
import java.util.*
@ -127,12 +127,12 @@ data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
* [WireTransaction.toLedgerTransaction] with the passed in [ServiceHub] to resolve the dependencies,
* returning an unverified LedgerTransaction.
*
* @throws FileNotFoundException if a required attachment was not found in storage.
* @throws AttachmentResolutionException if a required attachment was not found in storage.
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
* @throws SignatureException if any signatures were invalid or unrecognised
* @throws SignaturesMissingException if any signatures that should have been present are missing.
*/
@Throws(FileNotFoundException::class, TransactionResolutionException::class, SignaturesMissingException::class)
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class, SignatureException::class)
fun toLedgerTransaction(services: ServiceHub) = verifySignatures().toLedgerTransaction(services)
/**

View File

@ -12,7 +12,6 @@ import net.corda.core.serialization.THREAD_LOCAL_KRYO
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.utilities.Emoji
import java.io.FileNotFoundException
import java.security.PublicKey
/**
@ -66,10 +65,10 @@ class WireTransaction(
* Looks up identities and attachments from storage to generate a [LedgerTransaction]. A transaction is expected to
* have been fully resolved using the resolution flow by this point.
*
* @throws FileNotFoundException if a required attachment was not found in storage.
* @throws AttachmentResolutionException if a required attachment was not found in storage.
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
*/
@Throws(FileNotFoundException::class, TransactionResolutionException::class)
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class)
fun toLedgerTransaction(services: ServiceHub): LedgerTransaction {
// Look up public keys to authenticated identities. This is just a stub placeholder and will all change in future.
val authenticatedArgs = commands.map {
@ -78,7 +77,7 @@ class WireTransaction(
}
// Open attachments specified in this transaction. If we haven't downloaded them, we fail.
val attachments = attachments.map {
services.storageService.attachments.openAttachment(it) ?: throw FileNotFoundException(it.toString())
services.storageService.attachments.openAttachment(it) ?: throw AttachmentResolutionException(it)
}
val resolvedInputs = inputs.map { StateAndRef(services.loadState(it), it) }
return LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, mustSign, timestamp, type)

View File

@ -18,11 +18,18 @@ class UntrustworthyData<out T>(private val fromUntrustedWorld: T) {
@Deprecated("Accessing the untrustworthy data directly without validating it first is a bad idea")
get() = fromUntrustedWorld
@Suppress("DEPRECATION")
@Throws(FlowException::class)
inline fun <R> unwrap(validator: (T) -> R) = validator(data)
fun <R> unwrap(validator: Validator<T, R>) = validator.validate(fromUntrustedWorld)
@Suppress("DEPRECATION")
@Deprecated("This old name was confusing, use unwrap instead", replaceWith = ReplaceWith("unwrap"))
inline fun <R> validate(validator: (T) -> R) = validator(data)
interface Validator<in T, out R> {
@Throws(FlowException::class)
fun validate(data: T): R
}
}
@Suppress("DEPRECATION")
inline fun <T, R> UntrustworthyData<T>.unwrap(validator: (T) -> R): R = validator(data)

View File

@ -15,6 +15,7 @@ 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 net.corda.flows.AbstractStateReplacementFlow.Acceptor
import net.corda.flows.AbstractStateReplacementFlow.Instigator

View File

@ -7,6 +7,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic
import net.corda.core.utilities.UntrustworthyData
import net.corda.core.utilities.unwrap
import net.corda.flows.FetchDataFlow.DownloadedVsRequestedDataMismatch
import net.corda.flows.FetchDataFlow.HashNotFound
import java.util.*

View File

@ -5,8 +5,8 @@ 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.flows.FlowLogic
import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic
import net.corda.core.node.services.TimestampChecker
import net.corda.core.node.services.UniquenessException
import net.corda.core.node.services.UniquenessProvider
@ -14,6 +14,7 @@ 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.unwrap
object NotaryFlow {
/**

View File

@ -16,6 +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 net.corda.core.utilities.unwrap
import java.security.KeyPair
/**

View File

@ -14,6 +14,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.node.PluginServiceHub
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap
import net.corda.flows.FinalityFlow
import net.corda.flows.ResolveTransactionsFlow
import java.util.*

View File

@ -8,6 +8,7 @@ import net.corda.core.node.PluginServiceHub
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.linearHeadsOfType
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap
import net.corda.flows.FinalityFlow
import java.security.PublicKey
import java.time.Duration

View File

@ -9,6 +9,7 @@ import net.corda.core.node.PluginServiceHub
import net.corda.core.serialization.OpaqueBytes
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import java.util.*
/**

View File

@ -13,6 +13,7 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.trace
import net.corda.core.utilities.unwrap
import java.security.KeyPair
import java.util.*

View File

@ -10,6 +10,7 @@ import net.corda.core.getOrThrow
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.random63BitValue
import net.corda.core.seconds
import net.corda.core.utilities.unwrap
import net.corda.node.internal.Node
import net.corda.node.services.User
import net.corda.node.services.config.SSLConfiguration

View File

@ -10,6 +10,7 @@ import net.corda.core.node.PluginServiceHub
import net.corda.core.node.recordTransactions
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap
import net.corda.flows.*
import java.util.function.Function
import javax.annotation.concurrent.ThreadSafe

View File

@ -21,6 +21,7 @@ import net.corda.core.random63BitValue
import net.corda.core.rootCause
import net.corda.core.serialization.OpaqueBytes
import net.corda.core.serialization.deserialize
import net.corda.core.utilities.unwrap
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.flows.CashCommand

View File

@ -14,6 +14,7 @@ import net.corda.core.node.services.ServiceType
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.FilteredTransaction
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.irs.flows.FixingFlow
import net.corda.irs.flows.RatesFixFlow
import net.corda.node.services.api.AcceptsFileUpload

View File

@ -7,6 +7,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.node.CordaPluginRegistry
import net.corda.core.node.NodeInfo
import net.corda.core.node.PluginServiceHub
import net.corda.core.utilities.unwrap
import net.corda.testing.node.MockNetworkMapCache
import java.util.concurrent.TimeUnit
import java.util.function.Function

View File

@ -10,6 +10,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.transactions.FilteredTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.irs.flows.RatesFixFlow.FixOutOfRange
import net.corda.irs.utilities.suggestInterestRateAnnouncementTimeWindow
import java.math.BigDecimal

View File

@ -7,6 +7,7 @@ import net.corda.core.node.CordaPluginRegistry
import net.corda.core.node.NodeInfo
import net.corda.core.node.PluginServiceHub
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.node.utilities.TestClock
import net.corda.testing.node.MockNetworkMapCache
import java.time.LocalDate

View File

@ -5,6 +5,7 @@ import net.corda.core.crypto.Party
import net.corda.core.flows.FlowLogic
import net.corda.core.node.PluginServiceHub
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap
import net.corda.flows.TwoPartyDealFlow
import net.corda.vega.contracts.IRSState
import net.corda.vega.contracts.OGTrade

View File

@ -18,6 +18,7 @@ import net.corda.core.messaging.Ack
import net.corda.core.node.PluginServiceHub
import net.corda.core.node.services.dealsWith
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.unwrap
import net.corda.flows.AbstractStateReplacementFlow.Proposal
import net.corda.flows.StateReplacementException
import net.corda.flows.TwoPartyDealFlow

View File

@ -12,6 +12,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.Emoji
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.flows.TwoPartyTradeFlow
import net.corda.node.services.persistence.NodeAttachmentService
import java.nio.file.Path