I am trying to identify which CorDapps are running on a node
this information is displayed in the console and in the log during startup Loaded CorDapps : blah-1.1.20, corda-core-2.0.0
Is there a programmatic way to get that list? (RPC?)
You can retrieve a list of flows registered on the node using the CordaRPCOps.registeredFlows method.
If you want a list of the CorDapp names, you can write a flow that reads them directory from the node's cordapps directory, as follows:
#InitiatingFlow
#StartableByRPC
class ReadFilesFlow : FlowLogic<List<String>>() {
override val progressTracker = ProgressTracker()
#Suspendable
override fun call(): List<String> {
val cordappDirectory = File("./cordapps")
val cordappFiles = cordappDirectory.listFiles()
return cordappFiles.map { file -> file.name }
}
}
You would then retrieve the list of CorDapps via RPC using:
CordaRPCOps.startFlowDynamic(ReadFilesFlow::class.java)
Note that this wouldn't work in the case of flow tests with a mock network, as the current directory (./) wouldn't refer to the node's base directory.
Related
After updating to Corda 4.1 from 3.3, when I run the node with deployNodes I get the following error:
[main] internal.NodeStartupLogging.invoke - Exception during node startup: Unable to determine which flow to use when responding to: com.example.CreateDealFlow.Sender. [com.example.CreateDealFlow.Receiver, com.example.CreateDealFlow.Receiver] are all registered with equal weight. [errorCode=mnl04m, moreInformationAt=https://errors.corda.net/OS/4.1/mnl04m]
there is no any information when I go through URL in error.
My flow looks something like this(I have simplified the code and removed custom logics, just what matters for this case is there)
object CreateDealFlow {
#InitiatingFlow
#StartableByService
class Sender(private val dataHolder: DealDataHolder) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val sender = PartyAndCompany(dataHolder.senderUUID, ourIdentity)
val receiver = PartyAndCompany(dataHolder.receiverUUID, getPartyFromX500String(dataHolder.receiverX500String))
val txBuilder = buildTransaction(sender = sender, receiver = receiver)
txBuilder.verify(serviceHub)
val partiallySignedTransaction = serviceHub.signInitialTransaction(txBuilder)
val parties = partiallySignedTransaction.tx.outputStates.first().participants
val (fullySignedTx, flowSessions) = collectSignaturesFromReceivers(partiallySignedTransaction, parties)
return subFlow(FinalityFlow(fullySignedTx, flowSessions, FinalityFlow.tracker()))
}
#Suspendable
fun buildTransaction(sender: PartyAndCompany, receiver: PartyAndCompany): TransactionBuilder {
}
}
#InitiatedBy(CreateDealFlow.Sender::class)
class Receiver(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
}
val txWeJustSigned = subFlow(signTransactionFlow)
return subFlow(ReceiveFinalityFlow(otherPartyFlow, expectedTxId = txWeJustSigned.id))
}
}
}
Resolved by Andranik himself 🙂
The issue was due to having 3 CorDapps (workflows, contracts, workflows-2).
workflows-2 depends on workflows. To do so it was using a compile dependency. When delpoyNodes was run this was building in the workflows code into workflows-2 (a.k.a fat jarring). This then failed at runtime since there were now two CorDapps that contained a flow found in workflows.
To resolve this, cordaCompile was used. This included the workflows module as a compile time dependency but does not build it into the jar. When the node is ran, the flow is loaded from the workflows CorDapp and loaded onto the classpath where workflows-2 can now also access it.
Where to set consensus algorithm in corda? Answer is expecting in a
technical point of view and if we are working with multiple consensus algorithm then where we switch these algorithms?
As of Corda 3, implementing a custom notary service is still an experimental feature. The APIs for implementing custom notary services may change in the future. Additionally, customising Raft or BFT notaries is not yet fully supported. If you want to write your own Raft notary, you will have to implement a custom database connector (or use a separate database for the notary), and use a custom configuration file.
The first step in implementing a custom notary is to create a notary service class in your CorDapp (i.e. one annotated with #CordaService). The Corda node scans for these service classes and initialises them at srart-up. The custom notary service class should provide a constructor taking an AppServiceHub and a PublicKey:
#CordaService
class MyCustomValidatingNotaryService(override val services: AppServiceHub, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
override val uniquenessProvider = PersistentUniquenessProvider()
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?> = MyValidatingNotaryFlow(otherPartySession, this)
override fun start() {}
override fun stop() {}
}
The next step is to write the notary service flow. You are free to copy and modify the existing built-in flows such as ValidatingNotaryFlow, NonValidatingNotaryFlow, or implement your own from scratch (following the NotaryFlow.Service template). Below is an example of a custom flow for a validating notary service:
class MyValidatingNotaryFlow(otherSide: FlowSession, service: MyCustomValidatingNotaryService) : NotaryFlow.Service(otherSide, service) {
/**
* The received transaction is checked for contract-validity, for which the caller also has to to reveal the whole
* transaction dependency chain.
*/
#Suspendable
override fun receiveAndVerifyTx(): TransactionParts {
try {
val stx = receiveTransaction()
val notary = stx.notary
checkNotary(notary)
verifySignatures(stx)
resolveAndContractVerify(stx)
val timeWindow: TimeWindow? = if (stx.coreTransaction is WireTransaction) stx.tx.timeWindow else null
return TransactionParts(stx.id, stx.inputs, timeWindow, notary!!)
} catch (e: Exception) {
throw when (e) {
is TransactionVerificationException,
is SignatureException -> NotaryInternalException(NotaryError.TransactionInvalid(e))
else -> e
}
}
}
#Suspendable
private fun receiveTransaction(): SignedTransaction {
return otherSideSession.receive<NotarisationPayload>().unwrap {
val stx = it.signedTransaction
validateRequest(NotarisationRequest(stx.inputs, stx.id), it.requestSignature)
stx
}
}
#Suspendable
private fun resolveAndContractVerify(stx: SignedTransaction) {
subFlow(ResolveTransactionsFlow(stx, otherSideSession))
stx.verify(serviceHub, false)
customVerify(stx)
}
private fun verifySignatures(stx: SignedTransaction) {
val transactionWithSignatures = stx.resolveTransactionWithSignatures(serviceHub)
checkSignatures(transactionWithSignatures)
}
private fun checkSignatures(tx: TransactionWithSignatures) {
try {
tx.verifySignaturesExcept(service.notaryIdentityKey)
} catch (e: SignatureException) {
throw NotaryInternalException(NotaryError.TransactionInvalid(e))
}
}
private fun customVerify(stx: SignedTransaction) {
// Add custom verification logic
}
}
To enable the service, add the following to the node's configuration:
notary : {
validating : true # Set to false if your service is non-validating
custom : true
}
I was performing testing on corda observer node. On IOU issue, put call of flow for observer. same thing on IOU lender transfer flow (Flow for changing lender property to the new Party).
I issue IOU From partyA to PartyB. On observer node stateAndRef gets displayed too.
but when performed transferred IOU, no change gets displayed on observer node. It's still showing old state.
Does observer node keep unconsume states only in vault or consume/unconsumed transaction both?
below code is working for one flow IOU issue only not for other flow:
I am referring IOU example here
Below is the code I called from each Flow:
object BroadcastTransaction {
#InitiatingFlow
class BroadcastTransactionToObservers(private val stx: SignedTransaction, private val observers: List<Party>) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val sessions = observers.map { initiateFlow(it) }
sessions.forEach { subFlow(SendTransactionFlow(it, stx)) }
}
}
#InitiatedBy(BroadcastTransactionToObservers::class)
class RecordTransactionAsObserver(private val otherSession: FlowSession) :FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow( ReceiveTransactionFlow(
otherSideSession = otherSession,
checkSufficientSignatures = true,
statesToRecord = StatesToRecord.ALL_VISIBLE
)
)
}
}
}
I have checked logs for node getting not enough signature even after put call to observer flow just after finalityflow call...plz help in this regard?
Finally found my mistake. In logs i got error "Insufficient signature corda". I had passes signedsignature after finalityflow but not passed finalityflow result to above mention flow.
Can I find a state with a txhash ? I want something like this : val state = rpcOps.findStateFromTXhash(txhash)
I have found that there is a type of state called linearState that have a linearId property . There is also a hash property but I don't know if it is what I search.
In your flows, you can do getServiceHub().loadState() here you can pass in the securehash to get your state. not sure if we can do something like that directly from CordaRpcConnection object.
Your state will have a linearId if it's a type of linear state. You can search your state using the linearId easily.
read here.
I'd recommend you read more about states to see what best suits your requirement. Link
There is no RPC operation to load a transaction's states given a transaction ID.
However, you can write a flow to do this, as follows, then invoke this flow via RPC:
#InitiatingFlow
#StartableByRPC
class GetStatesFromTransactionFlow(val transactionID: SecureHash) : FlowLogic<List<ContractState>>() {
#Suspendable
override fun call(): List<ContractState> {
val signedTransaction = serviceHub.validatedTransactions.getTransaction(transactionID)
if (signedTransaction == null) {
throw FlowException("Transaction does not exist in node's transaction storage.")
}
val ledgerTransaction = signedTransaction.toLedgerTransaction(serviceHub)
val inputs = ledgerTransaction.inputs.map { it.state.data }
val outputs = ledgerTransaction.outputs.map { it.data }
return inputs + outputs
}
}
Currently we are planning to have one "Draft" version of contract which will not be sent to the counterparty and the initiator can make any changes before send it to the network, so this should be as one "unshared fact". As we know Corda and the vault is used for shared facts, so here I am not sure whether we can still use vault to store this type of "unshared fact", my idea as below and I already can make this work in my local based on the tutorial CorDapp, but would like to get some inputs from other Corda team/experts.
The main change is in the initiator flow:
Initiate the create command's only with the initiator's key
Do not invoke the "CollectSignaturesFlow" so this will not be sent to any others
Invoke "FinalityFlow" after the verify(), so this will be committed to the ledger
Below are the codes for above mentioned points.
override fun call(): SignedTransaction {
// We create a transaction builder
val txBuilder = TransactionBuilder()
val notaryIdentity = serviceHub.networkMapCache.getAnyNotary()
txBuilder.notary = notaryIdentity
// We create the transaction's components.
val ourIdentity = serviceHub.myInfo.legalIdentity
val iou = TemplateState(iouValue, ourIdentity, ourIdentity)
val txCommand = Command(TemplateContract.Create(), listOf(ourIdentity.owningKey))
// Adding the item's to the builder.
txBuilder.withItems(iou, txCommand)
// Verifying the transaction.
txBuilder.toWireTransaction().toLedgerTransaction(serviceHub).verify()
// Signing the transaction.
val partSignedTx = serviceHub.signInitialTransaction(txBuilder)
// Finalising the transaction.
return subFlow(FinalityFlow(partSignedTx)).single()
}
You can indeed create an unshared fact in Corda! The key here is in the state's participants list. Just add yourself in the participants list and only your public key to the command. Here's a simple example:
//Contract and State.
class UnsharedFact: Contract {
override val legalContractReference: SecureHash = SecureHash.zeroHash
override fun verify(tx: TransactionForContract) = Unit // Stubbed out.
class Create: CommandData
data class State(val parties: Set<Party>): ContractState {
override val contract: Contract get() = UnsharedFact()
override val participants: List<AbstractParty> get() = parties.toList()
fun addParty(newParty: Party) = copy(parties = parties + newParty)
}
}
// Create flow.
#InitiatingFlow
#StartableByRPC
class CreateUnsharedFact(): FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val me = serviceHub.myInfo.legalIdentity
val notary = serviceHub.networkMapCache.getAnyNotary()
val state = UnsharedFact.State(setOf(me))
val command = Command(UnsharedFact.Create(), listOf(me.owningKey))
val utx = TransactionBuilder(notary = notary).withItems(state, command)
val stx = serviceHub.signInitialTransaction(utx)
return subFlow(FinalityFlow(stx)).single()
}
}
When FinalityFlow is called, you will be the only node that receives the output state.
If you wish to subsequently involve another party then you can create a new version of the state using the addParty method on UnsharedFact.State. Then, create a new transaction, adding the original state as the input and the new version (with the new party) as the output. When this transaction is finalised (notarised) then both parties will have a copy in their respective vaults. Now, I guess the name 'UnsharedFact' is inappropriate :)
You can also remove parties using a similar approach.