Я воссоздал сценарий с четырьмя узлами, работающими Ledger Sync Service , построенными из master (самый последний коммит 839dfb8772c3b08447183a84e336a527a0f3975b
). Я изменил BogusFlow
следующим образом, чтобы разрешить потребление состояния ввода:
/**
* A trivial flow that is merely used to illustrate synchronisation by persisting meaningless transactions in
* participant's vaults
*/
@InitiatingFlow
@StartableByRPC
class BogusFlow(
private val them: Party,
private val precursor: UniqueIdentifier? = null
) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.notaryIdentities.first()
val cmd = Command(BogusContract.Commands.Bogus(), listOf(them.owningKey))
val builder = TransactionBuilder(notary)
precursor?.let {
val result = serviceHub.vaultService.queryBy(BogusState::class.java, LinearStateQueryCriteria(linearId = listOf(it)))
val inputState = result.states.single()
builder.addInputState(inputState)
}
builder.addOutputState(BogusState(ourIdentity, them), BOGUS_CONTRACT_ID)
.addCommand(cmd).apply {
verify(serviceHub)
}
val partiallySigned = serviceHub.signInitialTransaction(builder)
val session = initiateFlow(them)
val fullySigned = subFlow(CollectSignaturesFlow(partiallySigned, setOf(session)))
return subFlow(FinalityFlow(fullySigned))
}
}
CorDapp, содержащий этот поток, развернут на трех узлах (Алиса A
, Боб B
, Чарли C
). Нотариальный нотариус (N
) используется.
Рассмотрим следующие шаги для симуляции сбоя и восстановления.
A
, B
, C
и N
, используя H2 в качестве базы данных A
, вызовите net.corda.businessnetworks.ledgersync.BogusFlow
, нацелив O=Bob Ltd., L=London, C=GB
A
и уничтожьте базу данных, т.е. rm persistence.mv.db
B
, запустите vaultQuery для contractStateType net.corda.businessnetworks.ledgersync.BogusState
, чтобы проверить, B
знает о неиспользованном состоянии после 2 [тысяча сто пятьдесят-один]. Вывод должен содержать linearId
. Запишите это удостоверение личности. B
, начать поток с C
, используя linearId
, полученный в 4 в качестве предшественника. То есть flow start net.corda.businessnetworks.ledgersync.BogusFlow them: "O=Charlie SARL, L=Paris, C=FR", precursor: "2429c289-0ccb-4adb-9714-32ee3d0d7f12"
. Обратите внимание, что в случае производственного использования код вашего контракта может в первую очередь запретить выполнение этой транзакции, учитывая, что A
не подписал ее. B
, запустите vaultQuery contractStateType: net.corda.businessnetworks.ledgersync.BogusState
и подтвердите, что существует неиспользованное состояние с участниками B
и C
(то есть "participants" : [ "O=Bob Ltd., L=London, C=GB", "O=Charlie SARL, L=Paris, C=FR" ]
). A
, верните узел обратно, создав новую базу данных H2. A
, начинайте EvaluateLedgerConsistencyFlow
(т.е. connection.proxy.startFlow(::EvaluateLedgerConsistencyFlow, listOf(alice, bob, charlie))
). Это должно вернуть {O=Bob Ltd., L=London, C=GB=false, O=Charlie SARL, L=Paris, C=FR=true}
, указывая, что A
не синхронизирован с B
. A
, запустите RequestLedgersSyncFlow
(т.е. connection.proxy.startFlow(::RequestLedgersSyncFlow, listOf(alice, bob, charlie))
). Это вернет сводку отсутствующих транзакций (например, {O=Bob Ltd., L=London, C=GB=LedgerSyncFindings(missingAtRequester=[BAA58E9E9E2025181F00459FCE8B0D035705A38D1068A0F4C4BAB53F3F56FB40], missingAtRequestee=[]), O=Charlie SARL, L=Paris, C=FR=LedgerSyncFindings(missingAtRequester=[], missingAtRequestee=[])}
). A
, запустите TransactionRecoveryFlow
, , передав в результате 9 . Например. connection.proxy.startFlow(::TransactionRecoveryFlow, report)
где report
- результат предыдущего шага. A
, для подтверждения повторного запуска EvaluateLedgerConsistencyFlow
, который вернет результат {O=Bob Ltd., L=London, C=GB=true, O=Charlie SARL, L=Paris, C=FR=true}
, указывая, что расхождение было устранено. A
, запустите запрос хранилища (т.е. VaultQueryCriteria(status = ALL), PageSpecification(), Sort(emptyList()), BogusState::class.java
), чтобы извлечь содержимое и убедиться, что состояние было воссоздано. Это охватывает сценарий, который вы описываете?
Для запуска с языком:
И если Вы будете использовать направляющие, эти скринкасты превосходны:
Вот другой, что я столкнулся в своем бесконечном поиске с помощью Google: Изучение Ruby
И я должен сказать, что мой фаворит до сих пор - То, почему Острое Руководство К Ruby. Определенно необходимость чтение.