imaging we have two classes, the Payer Class and the Receiver Class.
is it possible to pass/ send more than one variable by using the method:
FlowSession.send() ?
When trying e.g. the following
sessionWithRecipient.send(Variable1)
sessionWithRecipient.send(Variable2)
it seems that only the first variable will be send to the recipient class.
At the responder flow, I use the command shown below to receive the variable and unwrap it:
val variable1 = initiatorSession.receive<Int>().unwrap { it }
val variable2 = initiatorSession.receive<Int>().unwrap { it }
Could you please help me with a solution to send and receive multiple variables here? Thanks :)
Instead of sending it twice. Just create a wrapper object with all the desired member variables. Then Whitelist this Wrapper object. This way you'll only have to send it once. I find it cleaner this way.
The following works fine, printing Sum is 3. to the console:
#InitiatingFlow
#StartableByRPC
class Initiator(val counterparty: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val counterpartySession = initiateFlow(counterparty)
counterpartySession.send(1)
counterpartySession.send(2)
}
}
#InitiatedBy(Initiator::class)
class Responder(val counterpartySession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val int1 = counterpartySession.receive<Int>().unwrap { it }
val int2 = counterpartySession.receive<Int>().unwrap { it }
logger.info("Sum is ${int1 + int2}.")
}
}
Related
In Corda, the required signers on a transaction can be CompositeKeys instead of regular public keys. How do I create a CompositeKey and make it the required signer on the transaction? And how do I gather the corresponding signatures?
Here is a flow that creates a CompositeKey, makes it the required signer on the transaction, and collects the corresponding signatures:
object OurFlow {
#InitiatingFlow
#StartableByRPC
class Initiator(val otherPartyA: Party, val otherPartyB: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
// We create a composite key that requires signatures from ourselves
// and one of the other parties (each weight is one and the threshold is 2)
val compositeKey = CompositeKey.Builder()
.addKey(ourIdentity.owningKey, weight = 1)
.addKey(otherPartyA.owningKey, weight = 1)
.addKey(otherPartyB.owningKey, weight = 1)
.build(2)
// We make the `CompositeKey` the required signer.
val txBuilder = TransactionBuilder(serviceHub.networkMapCache.notaryIdentities[0])
.addCommand(OurContract.Commands.Create(), compositeKey)
.addOutputState(OurState(ourIdentity, otherPartyA, otherPartyB), OurContract.ID)
val partStx = serviceHub.signInitialTransaction(txBuilder)
// We gather the signatures. Note that we cannot use
// `CollectSignaturesFlow` because:
// * The `CompositeKey` does not correspond to a specific
// counterparty
// * The counterparty may refuse to sign
val sessions = listOf(otherPartyA, otherPartyB).map { initiateFlow(it) }
// We filter out any responses that are not
// `TransactionSignature`s (i.e. refusals to sign).
val signatures = sessions
.map { it.sendAndReceive<Any>(partStx).unwrap { it } }
.filter { it is TransactionSignature }
as List<TransactionSignature>
val fullStx = partStx.withAdditionalSignatures(signatures)
subFlow(FinalityFlow(fullStx))
}
}
#InitiatedBy(Initiator::class)
class Acceptor(val otherPartySession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
otherPartySession.receive<SignedTransaction>().unwrap { partStx ->
// We return either a `TransactionSignature` (if we're willing
// to sign) or `false`.
val payload = if (CONDITION) {
serviceHub.createSignature(partStx)
} else {
false
}
otherPartySession.send(payload)
}
}
}
}
And here is the contract that asserts that the required signer is a CompositeKey, that it has a threshold of two and three children of weight one corresponding to the parties listed in the transaction's output state:
class OurContract : Contract {
companion object {
#JvmStatic
val ID = "com.example.contract.OurContract"
}
override fun verify(tx: LedgerTransaction) {
requireThat {
val command = tx.commands.requireSingleCommand<Commands.Create>()
"There is only one required signer." using (command.signers.size == 1)
"The required signer is a CompositeKey." using (command.signers[0] is CompositeKey)
val signer = command.signers[0] as CompositeKey
"There are only three nodes and weights." using (signer.children.size == 3)
"The threshold is two." using (signer.threshold == 2)
"There is only one output." using (tx.outputStates.size == 1)
"The output is of type OurState." using (tx.outputsOfType<OurState>().size == 1)
val output = tx.outRefsOfType<OurState>().single().state.data
val expectedNodesAndWeights = listOf(output.partyA, output.partyB, output.partyC).map {
CompositeKey.NodeAndWeight(it.owningKey, 1)
}
"All three parties are children with weight 1." using (signer.children.containsAll(expectedNodesAndWeights))
}
}
interface Commands : CommandData {
class Create : Commands
}
}
And finally, here is our state definition:
class OurState(val partyA: Party, val partyB: Party, val partyC: Party) : ContractState {
override val participants = listOf(partyA, partyB, partyC)
}
I’m new to Corda. Is there a direct way to execute a repayment as a subflow on the other side back to the sender of a certain amount of cash, when directly calling the recipient node within the CashPaymentFlow, e.g. something like this:
recipient.run {
subFlow(CashPaymentFlow(amount, sender ,anonymous))
}
(This is not working, it’s just an example). I need a more dynamic solution for using it within the demobench. The recipient node for the initital payment is chosen from the demobench UI. The problem is to automatically call or reference to the other side’s node and ask it to execute a repayment (by using e.g. the cashPaymentFlow), when executing the initial payment from the sender side. I now that I can manually “go” to the receiver node and execute a payment back to the sender via the UI or terminal, but this is not the intention.
You can achieve this by making the repayment part of the same flow as the initial payment, as follows:
#InitiatingFlow
#StartableByRPC
class Payer(val initialAmount: Amount<Currency>, val changeAmount: Amount<Currency>, val recipient: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow(CashPaymentFlow(initialAmount, recipient))
val sessionWithRecipient = initiateFlow(recipient)
sessionWithRecipient.send(changeAmount)
}
}
#InitiatedBy(Payer::class)
class Recipient(val payerSession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val changeAmount = payerSession.receive<Amount<Currency>>().unwrap { it }
subFlow(CashPaymentFlow(changeAmount, payerSession.counterparty))
}
}
I would like to pass another variable along with ‘changeAmount’. Is this possible? I tried doing it this way:
#InitiatingFlow
#StartableByRPC
class Payer(val initialAmount: Amount<Currency>, val changeAmount:Amount<Currency>, val recipient: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow(CashPaymentFlow(initialAmount, recipient))
val sessionWithRecipient = initiateFlow(recipient)
sessionWithRecipient.send(changeAmount)
sessionWithRecipient.send(delay) //second variable
}
}
#InitiatedBy(Payer::class)
class Recipient(val payerSession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val changeAmount = payerSession.receive<Amount<Currency>>().unwrap { it }
val delay = payerSession.receive<Duration>().unwrap { it }
for (i in 1..10) //the 10 automated paybacks
{subFlow(CashPaymentFlow(changeAmount, payerSession.counterparty))
sleep(delay)} //usage of the second variable
}
}
Is there a pattern/technique that supports unit testing shared "initiating flows" that have been implemented in a "shared cordapp.jar" that have multiple corresponding private "responding flows " each of which is implemented in its own "private party name cordapp.jar" ? Hope this question makes sense.
Terminology is as per Can either side of a Corda flow exist in separate Cordapps?.
Thanks for all info.
John
Sure. You just have to define a dummy response flow and register it on each node as an initiated flow:
#InitiatedBy(MyInitiator::class)
class MyTestResponder(val counterpartySession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
// Implement flow logic here.
}
}
class FlowTests {
lateinit var network: MockNetwork
lateinit var a: StartedNode<MockNode>
lateinit var b: StartedNode<MockNode>
#Before
fun setup() {
setCordappPackages("my.package")
network = MockNetwork()
val nodes = network.createSomeNodes(2)
a = nodes.partyNodes[0]
b = nodes.partyNodes[1]
nodes.partyNodes.forEach {
it.registerInitiatedFlow(MyTestResponder::class.java)
}
network.runNetwork()
}
#After
fun tearDown() {
network.stopNodes()
unsetCordappPackages()
}
#Test
fun `example test`() {
val flow = MyInitiator(b.info.chooseIdentity())
val future = a.services.startFlow(flow).resultFuture
network.runNetwork()
future.getOrThrow()
}
}
I want to print values of properties of my class.
fun print() {
val cl = this::class
cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
println("${it.name} = ${it.get(this)}")
}
}
When I try to build this code I get compiler error:
Error:(34, 40) Kotlin: Out-projected type 'KProperty1<out SomeClass, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'
When I change this to class name SomeClass everything is fine
fun print() {
val cl = SomeClass::class
cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
println("${it.name} = ${it.get(this)}")
}
}
So the problem is that compiler changers type of this::class to KClass<out SomeClass> instead of using KClass<SomeClass>. Any idea why does it happen?
The reason for this difference is that, when you use the SomeClass::class reference, it is sure to be the class token representing SomeClass and not one of its possible derived classes, therefore it is KClass<SomeClass> without type projections.
But this::class written in a function of an open or abstract class or an extension function can return a class token of a derived class, therefore, to ensure type safety, the type is out-projected: KClass<out SomeClass> means that the actual type argument can be SomeClass or its subtype.
Example:
open class A {
fun f() {
println(this::class) // KClass<out A> because it can be KClass<B>
}
}
class B : A()
B().f()
I have the following function to access a property's delegate. It uses Kotlin reflection to get a property's name and Java reflection to get the field.
fun Any.getDelegate<T>(prop: KProperty<T>): Any {
return javaClass.getDeclaredField("${prop.name}\$delegate").let {
it.setAccessible(true)
it.get(this)
}
}
The method is used like this:
val delegate = a.getDelegate(A::b)
However, I would prefer to use it like this:
val delegate = a.b.delegate
The problem with the code above is getting the property name of a.b and getting the instance a from a.b. From what I know about Kotlin, this is probably not possible, however I'd like to see if I can clean up my function at all.
To give a bigger picture of what I'm trying do here's my complete code. I want an observable delegate to which I can add and remove observers using the delegate reference and without creating addition variables.
fun Any.addObservable<T>(prop: KProperty<T>, observer: (T) -> Unit) {
getObservableProperty(prop).observers.add(observer)
}
fun Any.getObservableProperty<T>(prop: KProperty<T>): ObservableProperty<T> {
return getDelegate(prop) as ObservableProperty<T>
}
fun Any.getDelegate<T>(prop: KProperty<T>): Any {
return javaClass.getDeclaredField("${prop.name}\$delegate").let {
it.setAccessible(true)
it.get(this)
}
}
class ObservableProperty<T>(
initialValue: T,
initialObservers: Array<(T) -> Unit> = emptyArray()) : ReadWriteProperty<Any?, T> {
private var value = initialValue
public val observers: MutableSet<(T) -> Unit> = initialObservers.toHashSet()
public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
return value
}
public override fun set(thisRef: Any?, desc: PropertyMetadata, value: T) {
this.value = value
observers.forEach { it(value) }
}
}
class A() {
var b by ObservableProperty(0)
}
fun main(args: Array<String>) {
val a = A()
a.addObservable(A::b) {
println("b is now $it")
}
a.b = 1
a.b = 2
a.b = 3
}
Edit:
I just realized that the function also isn't strict because the property delegate field name is referenced by KProperty name, which doesn't require a strong reference to the enclosing class. Here's an example to demonstrate the problem:
class A() {
var foo by ObservableProperty(0)
}
class B() {
var foo by ObservableProperty(0)
}
fun main(args: Array<String>) {
val a = A()
a.addObservable(B::foo) {
println("b is now $it")
}
a.foo = 1
a.foo = 2
a.foo = 3
}
This compiles and runs without error because A::foo and B::foo both result in a field string of "foo$delegate.
Right now reflection is all we can do to get to the delegate object. We are designing a language feature to have direct access to delegate instance, but it's long way to go.
This is how you get the name of a Kotlin Property (although only with an instance of the class). This part will be useful to anyone arriving at this question purely based off its title.
class Stuff(val thing: String)
val stuff = Stuff("cool stuff")
val thingFieldName = "${stuff.thing}\$delegate"
// value of thingFieldName is now "thing"
In terms of getting the delegate itself easier, they say you can now do this:
class Foo {
var bar: String by ReactiveProperty<String>()
}
val foo = Foo()
val bar = foo.bar
val barDelegate = ... // foo.bar$delegate
See ticket.