mirror of
https://github.com/corda/corda.git
synced 2025-06-23 01:19:00 +00:00
Add StateMachineRunId, type for SMM Changes
This commit is contained in:
@ -3,6 +3,7 @@ package com.r3corda.client.model
|
|||||||
import com.r3corda.client.fxutils.foldToObservableList
|
import com.r3corda.client.fxutils.foldToObservableList
|
||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
import com.r3corda.core.transactions.LedgerTransaction
|
import com.r3corda.core.transactions.LedgerTransaction
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.node.services.monitor.ServiceToClientEvent
|
import com.r3corda.node.services.monitor.ServiceToClientEvent
|
||||||
import com.r3corda.node.services.monitor.TransactionBuildResult
|
import com.r3corda.node.services.monitor.TransactionBuildResult
|
||||||
import com.r3corda.node.utilities.AddOrRemove
|
import com.r3corda.node.utilities.AddOrRemove
|
||||||
@ -16,7 +17,7 @@ import java.time.Instant
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
interface GatheredTransactionData {
|
interface GatheredTransactionData {
|
||||||
val fiberId: ObservableValue<Long?>
|
val stateMachineRunId: ObservableValue<StateMachineRunId?>
|
||||||
val uuid: ObservableValue<UUID?>
|
val uuid: ObservableValue<UUID?>
|
||||||
val protocolStatus: ObservableValue<ProtocolStatus?>
|
val protocolStatus: ObservableValue<ProtocolStatus?>
|
||||||
val stateMachineStatus: ObservableValue<StateMachineStatus?>
|
val stateMachineStatus: ObservableValue<StateMachineStatus?>
|
||||||
@ -42,7 +43,7 @@ sealed class StateMachineStatus(val stateMachineName: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class GatheredTransactionDataWritable(
|
data class GatheredTransactionDataWritable(
|
||||||
override val fiberId: SimpleObjectProperty<Long?> = SimpleObjectProperty(null),
|
override val stateMachineRunId: SimpleObjectProperty<StateMachineRunId?> = SimpleObjectProperty(null),
|
||||||
override val uuid: SimpleObjectProperty<UUID?> = SimpleObjectProperty(null),
|
override val uuid: SimpleObjectProperty<UUID?> = SimpleObjectProperty(null),
|
||||||
override val stateMachineStatus: SimpleObjectProperty<StateMachineStatus?> = SimpleObjectProperty(null),
|
override val stateMachineStatus: SimpleObjectProperty<StateMachineStatus?> = SimpleObjectProperty(null),
|
||||||
override val protocolStatus: SimpleObjectProperty<ProtocolStatus?> = SimpleObjectProperty(null),
|
override val protocolStatus: SimpleObjectProperty<ProtocolStatus?> = SimpleObjectProperty(null),
|
||||||
@ -85,7 +86,7 @@ class GatheredTransactionDataModel {
|
|||||||
is ServiceToClientEvent.OutputState -> {}
|
is ServiceToClientEvent.OutputState -> {}
|
||||||
is ServiceToClientEvent.StateMachine -> {
|
is ServiceToClientEvent.StateMachine -> {
|
||||||
newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent,
|
newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent,
|
||||||
fiberId = serviceToClientEvent.fiberId,
|
stateMachineRunId = serviceToClientEvent.stateMachineRunId,
|
||||||
tweak = {
|
tweak = {
|
||||||
stateMachineStatus.set(when (serviceToClientEvent.addOrRemove) {
|
stateMachineStatus.set(when (serviceToClientEvent.addOrRemove) {
|
||||||
AddOrRemove.ADD -> StateMachineStatus.Added(serviceToClientEvent.label)
|
AddOrRemove.ADD -> StateMachineStatus.Added(serviceToClientEvent.label)
|
||||||
@ -96,7 +97,7 @@ class GatheredTransactionDataModel {
|
|||||||
}
|
}
|
||||||
is ServiceToClientEvent.Progress -> {
|
is ServiceToClientEvent.Progress -> {
|
||||||
newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent,
|
newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent,
|
||||||
fiberId = serviceToClientEvent.fiberId,
|
stateMachineRunId = serviceToClientEvent.stateMachineRunId,
|
||||||
tweak = {
|
tweak = {
|
||||||
protocolStatus.set(ProtocolStatus(serviceToClientEvent.message))
|
protocolStatus.set(ProtocolStatus(serviceToClientEvent.message))
|
||||||
}
|
}
|
||||||
@ -106,8 +107,8 @@ class GatheredTransactionDataModel {
|
|||||||
val state = serviceToClientEvent.state
|
val state = serviceToClientEvent.state
|
||||||
newUuidTransactionStateOrModify(transactionStates, serviceToClientEvent,
|
newUuidTransactionStateOrModify(transactionStates, serviceToClientEvent,
|
||||||
uuid = serviceToClientEvent.id,
|
uuid = serviceToClientEvent.id,
|
||||||
fiberId = when (state) {
|
stateMachineRunId = when (state) {
|
||||||
is TransactionBuildResult.ProtocolStarted -> state.fiberId
|
is TransactionBuildResult.ProtocolStarted -> state.stateMachineId
|
||||||
is TransactionBuildResult.Failed -> null
|
is TransactionBuildResult.Failed -> null
|
||||||
},
|
},
|
||||||
transactionId = when (state) {
|
transactionId = when (state) {
|
||||||
@ -160,13 +161,13 @@ class GatheredTransactionDataModel {
|
|||||||
private fun newFiberIdTransactionStateOrModify(
|
private fun newFiberIdTransactionStateOrModify(
|
||||||
transactionStates: ObservableList<GatheredTransactionDataWritable>,
|
transactionStates: ObservableList<GatheredTransactionDataWritable>,
|
||||||
event: ServiceToClientEvent,
|
event: ServiceToClientEvent,
|
||||||
fiberId: Long,
|
stateMachineRunId: StateMachineRunId,
|
||||||
tweak: GatheredTransactionDataWritable.() -> Unit
|
tweak: GatheredTransactionDataWritable.() -> Unit
|
||||||
) {
|
) {
|
||||||
val index = transactionStates.indexOfFirst { it.fiberId.value == fiberId }
|
val index = transactionStates.indexOfFirst { it.stateMachineRunId.value == stateMachineRunId }
|
||||||
val state = if (index < 0) {
|
val state = if (index < 0) {
|
||||||
val newState = GatheredTransactionDataWritable(
|
val newState = GatheredTransactionDataWritable(
|
||||||
fiberId = SimpleObjectProperty(fiberId),
|
stateMachineRunId = SimpleObjectProperty(stateMachineRunId),
|
||||||
lastUpdate = SimpleObjectProperty(event.time)
|
lastUpdate = SimpleObjectProperty(event.time)
|
||||||
)
|
)
|
||||||
tweak(newState)
|
tweak(newState)
|
||||||
@ -185,19 +186,19 @@ class GatheredTransactionDataModel {
|
|||||||
transactionStates: ObservableList<GatheredTransactionDataWritable>,
|
transactionStates: ObservableList<GatheredTransactionDataWritable>,
|
||||||
event: ServiceToClientEvent,
|
event: ServiceToClientEvent,
|
||||||
uuid: UUID,
|
uuid: UUID,
|
||||||
fiberId: Long?,
|
stateMachineRunId: StateMachineRunId?,
|
||||||
transactionId: SecureHash?,
|
transactionId: SecureHash?,
|
||||||
tweak: GatheredTransactionDataWritable.() -> Unit
|
tweak: GatheredTransactionDataWritable.() -> Unit
|
||||||
) {
|
) {
|
||||||
val index = transactionStates.indexOfFirst {
|
val index = transactionStates.indexOfFirst {
|
||||||
it.uuid.value == uuid ||
|
it.uuid.value == uuid ||
|
||||||
(fiberId != null && it.fiberId.value == fiberId) ||
|
(stateMachineRunId != null && it.stateMachineRunId.value == stateMachineRunId) ||
|
||||||
(transactionId != null && it.transaction.value?.id == transactionId)
|
(transactionId != null && it.transaction.value?.id == transactionId)
|
||||||
}
|
}
|
||||||
val state = if (index < 0) {
|
val state = if (index < 0) {
|
||||||
val newState = GatheredTransactionDataWritable(
|
val newState = GatheredTransactionDataWritable(
|
||||||
uuid = SimpleObjectProperty(uuid),
|
uuid = SimpleObjectProperty(uuid),
|
||||||
fiberId = SimpleObjectProperty(fiberId),
|
stateMachineRunId = SimpleObjectProperty(stateMachineRunId),
|
||||||
lastUpdate = SimpleObjectProperty(event.time)
|
lastUpdate = SimpleObjectProperty(event.time)
|
||||||
)
|
)
|
||||||
tweak(newState)
|
tweak(newState)
|
||||||
|
@ -11,6 +11,7 @@ import com.r3corda.core.contracts.TransactionType
|
|||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.node.ServiceHub
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.node.services.Vault
|
import com.r3corda.core.node.services.Vault
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.core.serialization.OpaqueBytes
|
import com.r3corda.core.serialization.OpaqueBytes
|
||||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
@ -6,6 +6,13 @@ import com.r3corda.core.crypto.Party
|
|||||||
import com.r3corda.core.node.ServiceHub
|
import com.r3corda.core.node.ServiceHub
|
||||||
import com.r3corda.core.utilities.UntrustworthyData
|
import com.r3corda.core.utilities.UntrustworthyData
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
data class StateMachineRunId private constructor(val uuid: UUID) {
|
||||||
|
companion object {
|
||||||
|
fun createRandom() = StateMachineRunId(UUID.randomUUID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface of [ProtocolStateMachineImpl] exposing methods and properties required by ProtocolLogic for compilation.
|
* The interface of [ProtocolStateMachineImpl] exposing methods and properties required by ProtocolLogic for compilation.
|
||||||
@ -30,6 +37,8 @@ interface ProtocolStateMachine<R> {
|
|||||||
|
|
||||||
/** Unique ID for this machine, valid only while it is in memory. */
|
/** Unique ID for this machine, valid only while it is in memory. */
|
||||||
val machineId: Long
|
val machineId: Long
|
||||||
|
/** Unique ID for this machine run, valid across restarts */
|
||||||
|
val stateMachineRunId: StateMachineRunId
|
||||||
/** This future will complete when the call method returns. */
|
/** This future will complete when the call method returns. */
|
||||||
val resultFuture: ListenableFuture<R>
|
val resultFuture: ListenableFuture<R>
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import com.r3corda.core.crypto.Party
|
|||||||
import com.r3corda.core.crypto.SecureHash
|
import com.r3corda.core.crypto.SecureHash
|
||||||
import com.r3corda.core.crypto.toStringShort
|
import com.r3corda.core.crypto.toStringShort
|
||||||
import com.r3corda.core.transactions.LedgerTransaction
|
import com.r3corda.core.transactions.LedgerTransaction
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.explorer.AmountDiff
|
import com.r3corda.explorer.AmountDiff
|
||||||
import com.r3corda.explorer.formatters.AmountFormatter
|
import com.r3corda.explorer.formatters.AmountFormatter
|
||||||
import com.r3corda.explorer.formatters.Formatter
|
import com.r3corda.explorer.formatters.Formatter
|
||||||
@ -46,7 +47,7 @@ class TransactionViewer: View() {
|
|||||||
// Top half (transactions table)
|
// Top half (transactions table)
|
||||||
private val transactionViewTable: TableView<ViewerNode> by fxid()
|
private val transactionViewTable: TableView<ViewerNode> by fxid()
|
||||||
private val transactionViewTransactionId: TableColumn<ViewerNode, String> by fxid()
|
private val transactionViewTransactionId: TableColumn<ViewerNode, String> by fxid()
|
||||||
private val transactionViewFiberId: TableColumn<ViewerNode, String> by fxid()
|
private val transactionViewStateMachineId: TableColumn<ViewerNode, String> by fxid()
|
||||||
private val transactionViewClientUuid: TableColumn<ViewerNode, String> by fxid()
|
private val transactionViewClientUuid: TableColumn<ViewerNode, String> by fxid()
|
||||||
private val transactionViewTransactionStatus: TableColumn<ViewerNode, TransactionCreateStatus?> by fxid()
|
private val transactionViewTransactionStatus: TableColumn<ViewerNode, TransactionCreateStatus?> by fxid()
|
||||||
private val transactionViewProtocolStatus: TableColumn<ViewerNode, String> by fxid()
|
private val transactionViewProtocolStatus: TableColumn<ViewerNode, String> by fxid()
|
||||||
@ -98,7 +99,7 @@ class TransactionViewer: View() {
|
|||||||
*/
|
*/
|
||||||
data class ViewerNode(
|
data class ViewerNode(
|
||||||
val transactionId: ObservableValue<SecureHash?>,
|
val transactionId: ObservableValue<SecureHash?>,
|
||||||
val fiberId: ObservableValue<Long?>,
|
val stateMachineRunId: ObservableValue<StateMachineRunId?>,
|
||||||
val clientUuid: ObservableValue<UUID?>,
|
val clientUuid: ObservableValue<UUID?>,
|
||||||
val originator: ObservableValue<String>,
|
val originator: ObservableValue<String>,
|
||||||
val transactionStatus: ObservableValue<TransactionCreateStatus?>,
|
val transactionStatus: ObservableValue<TransactionCreateStatus?>,
|
||||||
@ -125,7 +126,7 @@ class TransactionViewer: View() {
|
|||||||
private val viewerNodes = gatheredTransactionDataList.map {
|
private val viewerNodes = gatheredTransactionDataList.map {
|
||||||
ViewerNode(
|
ViewerNode(
|
||||||
transactionId = it.transaction.map { it?.id },
|
transactionId = it.transaction.map { it?.id },
|
||||||
fiberId = it.fiberId,
|
stateMachineRunId = it.stateMachineRunId,
|
||||||
clientUuid = it.uuid,
|
clientUuid = it.uuid,
|
||||||
/**
|
/**
|
||||||
* We can't really do any better based on uuid, we need to store explicit data for this TODO
|
* We can't really do any better based on uuid, we need to store explicit data for this TODO
|
||||||
@ -288,7 +289,7 @@ class TransactionViewer: View() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transactionViewTransactionId.setCellValueFactory { it.value.transactionId.map { "${it ?: ""}" } }
|
transactionViewTransactionId.setCellValueFactory { it.value.transactionId.map { "${it ?: ""}" } }
|
||||||
transactionViewFiberId.setCellValueFactory { it.value.fiberId.map { "${it?: ""}" } }
|
transactionViewStateMachineId.setCellValueFactory { it.value.stateMachineRunId.map { "${it?.uuid ?: ""}" } }
|
||||||
transactionViewClientUuid.setCellValueFactory { it.value.clientUuid.map { "${it ?: ""}" } }
|
transactionViewClientUuid.setCellValueFactory { it.value.clientUuid.map { "${it ?: ""}" } }
|
||||||
transactionViewProtocolStatus.setCellValueFactory { it.value.protocolStatus.map { "${it ?: ""}" } }
|
transactionViewProtocolStatus.setCellValueFactory { it.value.protocolStatus.map { "${it ?: ""}" } }
|
||||||
transactionViewTransactionStatus.setCellValueFactory { it.value.transactionStatus }
|
transactionViewTransactionStatus.setCellValueFactory { it.value.transactionStatus }
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
<TableView fx:id="transactionViewTable" prefHeight="200.0" prefWidth="200.0">
|
<TableView fx:id="transactionViewTable" prefHeight="200.0" prefWidth="200.0">
|
||||||
<columns>
|
<columns>
|
||||||
<TableColumn fx:id="transactionViewTransactionId" prefWidth="75.0" text="Transaction ID" />
|
<TableColumn fx:id="transactionViewTransactionId" prefWidth="75.0" text="Transaction ID" />
|
||||||
<TableColumn fx:id="transactionViewFiberId" prefWidth="187.0" text="Fiber ID" />
|
<TableColumn fx:id="transactionViewStateMachineId" prefWidth="187.0" text="StateMachine ID" />
|
||||||
<TableColumn fx:id="transactionViewClientUuid" prefWidth="75.0" text="Client UUID" />
|
<TableColumn fx:id="transactionViewClientUuid" prefWidth="75.0" text="Client UUID" />
|
||||||
<TableColumn fx:id="transactionViewTransactionStatus" prefWidth="75.0" text="Transaction status" />
|
<TableColumn fx:id="transactionViewTransactionStatus" prefWidth="75.0" text="Transaction status" />
|
||||||
<TableColumn fx:id="transactionViewProtocolStatus" prefWidth="75.0" text="Protocol status" />
|
<TableColumn fx:id="transactionViewProtocolStatus" prefWidth="75.0" text="Protocol status" />
|
||||||
|
@ -36,10 +36,7 @@ import com.r3corda.node.services.network.NetworkMapService
|
|||||||
import com.r3corda.node.services.network.NetworkMapService.Companion.REGISTER_PROTOCOL_TOPIC
|
import com.r3corda.node.services.network.NetworkMapService.Companion.REGISTER_PROTOCOL_TOPIC
|
||||||
import com.r3corda.node.services.network.NodeRegistration
|
import com.r3corda.node.services.network.NodeRegistration
|
||||||
import com.r3corda.node.services.network.PersistentNetworkMapService
|
import com.r3corda.node.services.network.PersistentNetworkMapService
|
||||||
import com.r3corda.node.services.persistence.NodeAttachmentService
|
import com.r3corda.node.services.persistence.*
|
||||||
import com.r3corda.node.services.persistence.PerFileCheckpointStorage
|
|
||||||
import com.r3corda.node.services.persistence.PerFileTransactionStorage
|
|
||||||
import com.r3corda.node.services.persistence.StorageServiceImpl
|
|
||||||
import com.r3corda.node.services.statemachine.StateMachineManager
|
import com.r3corda.node.services.statemachine.StateMachineManager
|
||||||
import com.r3corda.node.services.transactions.NotaryService
|
import com.r3corda.node.services.transactions.NotaryService
|
||||||
import com.r3corda.node.services.transactions.SimpleNotaryService
|
import com.r3corda.node.services.transactions.SimpleNotaryService
|
||||||
|
@ -7,6 +7,7 @@ import com.r3corda.core.node.ServiceHub
|
|||||||
import com.r3corda.core.node.services.TxWritableStorageService
|
import com.r3corda.core.node.services.TxWritableStorageService
|
||||||
import com.r3corda.core.protocols.ProtocolLogic
|
import com.r3corda.core.protocols.ProtocolLogic
|
||||||
import com.r3corda.core.protocols.ProtocolLogicRefFactory
|
import com.r3corda.core.protocols.ProtocolLogicRefFactory
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
|
|
||||||
interface MessagingServiceInternal : MessagingService {
|
interface MessagingServiceInternal : MessagingService {
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ package com.r3corda.node.services.monitor
|
|||||||
|
|
||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
import com.r3corda.core.transactions.LedgerTransaction
|
import com.r3corda.core.transactions.LedgerTransaction
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.node.utilities.AddOrRemove
|
import com.r3corda.node.utilities.AddOrRemove
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -22,13 +23,13 @@ sealed class ServiceToClientEvent(val time: Instant) {
|
|||||||
}
|
}
|
||||||
class StateMachine(
|
class StateMachine(
|
||||||
time: Instant,
|
time: Instant,
|
||||||
val fiberId: Long,
|
val stateMachineRunId: StateMachineRunId,
|
||||||
val label: String,
|
val label: String,
|
||||||
val addOrRemove: AddOrRemove
|
val addOrRemove: AddOrRemove
|
||||||
) : ServiceToClientEvent(time) {
|
) : ServiceToClientEvent(time) {
|
||||||
override fun toString() = "StateMachine($label, ${addOrRemove.name})"
|
override fun toString() = "StateMachine($label, ${addOrRemove.name})"
|
||||||
}
|
}
|
||||||
class Progress(time: Instant, val fiberId: Long, val message: String) : ServiceToClientEvent(time) {
|
class Progress(time: Instant, val stateMachineRunId: StateMachineRunId, val message: String) : ServiceToClientEvent(time) {
|
||||||
override fun toString() = "Progress($message)"
|
override fun toString() = "Progress($message)"
|
||||||
}
|
}
|
||||||
class TransactionBuild(time: Instant, val id: UUID, val state: TransactionBuildResult) : ServiceToClientEvent(time) {
|
class TransactionBuild(time: Instant, val id: UUID, val state: TransactionBuildResult) : ServiceToClientEvent(time) {
|
||||||
@ -46,7 +47,7 @@ sealed class TransactionBuildResult {
|
|||||||
*
|
*
|
||||||
* @param transaction the transaction created as a result, in the case where the protocol has completed.
|
* @param transaction the transaction created as a result, in the case where the protocol has completed.
|
||||||
*/
|
*/
|
||||||
class ProtocolStarted(val fiberId: Long, val transaction: LedgerTransaction?, val message: String?) : TransactionBuildResult() {
|
class ProtocolStarted(val stateMachineId: StateMachineRunId, val transaction: LedgerTransaction?, val message: String?) : TransactionBuildResult() {
|
||||||
override fun toString() = "Started($message)"
|
override fun toString() = "Started($message)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import com.r3corda.core.messaging.createMessage
|
|||||||
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||||
import com.r3corda.core.node.services.Vault
|
import com.r3corda.core.node.services.Vault
|
||||||
import com.r3corda.core.protocols.ProtocolLogic
|
import com.r3corda.core.protocols.ProtocolLogic
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.core.serialization.serialize
|
import com.r3corda.core.serialization.serialize
|
||||||
import com.r3corda.core.transactions.LedgerTransaction
|
import com.r3corda.core.transactions.LedgerTransaction
|
||||||
import com.r3corda.core.transactions.TransactionBuilder
|
import com.r3corda.core.transactions.TransactionBuilder
|
||||||
@ -63,15 +64,15 @@ class NodeMonitorService(services: ServiceHubInternal, val smm: StateMachineMana
|
|||||||
services.storageService.validatedTransactions.updates.subscribe { tx -> notifyTransaction(tx.tx.toLedgerTransaction(services)) }
|
services.storageService.validatedTransactions.updates.subscribe { tx -> notifyTransaction(tx.tx.toLedgerTransaction(services)) }
|
||||||
services.vaultService.updates.subscribe { update -> notifyVaultUpdate(update) }
|
services.vaultService.updates.subscribe { update -> notifyVaultUpdate(update) }
|
||||||
smm.changes.subscribe { change ->
|
smm.changes.subscribe { change ->
|
||||||
val fiberId: Long = change.third
|
val stateMachineRunId: StateMachineRunId = change.stateMachineRunId
|
||||||
val logic: ProtocolLogic<*> = change.first
|
val logic: ProtocolLogic<*> = change.logic
|
||||||
val progressTracker = logic.progressTracker
|
val progressTracker = logic.progressTracker
|
||||||
|
|
||||||
notifyEvent(ServiceToClientEvent.StateMachine(Instant.now(), fiberId, logic.javaClass.name, change.second))
|
notifyEvent(ServiceToClientEvent.StateMachine(Instant.now(), stateMachineRunId, logic.javaClass.name, change.addOrRemove))
|
||||||
if (progressTracker != null) {
|
if (progressTracker != null) {
|
||||||
when (change.second) {
|
when (change.addOrRemove) {
|
||||||
AddOrRemove.ADD -> progressTracker.changes.subscribe { progress ->
|
AddOrRemove.ADD -> progressTracker.changes.subscribe { progress ->
|
||||||
notifyEvent(ServiceToClientEvent.Progress(Instant.now(), fiberId, progress.toString()))
|
notifyEvent(ServiceToClientEvent.Progress(Instant.now(), stateMachineRunId, progress.toString()))
|
||||||
}
|
}
|
||||||
AddOrRemove.REMOVE -> {
|
AddOrRemove.REMOVE -> {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
@ -168,7 +169,7 @@ class NodeMonitorService(services: ServiceHubInternal, val smm: StateMachineMana
|
|||||||
val tx = builder.toSignedTransaction(checkSufficientSignatures = false)
|
val tx = builder.toSignedTransaction(checkSufficientSignatures = false)
|
||||||
val protocol = FinalityProtocol(tx, setOf(req), setOf(req.recipient))
|
val protocol = FinalityProtocol(tx, setOf(req), setOf(req.recipient))
|
||||||
return TransactionBuildResult.ProtocolStarted(
|
return TransactionBuildResult.ProtocolStarted(
|
||||||
smm.add(BroadcastTransactionProtocol.TOPIC, protocol).machineId,
|
smm.add(BroadcastTransactionProtocol.TOPIC, protocol).stateMachineRunId,
|
||||||
tx.tx.toLedgerTransaction(services),
|
tx.tx.toLedgerTransaction(services),
|
||||||
"Cash payment transaction generated"
|
"Cash payment transaction generated"
|
||||||
)
|
)
|
||||||
@ -202,7 +203,7 @@ class NodeMonitorService(services: ServiceHubInternal, val smm: StateMachineMana
|
|||||||
val tx = builder.toSignedTransaction(checkSufficientSignatures = false)
|
val tx = builder.toSignedTransaction(checkSufficientSignatures = false)
|
||||||
val protocol = FinalityProtocol(tx, setOf(req), participants)
|
val protocol = FinalityProtocol(tx, setOf(req), participants)
|
||||||
return TransactionBuildResult.ProtocolStarted(
|
return TransactionBuildResult.ProtocolStarted(
|
||||||
smm.add(BroadcastTransactionProtocol.TOPIC, protocol).machineId,
|
smm.add(BroadcastTransactionProtocol.TOPIC, protocol).stateMachineRunId,
|
||||||
tx.tx.toLedgerTransaction(services),
|
tx.tx.toLedgerTransaction(services),
|
||||||
"Cash destruction transaction generated"
|
"Cash destruction transaction generated"
|
||||||
)
|
)
|
||||||
@ -221,7 +222,7 @@ class NodeMonitorService(services: ServiceHubInternal, val smm: StateMachineMana
|
|||||||
// Issuance transactions do not need to be notarised, so we can skip directly to broadcasting it
|
// Issuance transactions do not need to be notarised, so we can skip directly to broadcasting it
|
||||||
val protocol = BroadcastTransactionProtocol(tx, setOf(req), setOf(req.recipient))
|
val protocol = BroadcastTransactionProtocol(tx, setOf(req), setOf(req.recipient))
|
||||||
return TransactionBuildResult.ProtocolStarted(
|
return TransactionBuildResult.ProtocolStarted(
|
||||||
smm.add(BroadcastTransactionProtocol.TOPIC, protocol).machineId,
|
smm.add(BroadcastTransactionProtocol.TOPIC, protocol).stateMachineRunId,
|
||||||
tx.tx.toLedgerTransaction(services),
|
tx.tx.toLedgerTransaction(services),
|
||||||
"Cash issuance completed"
|
"Cash issuance completed"
|
||||||
)
|
)
|
||||||
|
@ -9,6 +9,7 @@ import com.google.common.util.concurrent.SettableFuture
|
|||||||
import com.r3corda.core.crypto.Party
|
import com.r3corda.core.crypto.Party
|
||||||
import com.r3corda.core.protocols.ProtocolLogic
|
import com.r3corda.core.protocols.ProtocolLogic
|
||||||
import com.r3corda.core.protocols.ProtocolStateMachine
|
import com.r3corda.core.protocols.ProtocolStateMachine
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.core.utilities.UntrustworthyData
|
import com.r3corda.core.utilities.UntrustworthyData
|
||||||
import com.r3corda.core.utilities.trace
|
import com.r3corda.core.utilities.trace
|
||||||
import com.r3corda.node.services.api.ServiceHubInternal
|
import com.r3corda.node.services.api.ServiceHubInternal
|
||||||
@ -28,7 +29,8 @@ import java.util.concurrent.ExecutionException
|
|||||||
* a protocol invokes a sub-protocol, then it will pass along the PSM to the child. The call method of the topmost
|
* a protocol invokes a sub-protocol, then it will pass along the PSM to the child. The call method of the topmost
|
||||||
* logic element gets to return the value that the entire state machine resolves to.
|
* logic element gets to return the value that the entire state machine resolves to.
|
||||||
*/
|
*/
|
||||||
class ProtocolStateMachineImpl<R>(val logic: ProtocolLogic<R>,
|
class ProtocolStateMachineImpl<R>(override val stateMachineRunId: StateMachineRunId,
|
||||||
|
val logic: ProtocolLogic<R>,
|
||||||
scheduler: FiberScheduler,
|
scheduler: FiberScheduler,
|
||||||
private val loggerName: String)
|
private val loggerName: String)
|
||||||
: Fiber<R>("protocol", scheduler), ProtocolStateMachine<R> {
|
: Fiber<R>("protocol", scheduler), ProtocolStateMachine<R> {
|
||||||
|
@ -7,12 +7,14 @@ import com.codahale.metrics.Gauge
|
|||||||
import com.esotericsoftware.kryo.Kryo
|
import com.esotericsoftware.kryo.Kryo
|
||||||
import com.google.common.base.Throwables
|
import com.google.common.base.Throwables
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import com.r3corda.core.ThreadBox
|
||||||
import com.r3corda.core.abbreviate
|
import com.r3corda.core.abbreviate
|
||||||
import com.r3corda.core.messaging.TopicSession
|
import com.r3corda.core.messaging.TopicSession
|
||||||
import com.r3corda.core.messaging.runOnNextMessage
|
import com.r3corda.core.messaging.runOnNextMessage
|
||||||
import com.r3corda.core.messaging.send
|
import com.r3corda.core.messaging.send
|
||||||
import com.r3corda.core.protocols.ProtocolLogic
|
import com.r3corda.core.protocols.ProtocolLogic
|
||||||
import com.r3corda.core.protocols.ProtocolStateMachine
|
import com.r3corda.core.protocols.ProtocolStateMachine
|
||||||
|
import com.r3corda.core.protocols.StateMachineRunId
|
||||||
import com.r3corda.core.serialization.*
|
import com.r3corda.core.serialization.*
|
||||||
import com.r3corda.core.then
|
import com.r3corda.core.then
|
||||||
import com.r3corda.core.utilities.ProgressTracker
|
import com.r3corda.core.utilities.ProgressTracker
|
||||||
@ -24,10 +26,10 @@ import com.r3corda.node.utilities.AddOrRemove
|
|||||||
import com.r3corda.node.utilities.AffinityExecutor
|
import com.r3corda.node.utilities.AffinityExecutor
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
|
import rx.subjects.UnicastSubject
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.Collections.synchronizedMap
|
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
|
|
||||||
@ -60,30 +62,43 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
|
|
||||||
val scheduler = FiberScheduler()
|
val scheduler = FiberScheduler()
|
||||||
|
|
||||||
|
data class Change(
|
||||||
|
val logic: ProtocolLogic<*>,
|
||||||
|
val addOrRemove: AddOrRemove,
|
||||||
|
val stateMachineRunId: StateMachineRunId
|
||||||
|
)
|
||||||
|
|
||||||
// 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(LinkedHashMap<ProtocolStateMachineImpl<*>, Checkpoint>())
|
private val mutex = ThreadBox(object {
|
||||||
|
var started = false
|
||||||
|
val stateMachines = LinkedHashMap<ProtocolStateMachineImpl<*>, Checkpoint>()
|
||||||
|
val changesPublisher = PublishSubject.create<Change>()
|
||||||
|
|
||||||
|
fun notifyChangeObservers(psm: ProtocolStateMachineImpl<*>, addOrRemove: AddOrRemove) {
|
||||||
|
changesPublisher.onNext(Change(psm.logic, addOrRemove, psm.stateMachineRunId))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Monitoring support.
|
// Monitoring support.
|
||||||
private val metrics = serviceHub.monitoringService.metrics
|
private val metrics = serviceHub.monitoringService.metrics
|
||||||
|
|
||||||
init {
|
init {
|
||||||
metrics.register("Protocols.InFlight", Gauge<Int> { stateMachines.size })
|
metrics.register("Protocols.InFlight", Gauge<Int> { mutex.content.stateMachines.size })
|
||||||
}
|
}
|
||||||
|
|
||||||
private val checkpointingMeter = metrics.meter("Protocols.Checkpointing Rate")
|
private val checkpointingMeter = metrics.meter("Protocols.Checkpointing Rate")
|
||||||
private val totalStartedProtocols = metrics.counter("Protocols.Started")
|
private val totalStartedProtocols = metrics.counter("Protocols.Started")
|
||||||
private val totalFinishedProtocols = metrics.counter("Protocols.Finished")
|
private val totalFinishedProtocols = metrics.counter("Protocols.Finished")
|
||||||
private var started = false
|
|
||||||
|
|
||||||
// Context for tokenized services in checkpoints
|
// Context for tokenized services in checkpoints
|
||||||
private val serializationContext = SerializeAsTokenContext(tokenizableServices, quasarKryo())
|
private val serializationContext = SerializeAsTokenContext(tokenizableServices, quasarKryo())
|
||||||
|
|
||||||
/** Returns a list of all state machines executing the given protocol logic at the top level (subprotocols do not count) */
|
/** Returns a list of all state machines executing the given protocol logic at the top level (subprotocols do not count) */
|
||||||
fun <P : ProtocolLogic<T>, T> findStateMachines(protocolClass: Class<P>): List<Pair<P, ListenableFuture<T>>> {
|
fun <P : ProtocolLogic<T>, T> findStateMachines(protocolClass: Class<P>): List<Pair<P, ListenableFuture<T>>> {
|
||||||
synchronized(stateMachines) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return stateMachines.keys
|
return mutex.locked {
|
||||||
|
stateMachines.keys
|
||||||
.map { it.logic }
|
.map { it.logic }
|
||||||
.filterIsInstance(protocolClass)
|
.filterIsInstance(protocolClass)
|
||||||
.map { it to (it.psm as ProtocolStateMachineImpl<T>).resultFuture }
|
.map { it to (it.psm as ProtocolStateMachineImpl<T>).resultFuture }
|
||||||
@ -91,19 +106,25 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
}
|
}
|
||||||
|
|
||||||
val allStateMachines: List<ProtocolLogic<*>>
|
val allStateMachines: List<ProtocolLogic<*>>
|
||||||
get() = stateMachines.keys.map { it.logic }
|
get() = mutex.locked { stateMachines.keys.map { it.logic } }
|
||||||
|
|
||||||
private val _changesPublisher = PublishSubject.create<Triple<ProtocolLogic<*>, AddOrRemove, Long>>()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An observable that emits triples of the changing protocol, the type of change, and a process-specific ID number
|
* An observable that emits triples of the changing protocol, the type of change, and a process-specific ID number
|
||||||
* which may change across restarts.
|
* which may change across restarts.
|
||||||
*/
|
*/
|
||||||
val changes: Observable<Triple<ProtocolLogic<*>, AddOrRemove, Long>>
|
val changes: Observable<Change>
|
||||||
get() = _changesPublisher
|
get() = mutex.content.changesPublisher
|
||||||
|
|
||||||
private fun notifyChangeObservers(psm: ProtocolStateMachineImpl<*>, change: AddOrRemove) {
|
/**
|
||||||
_changesPublisher.onNext(Triple(psm.logic, change, psm.id))
|
* Atomic get snapshot + subscribe. This is needed so we don't miss updates between subscriptions to [changes] and
|
||||||
|
* calls to [allStateMachines]
|
||||||
|
*/
|
||||||
|
fun getAllStateMachinesAndChanges(): Pair<List<ProtocolStateMachineImpl<*>>, Observable<Change>> {
|
||||||
|
return mutex.locked {
|
||||||
|
val bufferedChanges = UnicastSubject.create<Change>()
|
||||||
|
changesPublisher.subscribe(bufferedChanges)
|
||||||
|
Pair(stateMachines.keys.toList(), bufferedChanges)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to work around a small limitation in Quasar.
|
// Used to work around a small limitation in Quasar.
|
||||||
@ -122,7 +143,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
fun start() {
|
fun start() {
|
||||||
checkpointStorage.checkpoints.forEach { createFiberForCheckpoint(it) }
|
checkpointStorage.checkpoints.forEach { createFiberForCheckpoint(it) }
|
||||||
serviceHub.networkMapCache.mapServiceRegistered.then(executor) {
|
serviceHub.networkMapCache.mapServiceRegistered.then(executor) {
|
||||||
synchronized(started) {
|
mutex.locked {
|
||||||
started = true
|
started = true
|
||||||
stateMachines.forEach { restartFiber(it.key, it.value) }
|
stateMachines.forEach { restartFiber(it.key, it.value) }
|
||||||
}
|
}
|
||||||
@ -205,6 +226,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
}
|
}
|
||||||
psm.actionOnEnd = {
|
psm.actionOnEnd = {
|
||||||
psm.logic.progressTracker?.currentStep = ProgressTracker.DONE
|
psm.logic.progressTracker?.currentStep = ProgressTracker.DONE
|
||||||
|
mutex.locked {
|
||||||
val finalCheckpoint = stateMachines.remove(psm)
|
val finalCheckpoint = stateMachines.remove(psm)
|
||||||
if (finalCheckpoint != null) {
|
if (finalCheckpoint != null) {
|
||||||
checkpointStorage.removeCheckpoint(finalCheckpoint)
|
checkpointStorage.removeCheckpoint(finalCheckpoint)
|
||||||
@ -212,11 +234,14 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
totalFinishedProtocols.inc()
|
totalFinishedProtocols.inc()
|
||||||
notifyChangeObservers(psm, AddOrRemove.REMOVE)
|
notifyChangeObservers(psm, AddOrRemove.REMOVE)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
val checkpoint = startingCheckpoint()
|
val checkpoint = startingCheckpoint()
|
||||||
checkpoint.fiberCreated = true
|
checkpoint.fiberCreated = true
|
||||||
totalStartedProtocols.inc()
|
totalStartedProtocols.inc()
|
||||||
|
mutex.locked {
|
||||||
stateMachines[psm] = checkpoint
|
stateMachines[psm] = checkpoint
|
||||||
notifyChangeObservers(psm, AddOrRemove.ADD)
|
notifyChangeObservers(psm, AddOrRemove.ADD)
|
||||||
|
}
|
||||||
return checkpoint
|
return checkpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,14 +251,15 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
* restarted with checkpointed state machines in the storage service.
|
* restarted with checkpointed state machines in the storage service.
|
||||||
*/
|
*/
|
||||||
fun <T> add(loggerName: String, logic: ProtocolLogic<T>): ProtocolStateMachine<T> {
|
fun <T> add(loggerName: String, logic: ProtocolLogic<T>): ProtocolStateMachine<T> {
|
||||||
val fiber = ProtocolStateMachineImpl(logic, scheduler, loggerName)
|
val id = StateMachineRunId.createRandom()
|
||||||
|
val fiber = ProtocolStateMachineImpl(id, logic, scheduler, loggerName)
|
||||||
// Need to add before iterating in case of immediate completion
|
// Need to add before iterating in case of immediate completion
|
||||||
val checkpoint = initFiber(fiber) {
|
val checkpoint = initFiber(fiber) {
|
||||||
val checkpoint = Checkpoint(serializeFiber(fiber), null, null)
|
val checkpoint = Checkpoint(serializeFiber(fiber), null, null)
|
||||||
checkpoint
|
checkpoint
|
||||||
}
|
}
|
||||||
checkpointStorage.addCheckpoint(checkpoint)
|
checkpointStorage.addCheckpoint(checkpoint)
|
||||||
synchronized(started) { // If we are not started then our checkpoint will be picked up during start
|
mutex.locked { // If we are not started then our checkpoint will be picked up during start
|
||||||
if (!started) {
|
if (!started) {
|
||||||
return fiber
|
return fiber
|
||||||
}
|
}
|
||||||
@ -267,7 +293,9 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService
|
|||||||
request: ProtocolIORequest?,
|
request: ProtocolIORequest?,
|
||||||
receivedPayload: Any?) {
|
receivedPayload: Any?) {
|
||||||
val newCheckpoint = Checkpoint(serialisedFiber, request, receivedPayload)
|
val newCheckpoint = Checkpoint(serialisedFiber, request, receivedPayload)
|
||||||
val previousCheckpoint = stateMachines.put(psm, newCheckpoint)
|
val previousCheckpoint = mutex.locked {
|
||||||
|
stateMachines.put(psm, newCheckpoint)
|
||||||
|
}
|
||||||
if (previousCheckpoint != null) {
|
if (previousCheckpoint != null) {
|
||||||
checkpointStorage.removeCheckpoint(previousCheckpoint)
|
checkpointStorage.removeCheckpoint(previousCheckpoint)
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ import java.util.*
|
|||||||
class ANSIProgressObserver(val smm: StateMachineManager) {
|
class ANSIProgressObserver(val smm: StateMachineManager) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
smm.changes.subscribe { change: Triple<ProtocolLogic<*>, AddOrRemove, Long> ->
|
smm.changes.subscribe { change ->
|
||||||
when (change.second) {
|
when (change.addOrRemove) {
|
||||||
AddOrRemove.ADD -> addProtocolLogic(change.first)
|
AddOrRemove.ADD -> addProtocolLogic(change.logic)
|
||||||
AddOrRemove.REMOVE -> removeProtocolLogic(change.first)
|
AddOrRemove.REMOVE -> removeProtocolLogic(change.logic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,8 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
|||||||
scheduler = NodeSchedulerService(services, factory, schedulerGatedExecutor)
|
scheduler = NodeSchedulerService(services, factory, schedulerGatedExecutor)
|
||||||
smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
|
smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
|
||||||
val mockSMM = StateMachineManager(services, listOf(services), PerFileCheckpointStorage(fs.getPath("checkpoints")), smmExecutor)
|
val mockSMM = StateMachineManager(services, listOf(services), PerFileCheckpointStorage(fs.getPath("checkpoints")), smmExecutor)
|
||||||
mockSMM.changes.subscribe { change:Triple<ProtocolLogic<*>, AddOrRemove, Long> ->
|
mockSMM.changes.subscribe { change ->
|
||||||
if(change.second==AddOrRemove.REMOVE && mockSMM.allStateMachines.size==0) {
|
if (change.addOrRemove == AddOrRemove.REMOVE && mockSMM.allStateMachines.isEmpty()) {
|
||||||
smmHasRemovedAllProtocols.countDown()
|
smmHasRemovedAllProtocols.countDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import com.r3corda.demos.api.NodeInterestRates
|
|||||||
import com.r3corda.node.services.config.NodeConfiguration
|
import com.r3corda.node.services.config.NodeConfiguration
|
||||||
import com.r3corda.node.services.network.NetworkMapService
|
import com.r3corda.node.services.network.NetworkMapService
|
||||||
import com.r3corda.node.services.transactions.SimpleNotaryService
|
import com.r3corda.node.services.transactions.SimpleNotaryService
|
||||||
|
import com.r3corda.node.utilities.AddOrRemove
|
||||||
import com.r3corda.testing.node.InMemoryMessagingNetwork
|
import com.r3corda.testing.node.InMemoryMessagingNetwork
|
||||||
import com.r3corda.testing.node.MockNetwork
|
import com.r3corda.testing.node.MockNetwork
|
||||||
import com.r3corda.testing.node.TestClock
|
import com.r3corda.testing.node.TestClock
|
||||||
@ -259,8 +260,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
|
|
||||||
protected fun showProgressFor(nodes: List<SimulatedNode>) {
|
protected fun showProgressFor(nodes: List<SimulatedNode>) {
|
||||||
nodes.forEach { node ->
|
nodes.forEach { node ->
|
||||||
node.smm.changes.filter { it.second == com.r3corda.node.utilities.AddOrRemove.ADD }.first().subscribe {
|
node.smm.changes.filter { it.addOrRemove == AddOrRemove.ADD }.first().subscribe {
|
||||||
linkProtocolProgress(node, it.first)
|
linkProtocolProgress(node, it.logic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,8 +279,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
|
|
||||||
protected fun showConsensusFor(nodes: List<SimulatedNode>) {
|
protected fun showConsensusFor(nodes: List<SimulatedNode>) {
|
||||||
val node = nodes.first()
|
val node = nodes.first()
|
||||||
node.smm.changes.filter { it.second == com.r3corda.node.utilities.AddOrRemove.ADD }.first().subscribe {
|
node.smm.changes.filter { it.addOrRemove == com.r3corda.node.utilities.AddOrRemove.ADD }.first().subscribe {
|
||||||
linkConsensus(nodes, it.first)
|
linkConsensus(nodes, it.logic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user