Split internal/external services

This patch splits internal services (to be referred to as "subsystems") from
external services (retaining the label "services"). This makes it clear which
are components of the node for its own use (such as the identity subsystem,
network map cache, wallet, etc.) and which are exposed for other nodes to use.

Further work is needed on consistency in naming, this just introduces the basic
restructuring.
This commit is contained in:
Ross Nicoll 2016-04-28 09:48:36 +01:00
parent e11ce06b87
commit 7a0300f024
32 changed files with 112 additions and 75 deletions

View File

@ -9,7 +9,7 @@ import core.WireTransaction
import core.crypto.DigitalSignature
import core.crypto.SecureHash
import core.node.AbstractNode
import core.node.services.linearHeadsOfType
import core.node.subsystems.linearHeadsOfType
import core.protocols.ProtocolLogic
import core.serialization.SerializedBytes
import core.utilities.ANSIProgressRenderer

View File

@ -1,7 +1,7 @@
package api
import com.fasterxml.jackson.databind.ObjectMapper
import core.node.services.ServiceHub
import core.node.ServiceHub
import core.utilities.JsonSupport
import javax.ws.rs.ext.ContextResolver
import javax.ws.rs.ext.Provider

View File

@ -9,7 +9,7 @@ import com.google.common.base.Throwables
import com.google.common.util.concurrent.ListenableFuture
import core.crypto.SecureHash
import core.crypto.sha256
import core.node.services.ServiceHub
import core.node.ServiceHub
import core.protocols.ProtocolLogic
import core.protocols.ProtocolStateMachine
import core.serialization.THREAD_LOCAL_KRYO

View File

@ -11,6 +11,7 @@ import core.crypto.generateKeyPair
import core.messaging.MessagingService
import core.messaging.StateMachineManager
import core.messaging.runOnNextMessage
import core.node.subsystems.*
import core.node.services.*
import core.random63BitValue
import core.serialization.deserialize

View File

@ -6,7 +6,7 @@ import api.ResponseFilter
import com.codahale.metrics.JmxReporter
import com.google.common.net.HostAndPort
import core.messaging.MessagingService
import core.node.services.ArtemisMessagingService
import core.node.subsystems.ArtemisMessagingService
import core.node.services.ServiceType
import core.node.servlets.AttachmentDownloadServlet
import core.node.servlets.DataUploadServlet

View File

@ -0,0 +1,58 @@
package core.node
import core.*
import core.crypto.SecureHash
import core.messaging.MessagingService
import core.node.subsystems.*
import core.node.services.*
import core.utilities.RecordingMap
import java.time.Clock
/**
* 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
* functionality and you don't want to hard-code which types in the interface.
*/
interface ServiceHub {
val walletService: WalletService
val keyManagementService: KeyManagementService
val identityService: IdentityService
val storageService: StorageService
val networkService: MessagingService
val networkMapCache: NetworkMapCache
val monitoringService: MonitoringService
val clock: Clock
/**
* Given a [LedgerTransaction], looks up all its dependencies in the local database, uses the identity service to map
* the [SignedTransaction]s the DB gives back into [LedgerTransaction]s, and then runs the smart contracts for the
* transaction. If no exception is thrown, the transaction is valid.
*/
fun verifyTransaction(ltx: LedgerTransaction) {
val dependencies = ltx.inputs.map {
storageService.validatedTransactions[it.txhash] ?: throw TransactionResolutionException(it.txhash)
}
val ltxns = dependencies.map { it.verifyToLedgerTransaction(identityService, storageService.attachments) }
TransactionGroup(setOf(ltx), ltxns.toSet()).verify()
}
/**
* Given a list of [SignedTransaction]s, writes them to the local storage for validated transactions and then
* sends them to the wallet for further processing.
*
* TODO: Need to come up with a way for preventing transactions being written other than by this method.
* TODO: RecordingMap is test infrastructure. Refactor it away or find a way to ensure it's only used in tests.
*
* @param txs The transactions to record
* @param skipRecordingMap This is used in unit testing and can be ignored most of the time.
*/
fun recordTransactions(txs: List<SignedTransaction>, skipRecordingMap: Boolean = false) {
val txns: Map<SecureHash, SignedTransaction> = txs.groupBy { it.id }.mapValues { it.value.first() }
val txStorage = storageService.validatedTransactions
if (txStorage is RecordingMap && skipRecordingMap)
txStorage.putAllUnrecorded(txns)
else
txStorage.putAll(txns)
walletService.notifyAll(txs.map { it.tx })
}
}

View File

@ -2,6 +2,7 @@ package core.node.services
import core.messaging.Message
import core.messaging.MessagingService
import core.node.subsystems.TOPIC_DEFAULT_POSTFIX
import core.serialization.deserialize
import core.serialization.serialize
import protocols.AbstractRequestMessage

View File

@ -11,6 +11,8 @@ import core.messaging.MessageRecipients
import core.messaging.MessagingService
import core.messaging.SingleMessageRecipient
import core.node.NodeInfo
import core.node.subsystems.NetworkMapCache
import core.node.subsystems.TOPIC_DEFAULT_POSTFIX
import core.serialization.SerializedBytes
import core.serialization.deserialize
import core.serialization.serialize

View File

@ -1,7 +1,7 @@
package core.node.servlets
import core.crypto.SecureHash
import core.node.services.StorageService
import core.node.subsystems.StorageService
import core.utilities.loggerFor
import java.io.FileNotFoundException
import javax.servlet.http.HttpServlet

View File

@ -1,4 +1,4 @@
package core.node.services
package core.node.subsystems
import com.google.common.net.HostAndPort
import core.RunOnCallerThread
@ -141,7 +141,7 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort,
// This code runs for every inbound message.
try {
if (!message.containsProperty(TOPIC_PROPERTY)) {
log.warn("Received message without a $TOPIC_PROPERTY property, ignoring")
log.warn("Received message without a ${TOPIC_PROPERTY} property, ignoring")
return@setMessageHandler
}
val topic = message.getStringProperty(TOPIC_PROPERTY)

View File

@ -1,4 +1,4 @@
package core.node.services
package core.node.subsystems
import core.SignedTransaction
import core.crypto.SecureHash
@ -6,6 +6,8 @@ import core.messaging.Message
import core.messaging.MessagingService
import core.messaging.SingleMessageRecipient
import core.messaging.send
import core.node.services.AbstractNodeService
import core.node.subsystems.StorageService
import core.serialization.deserialize
import core.utilities.loggerFor
import protocols.AbstractRequestMessage

View File

@ -1,7 +1,8 @@
package core.node.services
package core.node.subsystems
import core.ThreadBox
import core.crypto.generateKeyPair
import core.node.subsystems.KeyManagementService
import java.security.KeyPair
import java.security.PrivateKey
import java.security.PublicKey

View File

@ -1,6 +1,7 @@
package core.node.services
package core.node.subsystems
import core.Party
import core.node.services.IdentityService
import java.security.PublicKey
import java.util.concurrent.ConcurrentHashMap
import javax.annotation.concurrent.ThreadSafe

View File

@ -1,4 +1,4 @@
package core.node.services
package core.node.subsystems
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors
@ -10,6 +10,7 @@ import core.messaging.MessagingService
import core.messaging.StateMachineManager
import core.messaging.runOnNextMessage
import core.node.NodeInfo
import core.node.services.*
import core.random63BitValue
import core.serialization.deserialize
import core.serialization.serialize

View File

@ -1,9 +1,12 @@
package core.node.services
package core.node.subsystems
import com.codahale.metrics.Gauge
import contracts.Cash
import core.*
import core.crypto.SecureHash
import core.node.ServiceHub
import core.node.subsystems.Wallet
import core.node.subsystems.WalletService
import core.utilities.loggerFor
import core.utilities.trace
import java.security.PublicKey

View File

@ -1,10 +1,12 @@
package core.node.services
package core.node.subsystems
import com.codahale.metrics.MetricRegistry
import contracts.Cash
import core.*
import core.crypto.SecureHash
import core.messaging.MessagingService
import core.node.subsystems.NetworkMapCache
import core.node.services.AttachmentStorage
import core.utilities.RecordingMap
import java.security.KeyPair
import java.security.PrivateKey
@ -147,51 +149,3 @@ interface StorageService {
*/
class MonitoringService(val metrics: MetricRegistry)
/**
* 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
* functionality and you don't want to hard-code which types in the interface.
*/
interface ServiceHub {
val walletService: WalletService
val keyManagementService: KeyManagementService
val identityService: IdentityService
val storageService: StorageService
val networkService: MessagingService
val networkMapCache: NetworkMapCache
val monitoringService: MonitoringService
val clock: Clock
/**
* Given a [LedgerTransaction], looks up all its dependencies in the local database, uses the identity service to map
* the [SignedTransaction]s the DB gives back into [LedgerTransaction]s, and then runs the smart contracts for the
* transaction. If no exception is thrown, the transaction is valid.
*/
fun verifyTransaction(ltx: LedgerTransaction) {
val dependencies = ltx.inputs.map {
storageService.validatedTransactions[it.txhash] ?: throw TransactionResolutionException(it.txhash)
}
val ltxns = dependencies.map { it.verifyToLedgerTransaction(identityService, storageService.attachments) }
TransactionGroup(setOf(ltx), ltxns.toSet()).verify()
}
/**
* Given a list of [SignedTransaction]s, writes them to the local storage for validated transactions and then
* sends them to the wallet for further processing.
*
* TODO: Need to come up with a way for preventing transactions being written other than by this method.
* TODO: RecordingMap is test infrastructure. Refactor it away or find a way to ensure it's only used in tests.
*
* @param txs The transactions to record
* @param skipRecordingMap This is used in unit testing and can be ignored most of the time.
*/
fun recordTransactions(txs: List<SignedTransaction>, skipRecordingMap: Boolean = false) {
val txns: Map<SecureHash, SignedTransaction> = txs.groupBy { it.id }.mapValues { it.value.first() }
val txStorage = storageService.validatedTransactions
if (txStorage is RecordingMap && skipRecordingMap)
txStorage.putAllUnrecorded(txns)
else
txStorage.putAll(txns)
walletService.notifyAll(txs.map { it.tx })
}
}

View File

@ -1,8 +1,10 @@
package core.node.services
package core.node.subsystems
import core.Party
import core.SignedTransaction
import core.crypto.SecureHash
import core.node.services.AttachmentStorage
import core.node.subsystems.StorageService
import core.utilities.RecordingMap
import org.slf4j.LoggerFactory
import java.security.KeyPair

View File

@ -2,7 +2,7 @@ package core.protocols
import co.paralleluniverse.fibers.Suspendable
import core.messaging.MessageRecipients
import core.node.services.ServiceHub
import core.node.ServiceHub
import core.utilities.ProgressTracker
import core.utilities.UntrustworthyData
import org.slf4j.Logger

View File

@ -9,7 +9,7 @@ import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture
import core.messaging.MessageRecipients
import core.messaging.StateMachineManager
import core.node.services.ServiceHub
import core.node.ServiceHub
import core.serialization.createKryo
import core.utilities.UntrustworthyData
import org.slf4j.Logger

View File

@ -8,7 +8,7 @@ import contracts.InterestRateSwap
import core.*
import core.crypto.SecureHash
import core.testing.MockIdentityService
import core.node.services.linearHeadsOfType
import core.node.subsystems.linearHeadsOfType
import core.utilities.JsonSupport
import protocols.TwoPartyDealProtocol
import java.time.LocalDate

View File

@ -11,7 +11,7 @@ import co.paralleluniverse.common.util.VisibleForTesting
import core.Party
import core.crypto.DummyPublicKey
import core.messaging.SingleMessageRecipient
import core.node.services.InMemoryNetworkMapCache
import core.node.subsystems.InMemoryNetworkMapCache
import core.node.NodeInfo
/**

View File

@ -4,7 +4,7 @@ import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import contracts.CommercialPaper
import core.*
import core.node.services.NodeWalletService
import core.node.subsystems.NodeWalletService
import core.utilities.BriefLogFormatter
import protocols.TwoPartyTradeProtocol
import java.time.Instant

View File

@ -8,6 +8,7 @@ import core.node.Node
import core.node.NodeConfiguration
import core.node.NodeConfigurationFromConfig
import core.node.NodeInfo
import core.node.subsystems.ArtemisMessagingService
import core.node.services.*
import core.serialization.deserialize
import core.utilities.BriefLogFormatter

View File

@ -5,7 +5,7 @@ import core.*
import core.node.Node
import core.node.NodeConfiguration
import core.node.NodeInfo
import core.node.services.ArtemisMessagingService
import core.node.subsystems.ArtemisMessagingService
import core.node.services.NodeInterestRates
import core.node.services.ServiceType
import core.serialization.deserialize

View File

@ -12,6 +12,8 @@ import core.node.Node
import core.node.NodeConfiguration
import core.node.NodeConfigurationFromConfig
import core.node.NodeInfo
import core.node.subsystems.ArtemisMessagingService
import core.node.subsystems.NodeWalletService
import core.node.services.*
import core.protocols.ProtocolLogic
import core.serialization.deserialize

View File

@ -6,7 +6,7 @@ import contracts.InterestRateSwap
import core.StateAndRef
import core.node.Node
import core.node.NodeInfo
import core.node.services.linearHeadsOfType
import core.node.subsystems.linearHeadsOfType
import core.protocols.ProtocolLogic
import core.random63BitValue
import core.serialization.deserialize

View File

@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import core.NamedByHash
import core.crypto.SecureHash
import core.messaging.SingleMessageRecipient
import core.node.services.DataVendingService
import core.node.subsystems.DataVendingService
import core.protocols.ProtocolLogic
import core.random63BitValue
import core.utilities.UntrustworthyData

View File

@ -3,6 +3,8 @@ package core
import com.codahale.metrics.MetricRegistry
import core.crypto.*
import core.messaging.MessagingService
import core.node.ServiceHub
import core.node.subsystems.*
import core.node.services.*
import core.serialization.SerializedBytes
import core.serialization.deserialize

View File

@ -6,6 +6,11 @@ import core.*
import core.crypto.SecureHash
import core.node.NodeConfiguration
import core.node.NodeInfo
import core.node.ServiceHub
import core.node.subsystems.NodeWalletService
import core.node.subsystems.StorageService
import core.node.subsystems.StorageServiceImpl
import core.node.subsystems.Wallet
import core.node.services.*
import core.testing.InMemoryMessagingNetwork
import core.testing.MockNetwork

View File

@ -1,7 +1,8 @@
package core.node.services
package core.node.subsystems
import core.messaging.Message
import core.messaging.MessageRecipients
import core.node.subsystems.ArtemisMessagingService
import core.testutils.freeLocalHostAndPort
import org.assertj.core.api.Assertions.assertThat
import org.junit.After

View File

@ -1,4 +1,4 @@
package core.node.services
package core.node.subsystems
import core.testing.MockNetwork
import org.junit.Before

View File

@ -1,9 +1,9 @@
package core.node.services
package core.node.subsystems
import contracts.Cash
import core.*
import core.node.services.NodeWalletService
import core.node.services.ServiceHub
import core.node.subsystems.NodeWalletService
import core.node.ServiceHub
import core.testutils.*
import core.utilities.BriefLogFormatter
import org.junit.After