问题
If a node wants to perform their own specific business logic within one side of a flow, how can this be implemented?
For example if a company wants to call an internal company api to validate the incoming transaction data, can it do this within the flow? If so, does the flow need to be written generically so that all companies using the same Cordapp (and flow) call out to their own internal apis. Maybe the api url is stored in a local config file.
Or is another option to have each company have separate Cordapps containing flows specific to them, which can talk to flows in other Cordapps specific to other companies. This seems like it would get very complex very quickly.
回答1:
Sure. I wrote a whole bunch of stuff on this I can paste here!
Structuring CorDapps
CorDapps can be split into shared and private elements:
Shared CorDapp elements
Typically, the shared elements of a CorDapp will include:
- Data structures and custom types which are composed into state objects or used as payloads to send data between flows
- State and contract definitions must be available to all nodes which may have to verify a transaction containing one or more of the CorDapp's state objects
- Abstract flow definitions are used to define a common representation of a flow whilst hiding the actual implementation of it (which can be private). This is because InitiatedBy flow annotations require the FlowLogic sub-type for the corresponding InitatingFlow on the class path, so a flow initiator can be registered
- Shared utility functions that use node services are typically used from flows and take a ServiceHub parameter - often it makes more sense to do to this than writing another flow or cluttering your existing flows with repetitions of the same method
- Shared flows are often required in situations where a simple workflow is required that doesn't require any customisation and will be carried out by all parties running the CorDapp
It is generally advisable to keep the shared CorDapp JARs as small as possible, this is because the JAR containing the state and contract definitions travels around the network with transactions containing states of the type defined in the JAR. Downstream verifiers of transactions may need to verify transactions containing states they do not transact with, so they don't need the flows on their class path. As such, it makes sense to package up the state and contract definitions (and any dependencies) separately to everything else.
Private CorDapp elements
Private elements of a corDapp usually comprise:
- Bespoke flow implementations
- Corda services
- Any type definitions required for the above
As mentioned above, CorDapp developers can share abstract representations of their flows and keep the implementation private. The flow framework allows parties to implement their own flows providing they conform to a common interface, this is, both the InitiatingFlow
and the InitiatedBy
flow send and receive the same types at the expected points in the flow.
As long as the flows do this, the rest of the implementation can be customised. For example, custom, private implementations might reach out to internal systems or use proprietary types, and as such, they should not be packaged with the shared elements of the CorDapp.
Flow versioning
In addition to the evolution of the platform, flows that run on top of the platform can also evolve. Any flow from which you want to initiate other flows must be annotated with the @InitiatingFlow
annotation, which is defined as:
annotation class InitiatingFlow(val version: Int = 1)
Note, the optional version property, which defaults to 1, to specify the version of the flow. This integer value, which for the moment, exists purely to guide developers, should be incremented whenever there is a release of a flow which has changes that are not backwards compatible with previous versions. A non-backwards compatible change is one that changes the interface of the flow.
Currently, handling flow versioning is left to the CorDapp developers. However, in the future the platform will implement prescribed rules.
What is the interface for a set of flows?
The flow interface defines the sequence of sends and receives between an InitiatingFlow and an InitiatedBy flow as well as the types sent and received. It is best illustrated with a sequence diagram:
In the diagram above, the InitiatingFlow:
- Sends an Int
- Receives a String
- Sends a String
- Receives a CustomType
The InitiatedBy flow does the opposite:
- Receives an Int
- Sends a String
- Receives a String
- Sends a CustomType
Providing both the IntiatingFlow
and the InitiatedBy
flows conform to the sequence defined by interface, the rest of the flows can be implemented in any way and can include proprietary business logic that is not shared with other parties. Indeed, this is the intended way to write flows.
For a example of actually how one would go about doing this, please look here: https://github.com/sollecitom/corda-foreign-exchange-example/blob/master/buyer-api/src/main/kotlin/net/corda/examples/fx/buyer/BuyCurrencyFlowDefinitions.kt
This was written by one of the Corda developers and in the file above, there is an abstract flow definition which has a private implementation known only to the buyer.
来源:https://stackoverflow.com/questions/47835229/can-either-side-of-a-corda-flow-exist-in-separate-cordapps