HibernateException: Flush during cascade is dangerous during recordTransaction - corda
I am testing Corda 4.1 Open Source with Zone Constraints and I have 4 nodes which is Node A, Node B, Node C and Notary (the Notary is a CE version of Corda 4.1)
I run the IssueFlow to create StateA from Node B to Node A.
And in the IssueFlow.Responder after commit the transaction Node A subFlow a TestFlow to update the StateA which will add Node C to the participants of StateA.
This is the code in IssueFlow.Responder
#InitiatedBy(IssueFlow.Initiator::class)
class Responder(val otherFlow: FlowSession) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val flow = object : SignTransactionFlow(otherFlow) {
#Suspendable
override fun checkTransaction(stx: SignedTransaction) {
// Custom validation here
}
}
val stx = subFlow(flow)
val waitForLedgerCommit = subFlow(ReceiveFinalityFlow(otherFlow, stx.id))
executableAfterCommit(waitForLedgerCommit)
return waitForLedgerCommit
}
#Suspendable
private fun executableAfterCommit(stx: SignedTransaction) {
val listOfStateA = stx.tx.outputsOfType<StateA>()
require(listOfStateA.size == 1) { "Only one document of StateA is allowed in the transaction." }
val stateA = listOfStateA.single()
subFlow(TestFlow.Initiator(listOf(stateA.linearId.id.toString())))
}
}
In TestFlow I will update some information for StateA and add Node C as another participant but I want only NodeA and NodeB to sign.
The code as follow:
object TestFlow {
#InitiatingFlow
#StartableByRPC
class Initiator(private val linearId: String) : FlowLogic<SignedTransaction>() {
override val progressTracker: ProgressTracker()
val window by lazy { TimeWindow.withTolerance(currentClock.instant(), 30.minutes) }
#Suspendable
override fun call(): SignedTransaction {
val stx = collectSignatures(verifyAndSign(build()))
val sessions = transaction.sessionsOfParticipants()
return subFlow(FinalityFlow(stx, sessions))
}
private fun build(): TransactionBuilder {
val statesIn = queryByLinear(listOf(linearId.toUUID())).single()
val stateOut = stateIn.changeData("field1").addParticipants(NodeC)
val result = TransactionBuilder(firstNotary).apply {
// Add inputs
withItems(statesIn)
// Add outputs
withItems(StateAndContract(stateOut, StateAContract.CONTRACT_ID))
// Signer only NodeA and NodeB
val listOfSigner = listOf(statesIn.state.data, stateOut)
.selectKeysOf(addNodeA = true, addNodeB = true)
.toList()
// Add commands
addCommand(StateAContract.Commands.Test(), listOfSigner)
setTimeWindow(window)
}
return result.toLedgerTransaction(serviceHub)
}
private fun verifyAndSign(transaction: TransactionBuilder): SignedTransaction {
transaction.verify(serviceHub)
return serviceHub.signInitialTransaction(transaction)
}
#Suspendable
private fun collectSignatures(transaction: SignedTransaction): SignedTransaction {
val signers = excludeNotary(groupPublicKeysByWellKnownParty(serviceHub, transaction.getMissingSigners()), transaction).map { it.key }
return subFlow(CollectSignatureInitiator(transaction, signers))
}
}
#InitiatedBy(Initiator::class)
class Responder(private val otherFlow: FlowSession) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
return subFlow(ReceiveFinalityFlow(otherFlow))
}
}
/**
* Collect signature initiating flow
*/
#InitiatingFlow
class CollectSignatureInitiator(private val transaction: SignedTransaction, private val signers: List<Party>) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val sessions = signers.map { initiateFlow(it) }
return subFlow(CollectSignaturesFlow(transaction, sessions))
}
}
/**
* Collect signature responder flow
*/
#InitiatedBy(CollectSignatureInitiator::class)
class CollectSignatureResponder(private val session: FlowSession) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
return subFlow(object : SignTransactionFlow(session) {
override fun checkTransaction(stx: SignedTransaction) {
subFlow(ValidateDocument(session, stx))
return
}
})
}
}
}
and TestFlow throw an error in Node C as follow:
[INFO ] 2019-09-27T01:54:42,534Z [Node thread-1] corda.flow.call - Transaction dependencies resolution completed. {fiber-id=10000001, flow-id=1413cfc2-c522-45be-90d3-ce593ba3db91, invocation_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, invocation_timestamp=2019-09-27T01:52:36.071Z, origin=OU=NodeA, O=NodeA, L=Bangkok, C=TH, session_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, session_timestamp=2019-09-27T01:52:36.071Z, thread-id=205, tx_id=A083E2C3F0AA98DFCE5D0FD02420EF1A4947FEAEACE2AB1226FF89CA606D19B3}
[INFO ] 2019-09-27T01:54:42,814Z [Node thread-1] corda.flow.call - Successfully received fully signed tx. Sending it to the vault for processing. {fiber-id=10000001, flow-id=1413cfc2-c522-45be-90d3-ce593ba3db91, invocation_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, invocation_timestamp=2019-09-27T01:52:36.071Z, origin=OU=NodeA, O=NodeA, L=Bangkok, C=TH, session_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, session_timestamp=2019-09-27T01:52:36.071Z, thread-id=205, tx_id=A083E2C3F0AA98DFCE5D0FD02420EF1A4947FEAEACE2AB1226FF89CA606D19B3}
[INFO ] 2019-09-27T01:54:42,987Z [Node thread-1] corda.flow.run - Flow raised an error: org.hibernate.HibernateException: Flush during cascade is dangerous. Sending it to flow hospital to be triaged. {fiber-id=10000001, flow-id=1413cfc2-c522-45be-90d3-ce593ba3db91, invocation_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, invocation_timestamp=2019-09-27T01:52:36.071Z, origin=OU=NodeA, O=NodeA, L=Bangkok, C=TH, session_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, session_timestamp=2019-09-27T01:52:36.071Z, thread-id=205, tx_id=A083E2C3F0AA98DFCE5D0FD02420EF1A4947FEAEACE2AB1226FF89CA606D19B3}
[INFO ] 2019-09-27T01:54:42,999Z [Node thread-1] statemachine.StaffedFlowHospital.flowErrored - Flow [1413cfc2-c522-45be-90d3-ce593ba3db91] admitted to hospital in state StateMachineState(checkpoint=Checkpoint(invocationContext=InvocationContext(origin=Peer(party=OU=NodeA, O=NodeA, L=Bangkok, C=TH), trace=Trace(invocationId=cb808503-85c2-4c8c-afb7-3d1996f4fc02, timestamp: 2019-09-27T01:52:36.071Z, entityType: Invocation, sessionId=cb808503-85c2-4c8c-afb7-3d1996f4fc02, timestamp: 2019-09-27T01:52:36.071Z, entityType: Session), actor=null, externalTrace=null, impersonatedActor=null), ourIdentity=OU=BANK, O=SCB3, L=Bangkok, C=TH, sessions={SessionId(toLong=-2182783777352841143)=Initiated(peerParty=OU=NodeA, O=NodeA, L=Bangkok, C=TH, peerFlowInfo=FlowInfo(flowVersion=1, appName=testflow-1.0), receivedMessages=[], initiatedState=Live(peerSinkSessionId=SessionId(toLong=-3936218859034478298)), errors=[], deduplicationSeed=D--3936218859034478298--368822318982290956)}, subFlowStack=[Inlined(flowClass=class com.corda.test.flows.TestFlow$Responder, subFlowVersion=CoreFlow(platformVersion=4), isEnabledTimedFlow=false)], flowState=Started(flowIORequest=Send(sessionToMessage={FlowSessionImpl(counterparty=OU=NodeA, O=NodeA, L=Bangkok, C=TH, sourceSessionId=SessionId(toLong=-2182783777352841143))=768AED61FD2A58D74D7316731407E0600065080E1F3E6397EE4FA5AEFEE79295}), frozenFiber=6C3A73148E4E786591224DA1A0BDCADD704073C8A70CE425769DE7576F43735B), errorState=Clean, numberOfSuspends=5), flowLogic=com.corda.test.flows.TestFlow$Responder#1ad039f4, pendingDeduplicationHandlers=[], isFlowResumed=true, isTransactionTracked=false, isAnyCheckpointPersisted=true, isStartIdempotent=false, isRemoved=false, senderUUID=f5784837-d7a3-45e8-8b4c-9cf286f080b8) {fiber-id=10000001, flow-id=1413cfc2-c522-45be-90d3-ce593ba3db91, invocation_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, invocation_timestamp=2019-09-27T01:52:36.071Z, origin=OU=NodeA, O=NodeA, L=Bangkok, C=TH, session_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, session_timestamp=2019-09-27T01:52:36.071Z, thread-id=205, tx_id=A083E2C3F0AA98DFCE5D0FD02420EF1A4947FEAEACE2AB1226FF89CA606D19B3}
[INFO ] 2019-09-27T01:54:43,005Z [Node thread-1] statemachine.StaffedFlowHospital.invoke - Error 1 of 1: {fiber-id=10000001, flow-id=1413cfc2-c522-45be-90d3-ce593ba3db91, invocation_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, invocation_timestamp=2019-09-27T01:52:36.071Z, origin=OU=NodeA, O=NodeA, L=Bangkok, C=TH, session_id=cb808503-85c2-4c8c-afb7-3d1996f4fc02, session_timestamp=2019-09-27T01:52:36.071Z, thread-id=205, tx_id=A083E2C3F0AA98DFCE5D0FD02420EF1A4947FEAEACE2AB1226FF89CA606D19B3}
javax.persistence.PersistenceException: org.hibernate.HibernateException: Flush during cascade is dangerous
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1460) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1440) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at net.corda.node.utilities.AppendOnlyPersistentMapBase.loadValue(AppendOnlyPersistentMap.kt:145) ~[corda-node-4.1.jar:?]
at net.corda.node.utilities.AppendOnlyPersistentMapBase.access$loadValue(AppendOnlyPersistentMap.kt:22) ~[corda-node-4.1.jar:?]
at net.corda.node.utilities.AppendOnlyPersistentMapBase$transactionalLoadValue$3.invoke(AppendOnlyPersistentMap.kt:160) ~[corda-node-4.1.jar:?]
at net.corda.node.utilities.AppendOnlyPersistentMapBase$Transactional$Unknown$valueWithoutIsolationDelegate$1.invoke(AppendOnlyPersistentMap.kt:251) ~[corda-node-4.1.jar:?]
at kotlin.SafePublicationLazyImpl.getValue(LazyJVM.kt:107) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.node.utilities.AppendOnlyPersistentMapBase$Transactional$Unknown.isPresent(AppendOnlyPersistentMap.kt:249) ~[corda-node-4.1.jar:?]
at net.corda.node.utilities.AppendOnlyPersistentMapBase$Transactional.orElse(AppendOnlyPersistentMap.kt:222) ~[corda-node-4.1.jar:?]
at net.corda.node.utilities.AppendOnlyPersistentMapBase.get(AppendOnlyPersistentMap.kt:40) ~[corda-node-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService$certificateFromCordaX500Name$1.invoke(PersistentIdentityService.kt:165) ~[corda-node-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService$certificateFromCordaX500Name$1.invoke(PersistentIdentityService.kt:33) ~[corda-node-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:224) ~[corda-node-api-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:204) ~[corda-node-api-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:210) ~[corda-node-api-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService.certificateFromCordaX500Name(PersistentIdentityService.kt:164) ~[corda-node-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService.wellKnownPartyFromX500Name(PersistentIdentityService.kt:175) ~[corda-node-4.1.jar:?]
at net.corda.core.node.services.IdentityService$DefaultImpls.wellKnownPartyFromAnonymous(IdentityService.kt:103) ~[corda-core-4.1.jar:?]
at net.corda.node.services.api.IdentityServiceInternal$DefaultImpls.wellKnownPartyFromAnonymous(IdentityServiceInternal.kt) ~[corda-node-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService$wellKnownPartyFromAnonymous$1.invoke(PersistentIdentityService.kt:184) ~[corda-node-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService$wellKnownPartyFromAnonymous$1.invoke(PersistentIdentityService.kt:33) ~[corda-node-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:224) ~[corda-node-api-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:204) ~[corda-node-api-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:210) ~[corda-node-api-4.1.jar:?]
at net.corda.node.services.identity.PersistentIdentityService.wellKnownPartyFromAnonymous(PersistentIdentityService.kt:184) ~[corda-node-4.1.jar:?]
at net.corda.node.internal.AbstractNode$database$2.invoke(AbstractNode.kt:158) ~[corda-node-4.1.jar:?]
at net.corda.node.internal.AbstractNode$database$2.invoke(AbstractNode.kt:120) ~[corda-node-4.1.jar:?]
at net.corda.node.services.persistence.AbstractPartyToX500NameAsStringConverter.convertToDatabaseColumn(AbstractPartyToX500NameAsStringConverter.kt:23) ~[corda-node-4.1.jar:?]
at net.corda.node.services.persistence.AbstractPartyToX500NameAsStringConverter.convertToDatabaseColumn(AbstractPartyToX500NameAsStringConverter.kt:15) ~[corda-node-4.1.jar:?]
at org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl.toRelationalValue(JpaAttributeConverterImpl.java:50) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$1.bind(AttributeConverterSqlTypeDescriptorAdapter.java:78) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:280) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:275) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:39) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2868) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3162) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3686) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.ActionQueue.executeInserts(ActionQueue.java:461) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:258) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:359) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:292) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:200) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:131) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:824) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:791) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:471) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:396) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:197) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:504) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:436) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:399) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:197) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:130) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:486) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:200) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:800) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at net.corda.node.services.schema.PersistentStateService.persistStatesWithSchema$node(PersistentStateService.kt:48) ~[corda-node-4.1.jar:?]
at net.corda.node.services.schema.PersistentStateService.persist(PersistentStateService.kt:40) ~[corda-node-4.1.jar:?]
at net.corda.node.services.vault.NodeVaultService.processAndNotify(NodeVaultService.kt:364) ~[corda-node-4.1.jar:?]
at net.corda.node.services.vault.NodeVaultService.access$processAndNotify(NodeVaultService.kt:51) ~[corda-node-4.1.jar:?]
at net.corda.node.services.vault.NodeVaultService$notifyAll$1.invoke(NodeVaultService.kt:213) ~[corda-node-4.1.jar:?]
at net.corda.node.services.vault.NodeVaultService.notifyAll(NodeVaultService.kt:223) ~[corda-node-4.1.jar:?]
at net.corda.node.services.api.ServiceHubInternal$Companion$recordTransactions$1.invoke(ServiceHubInternal.kt:106) ~[corda-node-4.1.jar:?]
at net.corda.node.services.api.ServiceHubInternal$Companion$recordTransactions$1.invoke(ServiceHubInternal.kt:51) ~[corda-node-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:224) ~[corda-node-api-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:204) ~[corda-node-api-4.1.jar:?]
at net.corda.nodeapi.internal.persistence.CordaPersistence.transaction(CordaPersistence.kt:210) ~[corda-node-api-4.1.jar:?]
at net.corda.node.services.api.ServiceHubInternal$Companion.recordTransactions(ServiceHubInternal.kt:60) ~[corda-node-4.1.jar:?]
at net.corda.node.services.api.ServiceHubInternal$DefaultImpls.recordTransactions(ServiceHubInternal.kt:132) ~[corda-node-4.1.jar:?]
at net.corda.node.internal.AbstractNode$ServiceHubInternalImpl.recordTransactions(AbstractNode.kt:962) ~[corda-node-4.1.jar:?]
at net.corda.core.flows.ReceiveTransactionFlow.call(ReceiveTransactionFlow.kt:62) ~[corda-core-4.1.jar:?]
at net.corda.core.flows.ReceiveTransactionFlow.call(ReceiveTransactionFlow.kt:28) ~[corda-core-4.1.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt:329) ~[corda-node-4.1.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:314) ~[corda-core-4.1.jar:?]
at net.corda.core.flows.ReceiveFinalityFlow.call(FinalityFlow.kt:256) ~[corda-core-4.1.jar:?]
at net.corda.core.flows.ReceiveFinalityFlow.call(FinalityFlow.kt:251) ~[corda-core-4.1.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt:329) ~[corda-node-4.1.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:314) ~[corda-core-4.1.jar:?]
at com.corda.test.flows.TestFlow$Responder.call(TestFlow.kt:226) ~[?:?]
at com.corda.test.flows.TestFlow$Responder.call(TestFlow.kt:221) ~[?:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:269) ~[corda-node-4.1.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:45) ~[corda-node-4.1.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_222]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_222]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[?:1.8.0_222]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[?:1.8.0_222]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_222]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_222]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:63) ~[corda-node-4.1.jar:?]
Caused by: org.hibernate.HibernateException: Flush during cascade is dangerous
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1449) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
... 104 more
Now what I'm doing to solve this problem is I went to onchain database and truncate the following table
- node_info_party_cert
- node_link_nodeinfo_party
- node_info_hosts
- node_infos
After truncate these table I restart Node C then let it resume from node checkpoints and everything works.
Sometimes the error happens on Both Node B and Node C.
I'm using the same code and test in the CE environment but I didn't found this error.
The question is
What is the root cause of this error?
What was Corda is trying to do when recordTransactions?
What is the proper way to solve this problem?
This issue is resolved with the latest version of Corda OS 4.3.
You can get update your dependencies at build.gradle, and point it to newer version of Corda.
Related
How to get signature from Same Counter Party, multiple times in a single flow?
I need to implement the scenario like, there are CentralParty,PartyA,PartyB. CentralParty needs to initiate a flow where there will be 3 transactions in a loop ,where inititor is always Central party and the otherparty will be Party A 2 times. i.e.I m trying to collecting signature from same counterparty with multiple times from a single flow by referring the below link Corda returning Multiple transactions in a single flow call () val flowSessionMap = mutableMapOf<Party, FlowSession>() var ftx:MutableList<SignedTransaction> = mutableListOf<SignedTransaction>() var signedTransaction:SignedTransaction val fullySignedTransactions = matchingStateList.forEach { matchingState -> val txCommand = Command(IOUContract.Commands.Matching(), matchingState.participants.map { it.owningKey }) val txBuilder = TransactionBuilder(notary) .addOutputState(matchingState, IOU_CONTRACT_ID) .addCommand(txCommand) // Stage 2. progressTracker.currentStep = VERIFYING_TRANSACTION // Verify that the transaction is valid. txBuilder.verify(serviceHub) // Stage 3. progressTracker.currentStep = SIGNING_TRANSACTION // Sign the transaction. val partSignedTx = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey) val sessions = (listOf(PartyA).map { signer -> flowSessionMap.getOrPut(signer) { initiateFlow(signer) } }) val fullySignedTransaction = subFlow(CollectSignaturesInitiatingFlow( partSignedTx, sessions) ) signedTransaction = fullySignedTransaction ftx.add(signedTransaction) } for (transaction in ftx) { subFlow(FinalityFlow(transaction)) } Responder flow is defined as follows: class Acceptor(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() { #Suspendable override fun call(): SignedTransaction { val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) { override fun checkTransaction(stx: SignedTransaction) = requireThat { val output = stx.tx.outputs.single().data "This must be an Matching State transaction." using (output is MatchingState) val Match = output as MatchingState "I won't accept IOUs with a value over 100." using (iou.value <= 100) } } return subFlow(signTransactionFlow) } } Where CollectSignaturesInitiatingFlow is defined as follows: #InitiatingFlow class CollectSignaturesInitiatingFlow(val signedTransaction: SignedTransaction, val sessions: List<FlowSession>): FlowLogic<SignedTransaction>() { override fun call(): SignedTransaction { return subFlow(CollectSignaturesFlow(signedTransaction, sessions)) } } And the responder for CollectSignaturesInitiatingFlow is defined as follows: #InitiatedBy(CollectSignaturesInitiatingFlow::class) class CollectSignaturesInitiatingFlowResponder(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() { #Suspendable override fun call(): SignedTransaction { val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) { override fun checkTransaction(stx: SignedTransaction) { TODO("Check the transaction here.") } } return subFlow(signTransactionFlow) } } While running the same code I got an error like [WARN ] 15:43:18,817 [Node thread-1] (FlowStateMachineImpl.kt:111) flow.[82900238-9223-4ace-ba78-9ecc45121b11].run - Terminated by unexpected exception {} net.corda.core.flows.UnexpectedFlowEndException: Counterparty flow on O=PartyA, L=London, C=GB has completed without sending data at net.corda.node.services.statemachine.FlowStateMachineImpl.confirmNoError(FlowStateMachineImpl.kt:488) ~[corda-node-3.2-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForMessage(FlowStateMachineImpl.kt:444) ~[corda-node-3.2-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceiveInternal(FlowStateMachineImpl.kt:385) ~[corda-node-3.2-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceive(FlowStateMachineImpl.kt:203) ~[corda-node-3.2-corda.jar:?] at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:29) ~[corda-node-3.2-corda.jar:?] at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:40) ~[corda-node-3.2-corda.jar:?] at net.corda.core.flows.DataVendingFlow.sendPayloadAndReceiveDataRequest(SendTransactionFlow.kt:70) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:48) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:31) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.CollectSignatureFlow.call(CollectSignaturesFlow.kt:142) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.CollectSignatureFlow.call(CollectSignaturesFlow.kt:135) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:114) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:64) ~[corda-core-3.2-corda.jar:?] at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?] at com.example.flow.ExampleFlowMatching$CollectSignaturesInitiatingFlow.call(ExampleFlowMatching.kt:260) ~[classes/:?] at com.example.flow.ExampleFlowMatching$CollectSignaturesInitiatingFlow.call(ExampleFlowMatching.kt:258) ~[classes/:?] at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?] at com.example.flow.ExampleFlowMatching$ExampleFlowMatchingInitiator.call(ExampleFlowMatching.kt:202) ~[classes/:?] at com.example.flow.ExampleFlowMatching$ExampleFlowMatchingInitiator.call(ExampleFlowMatching.kt:45) ~[classes/:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.2-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.2-corda.jar:?] at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_191] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_191] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_191] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_191] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_191] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_191] at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:62) [corda-node-3.2-corda.jar:?]
The issue is that you are initiating the flow sessions in your main flow, ExampleFlowMatchingInitiator, instead of inside CollectSignaturesInitiatingFlow. When you call initiateFlow, it starts a flow session with the counterparty in the context of the current InitiatingFlow. So when you call initiateFlow in ExampleFlowMatchingInitiator, the counterparty will check whether it has any responders registered for ExampleFlowMatchingInitiator. It does - Acceptor - so it starts a flow session to speak to the counterparty using Acceptor. If you call initiateFlow inside CollectSignaturesInitiatingFlow instead, the counterparty will check whether it has any responders registered for CollectSignaturesInitiatingFlow. It does - CollectSignaturesInitiatingFlowResponder - so it starts a flow session to speak to the counterparty using CollectSignaturesInitiatingFlowResponder instead.
Implementing FungibleAsset
I have some troubles implementing a FungibleAsset contract. The Dapp should consist of a Pool which is tokenized through PoolToken. For the PoolToken I implement the FungibleAsset class. There is a flow called CreatePoolFlow which uses the Create-Command from the Pool and the Issue-Command from the PoolToken. This flow should create a new Pool and Issue a specified number of Tokens the the Creator. When invoking the Flow an Error occurs. Is there any guide on how to implement FungibleAsset or in general Tokens? Thanks in advance for any help! Pool.kt: package com.company //imports here // ***************** // * Contract Code * // ***************** class Pool : Contract { // This is used to identify our contract when building a transaction companion object { const val POOL_CONTRACT_ID: ContractClassName = "com.company.Pool" } // A transaction is considered valid if the verify() function of the contract of each of the transaction's input // and output states does not throw an exception. override fun verify(tx: LedgerTransaction) { //requireSingleCommand var command = tx.commands.requireSingleCommand<Pool.Commands>() val timeWindow: TimeWindow? = tx.timeWindow when (command.value) { is Commands.Create -> { } else -> throw IllegalArgumentException("Unrecognised command!") } } // Used to indicate the transaction's intent. interface Commands : CommandData { class Create : TypeOnlyCommandData(), Commands } } // ********* // * State * // ********* data class PoolState(val issuer: Party, override val participants: List<Party> = listOf(issuer), val id: UniqueIdentifier = UniqueIdentifier()) //val id: UniqueIdentifier = UniqueIdentifier()) //val loans: Array<StateRef<Loan>> : ContractState { //override val participants = listOf(issuer) //fun withoutOwner() = copy(issuer = AnonymousParty(NullKeys.NullPublicKey)) } PoolToken.kt: package com.company //imports here // ***************** // * Contract Code * // ***************** class PoolToken : Contract { // This is used to identify our contract when building a transaction companion object { const val POOLTOKEN_CONTRACT_ID: ContractClassName = "com.company.PoolToken" } // A transaction is considered valid if the verify() function of the contract of each of the transaction's input // and output states does not throw an exception. override fun verify(tx: LedgerTransaction) { //requireSingleCommand var command = tx.commands.requireSingleCommand<PoolToken.Commands>() val timeWindow: TimeWindow? = tx.timeWindow when (command.value) { is Commands.Issue -> { } is Commands.Move -> { } is Commands.Exit -> { } else -> throw IllegalArgumentException("Unrecognised command!") } } // Used to indicate the transaction's intent. interface Commands : CommandData { class Move : TypeOnlyCommandData(), Commands class Issue : TypeOnlyCommandData(), Commands class Exit : TypeOnlyCommandData(), Commands } } // ********* // * State * // ********* data class PoolTokenState(override val owner: AbstractParty, override val amount: Amount<Issued<UniqueIdentifier>>) : FungibleAsset<UniqueIdentifier> { //TODO: Change to BigDecimal override val exitKeys = setOf(owner.owningKey) //, amount.token.issuer.party.owningKey override val participants = listOf(owner) override fun withNewOwnerAndAmount(newAmount: Amount<Issued<UniqueIdentifier>>, newOwner: AbstractParty): FungibleAsset<UniqueIdentifier> = copy(amount = amount.copy(newAmount.quantity), owner = newOwner) //override fun toString() = "$amount Tokens of Pool ${amount.token.product} from ${amount.token.issuer} owned by $owner" override fun withNewOwner(newOwner: AbstractParty) = CommandAndState(PoolToken.Commands.Move(), copy(owner = newOwner)) //fun withoutOwner() = copy(issuer = AnonymousParty(NullKeys.NullPublicKey)) } PoolFlows.kt: package com.company //imports here #InitiatingFlow #StartableByRPC class CreatePoolFlow(val tokens: Long) : FlowLogic<SignedTransaction>() { //val auditor: Party override val progressTracker = ProgressTracker() #Suspendable override fun call(): SignedTransaction { //retrieve the notary identity from the network map val notary = serviceHub.networkMapCache.notaryIdentities.first() //create a transaction builder val txBuilder = TransactionBuilder(notary = notary) //get all parties in the network //TODO: Construct as set and convert to list in order to prevent duplicates? val nodes = serviceHub.networkMapCache.allNodes val _parties = mutableListOf<Party>() for (node in nodes) { for (party in node.legalIdentities) { _parties.add(party) } } val parties: List<Party> = _parties //create the Pool transaction components val outputStatePool = PoolState(ourIdentity,parties) val outputContractAndStatePool = StateAndContract(outputStatePool, POOL_CONTRACT_ID) val cmdPool = Command(Pool.Commands.Create(), ourIdentity.owningKey) //create the PoolToken transaction components val outputStatePoolToken = PoolTokenState(ourIdentity, Amount(tokens,Issued(ourIdentity.ref(),outputStatePool.id))) val outputContractAndStatePoolToken = StateAndContract(outputStatePoolToken, POOLTOKEN_CONTRACT_ID) val cmdPoolToken = Command(PoolToken.Commands.Issue(), ourIdentity.owningKey) //add the items to the builder txBuilder.withItems(outputContractAndStatePool, cmdPool, outputContractAndStatePoolToken, cmdPoolToken) //add time val currentTime = serviceHub.clock.instant() txBuilder.setTimeWindow(currentTime, 60.seconds) //verifying the transaction txBuilder.verify(serviceHub) //signing the transaction val signedTx = serviceHub.signInitialTransaction(txBuilder) // Finalising the transaction. subFlow(FinalityFlow(signedTx)) return signedTx } } Error when executing the flow: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Failed requirement. at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357) at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895) at com.company.FlowTests.create pool and tokens(FlowTests.kt:48) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: java.lang.IllegalArgumentException: Failed requirement. at net.corda.core.utilities.OpaqueBytes.<init>(ByteArrays.kt:154) at net.corda.core.utilities.OpaqueBytes$Companion.of(ByteArrays.kt:150) at net.corda.core.identity.AbstractParty.ref(AbstractParty.kt:32) at com.company.CreatePoolFlow.call(PoolFlows.kt:63) at com.company.CreatePoolFlow.call(PoolFlows.kt:34) at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:62)
I assume the problem is in the line val outputStatePoolToken = PoolTokenState(ourIdentity, Amount(tokens,Issued(ourIdentity.ref(),outputStatePool.id))) You are creating ourIdenity.ref() with empty bytes, which will cause the exact error. Pass something like OpaqueBytes.of(0) to it and see if it helps
Contract constraints failed for... corda exception during flow execution
i'm having some trouble to implement a simple use case in corda. i want to implement a free of payment transfer. the lifecycle is maintained in corda. At first i create a bond state that will be saved only on nodeA that works without problem). After that i want to create a new state that represent an FOP proposal, that the receiver(nodeB) can accept. The idea is that the bond will be consumed when the fop proposal is created. after the receiver accepts the proposal(another flow that needs to be implemented) a new bond state will be created an the the receiver is the owner. The Flow to create the FOP proposal (a state that should be saved on nodeA and nodeB) is this: object IssueFopFlow { #InitiatingFlow #StartableByRPC class Initiator(private val sender: AbstractParty, private val receiver: AbstractParty, private val amount: Int, private val bondLinearId: UniqueIdentifier) : MyBaseFlow() { companion object { object INITIALISING : ProgressTracker.Step("Performing initial steps.") object BUILDING : ProgressTracker.Step("Building and verifying transaction.") object SIGNING : ProgressTracker.Step("Signing transaction.") object COLLECTING : ProgressTracker.Step("Collecting counterparty signature.") { override fun childProgressTracker() = CollectSignaturesFlow.tracker() } object FINALISING : ProgressTracker.Step("Finalising transaction.") { override fun childProgressTracker() = FinalityFlow.tracker() } fun tracker() = ProgressTracker(INITIALISING, BUILDING, SIGNING, COLLECTING, FINALISING) } override val progressTracker: ProgressTracker = tracker() #Suspendable override fun call(): SignedTransaction { // Step 1. Initialisation. progressTracker.currentStep = INITIALISING val bondForFop = getBondByLinearId(bondLinearId) val inputBond = bondForFop.state.data // check that the bond owner is calling this flow check(inputBond.owner == ourIdentity) { throw FlowException("Issue fop transfer must be initiated by the bond owner.") } // check the amount check(inputBond.amount >= amount) { throw FlowException("Not enough of the bond ${inputBond.isin}. Quantity: ${inputBond.amount}. Amount to transfer: ${amount}") } // create fop transfer state val fopTransfer = FopState(sender, receiver, amount, inputBond.isin) val ourSigningKey = fopTransfer.sender.owningKey // Step 2. Building. progressTracker.currentStep = BUILDING val utx = TransactionBuilder(firstNotary) .addInputState(bondForFop) .addOutputState(fopTransfer, FOP_CONTRACT_ID) .addCommand(FopContract.Commands.Issue(), listOf(sender.owningKey, receiver.owningKey)) .setTimeWindow(serviceHub.clock.instant(), 30.seconds) // create new bond state if (amount < inputBond.amount) { val (command, newState) = inputBond.reduce(amount) utx .addOutputState(newState, BOND_CONTRACT_ID) .addCommand(command, newState.owner.owningKey) } utx.verify(serviceHub) // Step 3. Sign the transaction. progressTracker.currentStep = SIGNING val ptx = serviceHub.signInitialTransaction(utx, ourSigningKey) // Step 4. Get the counter-party signature. progressTracker.currentStep = COLLECTING val senderFlow = initiateFlow(ourIdentity) val stx = subFlow( CollectSignaturesFlow( ptx, setOf(senderFlow), listOf(sender.owningKey, receiver.owningKey), COLLECTING.childProgressTracker() ) ) // Step 5. Finalise the transaction. progressTracker.currentStep = FINALISING return subFlow(FinalityFlow(stx, FINALISING.childProgressTracker())) } } #InitiatedBy(Initiator::class) class Responder(private val otherFlow: FlowSession) : FlowLogic<SignedTransaction>() { #Suspendable override fun call(): SignedTransaction { subFlow(IdentitySyncFlow.Receive(otherFlow)) val stx = subFlow(SignTxFlowNoChecking(otherFlow)) return waitForLedgerCommit(stx.id) } } } My current problem is, that i get an exception: net.corda.core.contracts.TransactionVerificationException$ContractConstraintRejection: Contract constraints failed for com.models.BondContract, transaction: 44A52F07B9579C5106321361A6154C1EE5EF5670FA94CEFF24AB487F0B20D733 at net.corda.core.transactions.LedgerTransaction.verifyConstraints(LedgerTransaction.kt:91) ~[corda-core-2.0.0.jar:?] at net.corda.core.transactions.LedgerTransaction.verify(LedgerTransaction.kt:67) ~[corda-core-2.0.0.jar:?] at net.corda.core.transactions.TransactionBuilder.verify(TransactionBuilder.kt:113) ~[corda-core-2.0.0.jar:?] at com.flow.IssueFopFlow$Initiator.call(IssueFopFlow.kt:78) ~[cordapp-0.1.jar:?] at com.flow.IssueFopFlow$Initiator.call(IssueFopFlow.kt:19) ~[cordapp-0.1.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-2.0.0.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:41) [corda-node-2.0.0.jar:?] at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_162] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_162] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_162] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_162] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_162] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_162] I don't get why. the verify implementation of the BondContract should be fine(only from my point of view :D). Here is also the code of the bond contract. open class BondContract : Contract { override fun verify(tx: LedgerTransaction) { val command = tx.commands.requireSingleCommand<Commands>() val setOfSigners = command.signers.toSet() when (command.value) { is Commands.Issue -> verifyIssue(tx, setOfSigners) is Commands.Reduce -> verifyReduce(tx, setOfSigners) else -> throw IllegalArgumentException("Unrecognised command.") } } private fun keysFromParticipants(bond: BondState): Set<PublicKey> { return bond.participants.map { it.owningKey }.toSet() } private fun verifyIssue(tx: LedgerTransaction, signers: Set<PublicKey>) = requireThat { "No inputs should be consumed when issuing an obligation." using (tx.inputStates.isEmpty()) "Only one bond state should be created when issuing an obligation." using (tx.outputStates.size == 1) val bond = tx.outputsOfType<BondState>().single() "A newly issued bond must have a positive amount." using (bond.amount > 0) "Issuer may sign bond issue transaction." using (signers == keysFromParticipants(bond)) } private fun verifyReduce(tx: LedgerTransaction, signers: Set<PublicKey>) = requireThat { val bond = tx.outputsOfType<BondState>().single() "A bond must have a positive amount." using (bond.amount > 0) } interface Commands : CommandData { class Move : TypeOnlyCommandData(), Commands class Issue : TypeOnlyCommandData(), Commands class Reduce : TypeOnlyCommandData(), Commands } } // ********* // * State * // ********* data class BondState(val isin: String, val amount: Int, override val owner: AbstractParty, override val linearId: UniqueIdentifier = UniqueIdentifier()) : LinearState, QueryableState, OwnableState { override val participants: List<AbstractParty> get() = listOf(owner) override fun generateMappedObject(schema: MappedSchema): PersistentState { return when (schema) { is BondSchemaV1 -> BondSchemaV1.PersistentBond( this.owner.toString(), this.isin, this.amount, this.linearId.id ) else -> throw IllegalArgumentException("Unrecognised schema $schema") } } override fun supportedSchemas(): Iterable<MappedSchema> = listOf(BondSchemaV1) override fun withNewOwner(newOwner: AbstractParty) = CommandAndState(BondContract.Commands.Move(), copy(owner = newOwner)) fun reduce(amountToReduce: Int) = CommandAndState(BondContract.Commands.Reduce(), copy(amount = amount - amountToReduce)) } Can someone help me?
This problem was fixed by performing a clean build, either by: Using the Gradle clean flag (e.g. gradlew clean deployNodes) Deleting the build folder manually
java.util.concurrent.RejectedExecutionException when action calls runAsync
I noticed while updating my TornadoFX version from 1.7.12 to 1.7.14 that one of my tests broke. Things seemed to go off the rails when a runAsyncWithProgress in the View under test was rejected by a ThreadPoolExecutor with status Terminated. I saw in the release notes for 1.7.13 there was a change "internal thread pools are shut down on app exit". Setting the TornadoFX version to 1.7.13 resulted in the same failure, confirming my suspicion that it was related to the above change. I wrote a simple app to demonstrate this bug. // src/main/kotlin/me/carltonwhitehead/AsyncBugApp.kt class AsyncBugApp : App(MainView::class) /** * The main method is needed to support the mvn jfx:run goal. */ fun main(args: Array<String>) { Application.launch(AsyncBugApp::class.java, *args) } class MainView : View("Async Bug App") { val controller: MainController by inject() override val root = pane { button("Robot-click to repeat bug") { id = "bug" action { runAsync { controller.onAction("button clicked") } } } } } class MainController : Controller() { fun onAction(message: String) { println(message) } } And the test // src/test/kotlin/me/carltonwhitehead/AsyncBugAppTest.kt #RunWith(Parameterized::class) class AsyncBugAppTest(val rounds: Int) { companion object { #JvmStatic #Parameterized.Parameters fun data() : Collection<Array<Int>> { return listOf(arrayOf(1), arrayOf(1)) } } lateinit var robot: FxRobot lateinit var app: App #RelaxedMockK lateinit var controller: MainController #Rule #JvmField val timeout = Timeout(10, TimeUnit.SECONDS) #Before fun before() { MockKAnnotations.init(this) FxToolkit.registerPrimaryStage() app = AsyncBugApp() app.scope.set(controller) FxToolkit.setupApplication { app } robot = FxRobot() println("rounds = $rounds") } #After fun after() { FxToolkit.cleanupStages() FxToolkit.cleanupApplication(app) } #Test() fun itShouldSurviveRunAsyncMultipleTimes() { val latch = CountDownLatch(rounds) every { controller.onAction(any()) }.answers { latch.countDown() } var i = 0 while(i <= rounds) { robot.clickOn("#bug") i++ } latch.await() verify(exactly = rounds) { controller.onAction(any()) } } } The first time that test executes, it passes. The second time, it hangs, because the runAsync is rejected with the below stack trace. --- Exception in Async Thread --- java.util.concurrent.RejectedExecutionException: Task tornadofx.FXTask#a315135 rejected from java.util.concurrent.ThreadPoolExecutor#75bde925[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 2] java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2104) java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:848) java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1397) tornadofx.AsyncKt.task(Async.kt:76) tornadofx.AsyncKt.task(Async.kt:69) tornadofx.Component.runAsync(Component.kt:272) tornadofx.Component.runAsync$default(Component.kt:988) me.carltonwhitehead.MainView$root$1$1$1.invoke(AsyncBugApp.kt:21) me.carltonwhitehead.MainView$root$1$1$1.invoke(AsyncBugApp.kt:15) tornadofx.ControlsKt$action$2.handle(Controls.kt:513) tornadofx.ControlsKt$action$2.handle(Controls.kt) javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) javafx.base/javafx.event.Event.fireEvent(Event.java:198) javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8863) javafx.controls/javafx.scene.control.Button.fire(Button.java:200) javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206) javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274) javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) javafx.base/javafx.event.Event.fireEvent(Event.java:198) javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3876) javafx.graphics/javafx.scene.Scene$MouseHandler.access$1300(Scene.java:3604) javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1874) javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2613) javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397) javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295) java.base/java.security.AccessController.doPrivileged(Native Method) javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434) javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433) javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556) javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942) javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277) java.base/java.lang.Thread.run(Thread.java:844) I suspect I might be doing something wrong with the TestFX/TornadoFX app lifecycle. Each test cycle is creating a new app instance, so I'm confused why the ThreadPoolExecutor would be retained. Any suggestions? Repo at https://github.com/carltonwhitehead/fx-async-bug-test
Corda V1 unit Test code issue
Please any suggest, but I aslo git the core project. most of junit test that have compile errror and some of the can't be run ok. I used below code make Junit test in V14 version the code it's ok. but in CordaV1 version. pop up error as blew: net.corda.core.transactions.MissingContractAttachments: Cannot find contract attachments for [com.legalcontract.contract.LegalContractCode] at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core_main(TransactionBuilder.kt:96) ~[corda-core-1.0.0.jar:?] at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core_main$default(TransactionBuilder.kt:87) ~[corda-core-1.0.0.jar:?] at net.corda.core.transactions.TransactionBuilder.toWireTransaction(TransactionBuilder.kt:85) ~[corda-core-1.0.0.jar:?] at net.corda.core.transactions.TransactionBuilder.toLedgerTransaction(TransactionBuilder.kt:107) ~[corda-core-1.0.0.jar:?] at net.corda.core.transactions.TransactionBuilder.verify(TransactionBuilder.kt:113) ~[corda-core-1.0.0.jar:?] at com.legalcontract.flow.LegalContractFlow$Initiator.call(LegalContractFlow.kt:247) ~[main/:?] at com.legalcontract.flow.LegalContractFlow$Initiator.call(LegalContractFlow.kt:47) ~[main/:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:112) [corda-node-1.0.0.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:40) [corda-node-1.0.0.jar:?] at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_131] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_131] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_131] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_131] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131] Code: #After fun tearDown() { net.stopNodes() } #Before fun setup() { net = MockNetwork(false, true) } class WrapperStream(input: InputStream) : FilterInputStream(input) #Test fun `flow a new status valid Legal Contract`() { val notaryNode = net.createNotaryNode() val a = net.createPartyNode(notaryNode.network.myAddress, CordaX500Name("a","London","GB")) val b = net.createPartyNode(notaryNode.network.myAddress, CordaX500Name("b","New York","US")) a.internals.registerInitiatedFlow(LegalContractFlow.Acceptor::class.java) b.internals.registerInitiatedFlow(LegalContractFlow.Acceptor::class.java) val attachment = gInputStreamAndHash() println(attachment) val id = a.database.transaction { a.attachments.importAttachment(attachment.inputStream) } assertEquals(attachment.sha256, id, "Attachment has correct SHA256 hash") LegalContractFlowTests.attachList.add(id.toString()) var fileName: String = "test1" var legalContract: LegalContract = LegalContract(a.info.legalIdentities.first().name.toString(),LegalContractFlowTests.attachList.get(0)) // System.out.print(legalContract) var state: LegalContractState = LegalContractState( legalContract, a.info.legalIdentities.first(), b.info.legalIdentities.first()) val flow = LegalContractFlow.Initiator(state, b.info.chooseIdentity(), false) val future = a.services.startFlow(flow).resultFuture var signedTx = future.getOrThrow() for (node in listOf(a, b)) { assertEquals(signedTx, node.services.validatedTransactions.getTransaction(signedTx.id)) } }
In Corda V1, you need to tell your tests which packages to scan when looking for contract attachments - see https://docs.corda.net/key-concepts-contract-constraints.html#testing. This is a temporary piece of boilerplate only, and is expected to be removed in the future. It is also not required for actual nodes, only for mock nodes.