diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt index f516593fb6..37c71d5b88 100644 --- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt @@ -9,6 +9,25 @@ import net.corda.core.transactions.SignedTransaction import java.security.KeyPair import java.time.Clock +/** + * Subset of node services that are used for loading transactions from the wire into fully resolved, looked up + * forms ready for verification. + * + * @see ServiceHub + */ +interface ServicesForResolution { + val identityService: IdentityService + val storageService: AttachmentsStorageService + + /** + * Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState]. + * + * @throws TransactionResolutionException if the [StateRef] points to a non-existent transaction. + */ + @Throws(TransactionResolutionException::class) + fun loadState(stateRef: StateRef): TransactionState<*> +} + /** * A service hub simply vends references to the other services a node has. Some of those services may be missing or * mocked out. This class is useful to pass to chunks of pluggable code that might have need of many different kinds of @@ -17,12 +36,11 @@ import java.time.Clock * Any services exposed to flows (public view) need to implement [SerializeAsToken] or similar to avoid their internal * state from being serialized in checkpoints. */ -interface ServiceHub { +interface ServiceHub : ServicesForResolution { val vaultService: VaultService val keyManagementService: KeyManagementService - val identityService: IdentityService - val storageService: StorageService val networkService: MessagingService + override val storageService: StorageService val networkMapCache: NetworkMapCache val schedulerService: SchedulerService val clock: Clock @@ -37,20 +55,29 @@ interface ServiceHub { // TODO: Make this take a single tx. fun recordTransactions(txs: Iterable) + /** + * Given some [SignedTransaction]s, writes them to the local storage for validated transactions and then + * sends them to the vault for further processing. + * + * @param txs The transactions to record. + */ + fun recordTransactions(vararg txs: SignedTransaction) = recordTransactions(txs.toList()) + /** * Given a [StateRef] loads the referenced transaction and looks up the specified output [ContractState]. * * @throws TransactionResolutionException if the [StateRef] points to a non-existent transaction. */ - fun loadState(stateRef: StateRef): TransactionState<*> { + @Throws(TransactionResolutionException::class) + override fun loadState(stateRef: StateRef): TransactionState<*> { val definingTx = storageService.validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) return definingTx.tx.outputs[stateRef.index] } /** - * Given a [StateRef] loads the referenced transaction and returns a [StateAndRef] + * Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the protocol. * - * @throws TransactionResolutionException if the [StateRef] points to a non-existent transaction. + * @throws IllegalProtocolLogicException or IllegalArgumentException if there are problems with the [logicType] or [args]. */ fun toStateAndRef(ref: StateRef): StateAndRef { val definingTx = storageService.validatedTransactions.getTransaction(ref.txhash) ?: throw TransactionResolutionException(ref.txhash) diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index 18451a9b9e..889e9e9ad1 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -261,12 +261,17 @@ interface FileUploader { fun accepts(type: String): Boolean } +interface AttachmentsStorageService { + /** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */ + val attachments: AttachmentStorage +} + /** * A sketch of an interface to a simple key/value storage system. Intended for persistence of simple blobs like * transactions, serialised flow state machines and so on. Again, this isn't intended to imply lack of SQL or * anything like that, this interface is only big enough to support the prototyping work. */ -interface StorageService { +interface StorageService : AttachmentsStorageService { /** * A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. * The signatures aren't technically needed after that point, but we keep them around so that we can relay @@ -274,9 +279,6 @@ interface StorageService { */ val validatedTransactions: ReadOnlyTransactionStorage - /** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */ - val attachments: AttachmentStorage - @Suppress("DEPRECATION") @Deprecated("This service will be removed in a future milestone") val uploaders: List diff --git a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt index 1897bc070b..780d003814 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -7,7 +7,7 @@ import net.corda.core.crypto.MerkleTree import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash import net.corda.core.indexOfOrThrow -import net.corda.core.node.ServiceHub +import net.corda.core.node.ServicesForResolution import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.THREAD_LOCAL_KRYO import net.corda.core.serialization.deserialize @@ -70,7 +70,7 @@ class WireTransaction( * @throws TransactionResolutionException if an input points to a transaction not found in storage. */ @Throws(AttachmentResolutionException::class, TransactionResolutionException::class) - fun toLedgerTransaction(services: ServiceHub): LedgerTransaction { + fun toLedgerTransaction(services: ServicesForResolution): LedgerTransaction { // Look up public keys to authenticated identities. This is just a stub placeholder and will all change in future. val authenticatedArgs = commands.map { val parties = it.signers.mapNotNull { pk -> services.identityService.partyFromKey(pk) } @@ -117,9 +117,9 @@ class WireTransaction( override fun toString(): String { val buf = StringBuilder() - buf.appendln("Transaction $id:") + buf.appendln("Transaction:") for (input in inputs) buf.appendln("${Emoji.rightArrow}INPUT: $input") - for (output in outputs) buf.appendln("${Emoji.leftArrow}OUTPUT: $output") + for (output in outputs) buf.appendln("${Emoji.leftArrow}OUTPUT: ${output.data}") for (command in commands) buf.appendln("${Emoji.diamond}COMMAND: $command") for (attachment in attachments) buf.appendln("${Emoji.paperclip}ATTACHMENT: $attachment") return buf.toString()