Merge pull request from corda/aslemmer-services-for-resolution

core: Add ServicesForResolution interface
This commit is contained in:
Andras Slemmer 2017-03-02 12:08:08 +00:00 committed by GitHub
commit f00515b39e
3 changed files with 43 additions and 14 deletions
core/src/main/kotlin/net/corda/core

@ -9,6 +9,25 @@ import net.corda.core.transactions.SignedTransaction
import java.security.KeyPair import java.security.KeyPair
import java.time.Clock 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 * 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 * 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 * Any services exposed to flows (public view) need to implement [SerializeAsToken] or similar to avoid their internal
* state from being serialized in checkpoints. * state from being serialized in checkpoints.
*/ */
interface ServiceHub { interface ServiceHub : ServicesForResolution {
val vaultService: VaultService val vaultService: VaultService
val keyManagementService: KeyManagementService val keyManagementService: KeyManagementService
val identityService: IdentityService
val storageService: StorageService
val networkService: MessagingService val networkService: MessagingService
override val storageService: StorageService
val networkMapCache: NetworkMapCache val networkMapCache: NetworkMapCache
val schedulerService: SchedulerService val schedulerService: SchedulerService
val clock: Clock val clock: Clock
@ -37,20 +55,29 @@ interface ServiceHub {
// TODO: Make this take a single tx. // TODO: Make this take a single tx.
fun recordTransactions(txs: Iterable<SignedTransaction>) fun recordTransactions(txs: Iterable<SignedTransaction>)
/**
* 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]. * 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 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) val definingTx = storageService.validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash)
return definingTx.tx.outputs[stateRef.index] return definingTx.tx.outputs[stateRef.index]
} }
/** /**
* Given a [StateRef] loads the referenced transaction and returns a [StateAndRef<T>] * 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 <T : ContractState> toStateAndRef(ref: StateRef): StateAndRef<T> { fun <T : ContractState> toStateAndRef(ref: StateRef): StateAndRef<T> {
val definingTx = storageService.validatedTransactions.getTransaction(ref.txhash) ?: throw TransactionResolutionException(ref.txhash) val definingTx = storageService.validatedTransactions.getTransaction(ref.txhash) ?: throw TransactionResolutionException(ref.txhash)

@ -264,12 +264,17 @@ interface FileUploader {
fun accepts(type: String): Boolean 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 * 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 * 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. * 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. * 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 * The signatures aren't technically needed after that point, but we keep them around so that we can relay
@ -277,9 +282,6 @@ interface StorageService {
*/ */
val validatedTransactions: ReadOnlyTransactionStorage val validatedTransactions: ReadOnlyTransactionStorage
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
val attachments: AttachmentStorage
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@Deprecated("This service will be removed in a future milestone") @Deprecated("This service will be removed in a future milestone")
val uploaders: List<FileUploader> val uploaders: List<FileUploader>

@ -7,7 +7,7 @@ import net.corda.core.crypto.MerkleTree
import net.corda.core.crypto.Party import net.corda.core.crypto.Party
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.indexOfOrThrow 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.SerializedBytes
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
@ -70,7 +70,7 @@ class WireTransaction(
* @throws TransactionResolutionException if an input points to a transaction not found in storage. * @throws TransactionResolutionException if an input points to a transaction not found in storage.
*/ */
@Throws(AttachmentResolutionException::class, TransactionResolutionException::class) @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. // Look up public keys to authenticated identities. This is just a stub placeholder and will all change in future.
val authenticatedArgs = commands.map { val authenticatedArgs = commands.map {
val parties = it.signers.mapNotNull { pk -> services.identityService.partyFromKey(pk) } val parties = it.signers.mapNotNull { pk -> services.identityService.partyFromKey(pk) }
@ -117,9 +117,9 @@ class WireTransaction(
override fun toString(): String { override fun toString(): String {
val buf = StringBuilder() val buf = StringBuilder()
buf.appendln("Transaction $id:") buf.appendln("Transaction:")
for (input in inputs) buf.appendln("${Emoji.rightArrow}INPUT: $input") 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 (command in commands) buf.appendln("${Emoji.diamond}COMMAND: $command")
for (attachment in attachments) buf.appendln("${Emoji.paperclip}ATTACHMENT: $attachment") for (attachment in attachments) buf.appendln("${Emoji.paperclip}ATTACHMENT: $attachment")
return buf.toString() return buf.toString()