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.DigitalSignature
import core.crypto.SecureHash import core.crypto.SecureHash
import core.node.AbstractNode import core.node.AbstractNode
import core.node.services.linearHeadsOfType import core.node.subsystems.linearHeadsOfType
import core.protocols.ProtocolLogic import core.protocols.ProtocolLogic
import core.serialization.SerializedBytes import core.serialization.SerializedBytes
import core.utilities.ANSIProgressRenderer import core.utilities.ANSIProgressRenderer

View File

@ -1,7 +1,7 @@
package api package api
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import core.node.services.ServiceHub import core.node.ServiceHub
import core.utilities.JsonSupport import core.utilities.JsonSupport
import javax.ws.rs.ext.ContextResolver import javax.ws.rs.ext.ContextResolver
import javax.ws.rs.ext.Provider 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 com.google.common.util.concurrent.ListenableFuture
import core.crypto.SecureHash import core.crypto.SecureHash
import core.crypto.sha256 import core.crypto.sha256
import core.node.services.ServiceHub import core.node.ServiceHub
import core.protocols.ProtocolLogic import core.protocols.ProtocolLogic
import core.protocols.ProtocolStateMachine import core.protocols.ProtocolStateMachine
import core.serialization.THREAD_LOCAL_KRYO import core.serialization.THREAD_LOCAL_KRYO

View File

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

View File

@ -6,7 +6,7 @@ import api.ResponseFilter
import com.codahale.metrics.JmxReporter import com.codahale.metrics.JmxReporter
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import core.messaging.MessagingService import core.messaging.MessagingService
import core.node.services.ArtemisMessagingService import core.node.subsystems.ArtemisMessagingService
import core.node.services.ServiceType import core.node.services.ServiceType
import core.node.servlets.AttachmentDownloadServlet import core.node.servlets.AttachmentDownloadServlet
import core.node.servlets.DataUploadServlet 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.Message
import core.messaging.MessagingService import core.messaging.MessagingService
import core.node.subsystems.TOPIC_DEFAULT_POSTFIX
import core.serialization.deserialize import core.serialization.deserialize
import core.serialization.serialize import core.serialization.serialize
import protocols.AbstractRequestMessage import protocols.AbstractRequestMessage

View File

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

View File

@ -1,7 +1,7 @@
package core.node.servlets package core.node.servlets
import core.crypto.SecureHash import core.crypto.SecureHash
import core.node.services.StorageService import core.node.subsystems.StorageService
import core.utilities.loggerFor import core.utilities.loggerFor
import java.io.FileNotFoundException import java.io.FileNotFoundException
import javax.servlet.http.HttpServlet 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 com.google.common.net.HostAndPort
import core.RunOnCallerThread import core.RunOnCallerThread
@ -141,7 +141,7 @@ class ArtemisMessagingService(val directory: Path, val myHostPort: HostAndPort,
// This code runs for every inbound message. // This code runs for every inbound message.
try { try {
if (!message.containsProperty(TOPIC_PROPERTY)) { 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 return@setMessageHandler
} }
val topic = message.getStringProperty(TOPIC_PROPERTY) 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.SignedTransaction
import core.crypto.SecureHash import core.crypto.SecureHash
@ -6,6 +6,8 @@ import core.messaging.Message
import core.messaging.MessagingService import core.messaging.MessagingService
import core.messaging.SingleMessageRecipient import core.messaging.SingleMessageRecipient
import core.messaging.send import core.messaging.send
import core.node.services.AbstractNodeService
import core.node.subsystems.StorageService
import core.serialization.deserialize import core.serialization.deserialize
import core.utilities.loggerFor import core.utilities.loggerFor
import protocols.AbstractRequestMessage import protocols.AbstractRequestMessage

View File

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

View File

@ -1,6 +1,7 @@
package core.node.services package core.node.subsystems
import core.Party import core.Party
import core.node.services.IdentityService
import java.security.PublicKey import java.security.PublicKey
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import javax.annotation.concurrent.ThreadSafe 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.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.MoreExecutors
@ -10,6 +10,7 @@ import core.messaging.MessagingService
import core.messaging.StateMachineManager import core.messaging.StateMachineManager
import core.messaging.runOnNextMessage import core.messaging.runOnNextMessage
import core.node.NodeInfo import core.node.NodeInfo
import core.node.services.*
import core.random63BitValue import core.random63BitValue
import core.serialization.deserialize import core.serialization.deserialize
import core.serialization.serialize import core.serialization.serialize

View File

@ -1,9 +1,12 @@
package core.node.services package core.node.subsystems
import com.codahale.metrics.Gauge import com.codahale.metrics.Gauge
import contracts.Cash import contracts.Cash
import core.* import core.*
import core.crypto.SecureHash 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.loggerFor
import core.utilities.trace import core.utilities.trace
import java.security.PublicKey import java.security.PublicKey

View File

@ -1,10 +1,12 @@
package core.node.services package core.node.subsystems
import com.codahale.metrics.MetricRegistry import com.codahale.metrics.MetricRegistry
import contracts.Cash import contracts.Cash
import core.* import core.*
import core.crypto.SecureHash import core.crypto.SecureHash
import core.messaging.MessagingService import core.messaging.MessagingService
import core.node.subsystems.NetworkMapCache
import core.node.services.AttachmentStorage
import core.utilities.RecordingMap import core.utilities.RecordingMap
import java.security.KeyPair import java.security.KeyPair
import java.security.PrivateKey import java.security.PrivateKey
@ -147,51 +149,3 @@ interface StorageService {
*/ */
class MonitoringService(val metrics: MetricRegistry) 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.Party
import core.SignedTransaction import core.SignedTransaction
import core.crypto.SecureHash import core.crypto.SecureHash
import core.node.services.AttachmentStorage
import core.node.subsystems.StorageService
import core.utilities.RecordingMap import core.utilities.RecordingMap
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.security.KeyPair import java.security.KeyPair

View File

@ -2,7 +2,7 @@ package core.protocols
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import core.messaging.MessageRecipients import core.messaging.MessageRecipients
import core.node.services.ServiceHub import core.node.ServiceHub
import core.utilities.ProgressTracker import core.utilities.ProgressTracker
import core.utilities.UntrustworthyData import core.utilities.UntrustworthyData
import org.slf4j.Logger 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 com.google.common.util.concurrent.SettableFuture
import core.messaging.MessageRecipients import core.messaging.MessageRecipients
import core.messaging.StateMachineManager import core.messaging.StateMachineManager
import core.node.services.ServiceHub import core.node.ServiceHub
import core.serialization.createKryo import core.serialization.createKryo
import core.utilities.UntrustworthyData import core.utilities.UntrustworthyData
import org.slf4j.Logger import org.slf4j.Logger

View File

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

View File

@ -11,7 +11,7 @@ import co.paralleluniverse.common.util.VisibleForTesting
import core.Party import core.Party
import core.crypto.DummyPublicKey import core.crypto.DummyPublicKey
import core.messaging.SingleMessageRecipient import core.messaging.SingleMessageRecipient
import core.node.services.InMemoryNetworkMapCache import core.node.subsystems.InMemoryNetworkMapCache
import core.node.NodeInfo 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 com.google.common.util.concurrent.ListenableFuture
import contracts.CommercialPaper import contracts.CommercialPaper
import core.* import core.*
import core.node.services.NodeWalletService import core.node.subsystems.NodeWalletService
import core.utilities.BriefLogFormatter import core.utilities.BriefLogFormatter
import protocols.TwoPartyTradeProtocol import protocols.TwoPartyTradeProtocol
import java.time.Instant import java.time.Instant

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,11 @@ import core.*
import core.crypto.SecureHash import core.crypto.SecureHash
import core.node.NodeConfiguration import core.node.NodeConfiguration
import core.node.NodeInfo 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.node.services.*
import core.testing.InMemoryMessagingNetwork import core.testing.InMemoryMessagingNetwork
import core.testing.MockNetwork 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.Message
import core.messaging.MessageRecipients import core.messaging.MessageRecipients
import core.node.subsystems.ArtemisMessagingService
import core.testutils.freeLocalHostAndPort import core.testutils.freeLocalHostAndPort
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After

View File

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

View File

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