Push internal subsystems into node

This commit is contained in:
Matthew Nesbit 2016-05-18 10:15:03 +01:00
parent 5e70646bd2
commit c8130581a9
8 changed files with 45 additions and 45 deletions

View File

@ -1,7 +1,6 @@
package protocols package protocols
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import com.google.common.util.concurrent.ListenableFuture
import contracts.Cash import contracts.Cash
import contracts.sumCashBy import contracts.sumCashBy
import core.contracts.* import core.contracts.*
@ -9,7 +8,6 @@ import core.crypto.DigitalSignature
import core.crypto.Party import core.crypto.Party
import core.crypto.signWithECDSA import core.crypto.signWithECDSA
import core.messaging.SingleMessageRecipient import core.messaging.SingleMessageRecipient
import core.messaging.StateMachineManager
import core.node.NodeInfo import core.node.NodeInfo
import core.protocols.ProtocolLogic import core.protocols.ProtocolLogic
import core.random63BitValue import core.random63BitValue
@ -46,20 +44,6 @@ import java.security.SignatureException
object TwoPartyTradeProtocol { object TwoPartyTradeProtocol {
val TRADE_TOPIC = "platform.trade" val TRADE_TOPIC = "platform.trade"
fun runSeller(smm: StateMachineManager, notary: NodeInfo,
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount,
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<SignedTransaction> {
val seller = Seller(otherSide, notary, assetToSell, price, myKeyPair, buyerSessionID)
return smm.add("${TRADE_TOPIC}.seller", seller)
}
fun runBuyer(smm: StateMachineManager, notaryNode: NodeInfo,
otherSide: SingleMessageRecipient, acceptablePrice: Amount, typeToBuy: Class<out OwnableState>,
sessionID: Long): ListenableFuture<SignedTransaction> {
val buyer = Buyer(otherSide, notaryNode.identity, acceptablePrice, typeToBuy, sessionID)
return smm.add("$TRADE_TOPIC.buyer", buyer)
}
class UnacceptablePriceException(val givenPrice: Amount) : Exception() class UnacceptablePriceException(val givenPrice: Amount) : Exception()
class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() { class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() {
override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName" override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName"

View File

@ -1,12 +1,10 @@
package core.node.subsystems package core.node.subsystems
import com.codahale.metrics.MetricRegistry import com.codahale.metrics.MetricRegistry
import core.*
import core.contracts.* import core.contracts.*
import core.crypto.Party import core.crypto.Party
import core.crypto.SecureHash import core.crypto.SecureHash
import core.node.services.AttachmentStorage import core.node.services.AttachmentStorage
import core.node.storage.CheckpointStorage
import java.security.KeyPair import java.security.KeyPair
import java.security.PrivateKey import java.security.PrivateKey
import java.security.PublicKey import java.security.PublicKey
@ -128,8 +126,6 @@ interface StorageService {
*/ */
val validatedTransactions: MutableMap<SecureHash, SignedTransaction> val validatedTransactions: MutableMap<SecureHash, SignedTransaction>
val checkpointStorage: CheckpointStorage
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */ /** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
val attachments: AttachmentStorage val attachments: AttachmentStorage

View File

@ -9,6 +9,7 @@ import com.google.common.base.Throwables
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import core.node.ServiceHub import core.node.ServiceHub
import core.node.storage.Checkpoint import core.node.storage.Checkpoint
import core.node.storage.CheckpointStorage
import core.protocols.ProtocolLogic import core.protocols.ProtocolLogic
import core.protocols.ProtocolStateMachine import core.protocols.ProtocolStateMachine
import core.protocols.ProtocolStateMachineImpl import core.protocols.ProtocolStateMachineImpl
@ -53,14 +54,13 @@ import javax.annotation.concurrent.ThreadSafe
* TODO: Implement stub/skel classes that provide a basic RPC framework on top of this. * TODO: Implement stub/skel classes that provide a basic RPC framework on top of this.
*/ */
@ThreadSafe @ThreadSafe
class StateMachineManager(val serviceHub: ServiceHub, val executor: AffinityExecutor) { class StateMachineManager(val serviceHub: ServiceHub, val checkpointStorage: CheckpointStorage, val executor: AffinityExecutor) {
inner class FiberScheduler : FiberExecutorScheduler("Same thread scheduler", executor) inner class FiberScheduler : FiberExecutorScheduler("Same thread scheduler", executor)
val scheduler = FiberScheduler() val scheduler = FiberScheduler()
// This map is backed by a database and will be used to store serialised state machines to disk, so we can resurrect // This map is backed by a database and will be used to store serialised state machines to disk, so we can resurrect
// them across node restarts. // them across node restarts.
private val checkpointStorage = serviceHub.storageService.checkpointStorage
// A list of all the state machines being managed by this class. We expose snapshots of it via the stateMachines // A list of all the state machines being managed by this class. We expose snapshots of it via the stateMachines
// property. // property.
private val stateMachines = synchronizedMap(HashMap<ProtocolStateMachineImpl<*>, Checkpoint>()) private val stateMachines = synchronizedMap(HashMap<ProtocolStateMachineImpl<*>, Checkpoint>())

View File

@ -78,6 +78,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity] open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
lateinit var storage: StorageService lateinit var storage: StorageService
lateinit var checkpointStorage: CheckpointStorage
lateinit var smm: StateMachineManager lateinit var smm: StateMachineManager
lateinit var wallet: WalletService lateinit var wallet: WalletService
lateinit var keyManagement: E2ETestKeyManagementService lateinit var keyManagement: E2ETestKeyManagementService
@ -99,9 +100,11 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
require(!started) { "Node has already been started" } require(!started) { "Node has already been started" }
log.info("Node starting up ...") log.info("Node starting up ...")
storage = initialiseStorageService(dir) val storageServices = initialiseStorageService(dir)
storage = storageServices.first
checkpointStorage = storageServices.second
net = makeMessagingService() net = makeMessagingService()
smm = StateMachineManager(services, serverThread) smm = StateMachineManager(services, checkpointStorage, serverThread)
wallet = NodeWalletService(services) wallet = NodeWalletService(services)
keyManagement = E2ETestKeyManagementService() keyManagement = E2ETestKeyManagementService()
makeInterestRatesOracleService() makeInterestRatesOracleService()
@ -216,16 +219,16 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
protected abstract fun startMessagingService() protected abstract fun startMessagingService()
protected open fun initialiseStorageService(dir: Path): StorageService { protected open fun initialiseStorageService(dir: Path): Pair<StorageService,CheckpointStorage> {
val attachments = makeAttachmentStorage(dir) val attachments = makeAttachmentStorage(dir)
val checkpointStorage = PerFileCheckpointStorage(dir.resolve("checkpoints")) val checkpointStorage = PerFileCheckpointStorage(dir.resolve("checkpoints"))
_servicesThatAcceptUploads += attachments _servicesThatAcceptUploads += attachments
val (identity, keypair) = obtainKeyPair(dir) val (identity, keypair) = obtainKeyPair(dir)
return constructStorageService(attachments, checkpointStorage, keypair, identity) return Pair(constructStorageService(attachments, keypair, identity),checkpointStorage)
} }
protected open fun constructStorageService(attachments: NodeAttachmentService, checkpointStorage: CheckpointStorage, keypair: KeyPair, identity: Party) = protected open fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party) =
StorageServiceImpl(attachments, checkpointStorage, keypair, identity) StorageServiceImpl(attachments, keypair, identity)
private fun obtainKeyPair(dir: Path): Pair<Party, KeyPair> { private fun obtainKeyPair(dir: Path): Pair<Party, KeyPair> {
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that // Load the private identity key, creating it if necessary. The identity key is a long term well known key that

View File

@ -11,7 +11,6 @@ import java.security.KeyPair
import java.util.* import java.util.*
open class StorageServiceImpl(override val attachments: AttachmentStorage, open class StorageServiceImpl(override val attachments: AttachmentStorage,
override val checkpointStorage: CheckpointStorage,
override val myLegalIdentityKey: KeyPair, override val myLegalIdentityKey: KeyPair,
override val myLegalIdentity: Party = Party("Unit test party", myLegalIdentityKey.public), override val myLegalIdentity: Party = Party("Unit test party", myLegalIdentityKey.public),
// This parameter is for unit tests that want to observe operation details. // This parameter is for unit tests that want to observe operation details.

View File

@ -91,7 +91,7 @@ class MockCheckpointStorage : CheckpointStorage {
@ThreadSafe @ThreadSafe
class MockStorageService : StorageServiceImpl(MockAttachmentStorage(), MockCheckpointStorage(), generateKeyPair()) class MockStorageService : StorageServiceImpl(MockAttachmentStorage(), generateKeyPair())
class MockServices( class MockServices(
customWallet: WalletService? = null, customWallet: WalletService? = null,

View File

@ -1,21 +1,23 @@
package core.messaging package core.messaging
import com.google.common.util.concurrent.ListenableFuture
import contracts.Cash import contracts.Cash
import contracts.CommercialPaper import contracts.CommercialPaper
import core.*
import core.contracts.* import core.contracts.*
import core.crypto.Party import core.crypto.Party
import core.crypto.SecureHash import core.crypto.SecureHash
import core.days
import core.node.NodeConfiguration import core.node.NodeConfiguration
import core.node.NodeInfo import core.node.NodeInfo
import core.node.ServiceHub import core.node.ServiceHub
import core.node.services.NodeAttachmentService import core.node.services.NodeAttachmentService
import core.node.services.ServiceType import core.node.services.ServiceType
import core.node.storage.CheckpointStorage
import core.node.subsystems.NodeWalletService import core.node.subsystems.NodeWalletService
import core.node.subsystems.StorageServiceImpl import core.node.subsystems.StorageServiceImpl
import core.node.subsystems.Wallet import core.node.subsystems.Wallet
import core.node.subsystems.WalletImpl import core.node.subsystems.WalletImpl
import core.random63BitValue
import core.seconds
import core.testing.InMemoryMessagingNetwork import core.testing.InMemoryMessagingNetwork
import core.testing.MockNetwork import core.testing.MockNetwork
import core.testutils.* import core.testutils.*
@ -79,7 +81,7 @@ class TwoPartyTradeProtocolTests {
val buyerSessionID = random63BitValue() val buyerSessionID = random63BitValue()
val aliceResult = TwoPartyTradeProtocol.runSeller( val aliceResult = runSeller(
aliceNode.smm, aliceNode.smm,
notaryNode.info, notaryNode.info,
bobNode.net.myAddress, bobNode.net.myAddress,
@ -88,7 +90,7 @@ class TwoPartyTradeProtocolTests {
ALICE_KEY, ALICE_KEY,
buyerSessionID buyerSessionID
) )
val bobResult = TwoPartyTradeProtocol.runBuyer( val bobResult = runBuyer(
bobNode.smm, bobNode.smm,
notaryNode.info, notaryNode.info,
aliceNode.net.myAddress, aliceNode.net.myAddress,
@ -104,8 +106,8 @@ class TwoPartyTradeProtocolTests {
aliceNode.stop() aliceNode.stop()
bobNode.stop() bobNode.stop()
assertThat(aliceNode.storage.checkpointStorage.checkpoints).isEmpty() assertThat(aliceNode.checkpointStorage.checkpoints).isEmpty()
assertThat(bobNode.storage.checkpointStorage.checkpoints).isEmpty() assertThat(bobNode.checkpointStorage.checkpoints).isEmpty()
} }
} }
@ -129,7 +131,7 @@ class TwoPartyTradeProtocolTests {
val buyerSessionID = random63BitValue() val buyerSessionID = random63BitValue()
val aliceFuture = TwoPartyTradeProtocol.runSeller( val aliceFuture = runSeller(
aliceNode.smm, aliceNode.smm,
notaryNode.info, notaryNode.info,
bobAddr, bobAddr,
@ -138,7 +140,7 @@ class TwoPartyTradeProtocolTests {
ALICE_KEY, ALICE_KEY,
buyerSessionID buyerSessionID
) )
TwoPartyTradeProtocol.runBuyer( runBuyer(
bobNode.smm, bobNode.smm,
notaryNode.info, notaryNode.info,
aliceAddr, aliceAddr,
@ -162,7 +164,7 @@ class TwoPartyTradeProtocolTests {
pumpBob() pumpBob()
// OK, now Bob has sent the partial transaction back to Alice and is waiting for Alice's signature. // OK, now Bob has sent the partial transaction back to Alice and is waiting for Alice's signature.
assertThat(bobNode.storage.checkpointStorage.checkpoints).hasSize(1) assertThat(bobNode.checkpointStorage.checkpoints).hasSize(1)
// TODO: remove once validated transactions are persisted to disk // TODO: remove once validated transactions are persisted to disk
val recordedTransactions = bobNode.storage.validatedTransactions val recordedTransactions = bobNode.storage.validatedTransactions
@ -208,15 +210,31 @@ class TwoPartyTradeProtocolTests {
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
return object : MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, id, keyPair) { return object : MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, id, keyPair) {
// That constructs the storage service object in a customised way ... // That constructs the storage service object in a customised way ...
override fun constructStorageService(attachments: NodeAttachmentService, checkpointStorage: CheckpointStorage, keypair: KeyPair, identity: Party): StorageServiceImpl { override fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party): StorageServiceImpl {
// To use RecordingMaps instead of ordinary HashMaps. // To use RecordingMaps instead of ordinary HashMaps.
return StorageServiceImpl(attachments, checkpointStorage, keypair, identity, { tableName -> name }) return StorageServiceImpl(attachments, keypair, identity, { tableName -> name })
} }
} }
} }
}, true, name, keyPair) }, true, name, keyPair)
} }
private fun runSeller(smm: StateMachineManager, notary: NodeInfo,
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount,
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<SignedTransaction> {
val seller = TwoPartyTradeProtocol.Seller(otherSide, notary, assetToSell, price, myKeyPair, buyerSessionID)
return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.seller", seller)
}
private fun runBuyer(smm: StateMachineManager, notaryNode: NodeInfo,
otherSide: SingleMessageRecipient, acceptablePrice: Amount, typeToBuy: Class<out OwnableState>,
sessionID: Long): ListenableFuture<SignedTransaction> {
val buyer = TwoPartyTradeProtocol.Buyer(otherSide, notaryNode.identity, acceptablePrice, typeToBuy, sessionID)
return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.buyer", buyer)
}
@Test @Test
fun checkDependenciesOfSaleAssetAreResolved() { fun checkDependenciesOfSaleAssetAreResolved() {
transactionGroupFor<ContractState> { transactionGroupFor<ContractState> {
@ -243,7 +261,7 @@ class TwoPartyTradeProtocolTests {
net.runNetwork() // Clear network map registration messages net.runNetwork() // Clear network map registration messages
TwoPartyTradeProtocol.runSeller( runSeller(
aliceNode.smm, aliceNode.smm,
notaryNode.info, notaryNode.info,
bobNode.net.myAddress, bobNode.net.myAddress,
@ -252,7 +270,7 @@ class TwoPartyTradeProtocolTests {
ALICE_KEY, ALICE_KEY,
buyerSessionID buyerSessionID
) )
TwoPartyTradeProtocol.runBuyer( runBuyer(
bobNode.smm, bobNode.smm,
notaryNode.info, notaryNode.info,
aliceNode.net.myAddress, aliceNode.net.myAddress,
@ -356,7 +374,7 @@ class TwoPartyTradeProtocolTests {
net.runNetwork() // Clear network map registration messages net.runNetwork() // Clear network map registration messages
val aliceResult = TwoPartyTradeProtocol.runSeller( val aliceResult = runSeller(
aliceNode.smm, aliceNode.smm,
notaryNode.info, notaryNode.info,
bobAddr, bobAddr,
@ -365,7 +383,7 @@ class TwoPartyTradeProtocolTests {
ALICE_KEY, ALICE_KEY,
buyerSessionID buyerSessionID
) )
val bobResult = TwoPartyTradeProtocol.runBuyer( val bobResult = runBuyer(
bobNode.smm, bobNode.smm,
notaryNode.info, notaryNode.info,
aliceAddr, aliceAddr,