Merge pull request #293 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

View File

@ -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<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].
*
* @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<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> {
val definingTx = storageService.validatedTransactions.getTransaction(ref.txhash) ?: throw TransactionResolutionException(ref.txhash)

View File

@ -264,12 +264,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
@ -277,9 +282,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<FileUploader>

View File

@ -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.deserialize
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(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()