TokenPointer’s & SendStateAndRefFlow()/ReceiveStateAndRefFlow()

Viewed 61

Setup:

  • Corda 4.6
  • Testing with MockNodes

Scenario:

I am building atomic swaps where I exchange FungibleToken’s that point to an EvolvableTokenType for FungibleToken’s representing USD. In the past I have always used SendTransactionFlow()/ReceiveTransactionFlow() like this:

SignedTransaction stx = subFlow(new ReceiveTransactionFlow(otherSideSession, true, StatesToRecord.ALL_VISIBLE));

It works great because it saves all the states to the vault on the receiver’s node – including the reference states (i.e. the EvolvableTokenType that the FungibleToken’s points to) . However in this stackoverflow answer Mike Hearn mentioned:

“You may also use SendStateAndRefFlow, which will reduce the amount of migration work involved in supporting SGX ledger encryption in future.”

So I am trying to switch to SendStateAndRefFlow()/ReceiveStateAndRefFlow().

Problem:

I cannot force the states to save in the vault using ReceiveStateAndRefFlow(). Only the transaction chain is stored in transaction storage.

When I try to add the FungibleToken’s that point to an EvolvableTokenType to the TransactionBuilder on the receiver’s node (the node constructing the swap):

List<StateAndRef<FungibleToken>> inputs = subFlow(new ReceiveStateAndRefFlow<>(otherSideSession));
txBuilder.addInputState(inputs.get(0));

… I will get an error:

java.lang.IllegalStateException: The LinearState with ID 598e1d3e-3b89-428c-b343-21c54a066856 is unknown to this node or it has been exited from the ledger.

The UUID the error refers to is the LinearId of the EvolvableTokenType the FungibleToken’s are pointing to.

Questions:

  1. Are Mike’s comments still valid? Should I avoid using SendTransactionFlow/ReceiveTransactionFlow because SGX will break its functionality?

  2. How can I send and save the EvolvableTokenType the FungibleToken’s point to so the state is available to the TransactionBuilder?

1 Answers

I would still appreciate if R3 or a more experienced CorDapp developer weighed in on this and answered my first question. I am curious if the move to SGX would also break the solution I settled on because its basically a manual SendTransactionFlow/ReceiveTransactionFlow:

Solution 1:

Use the same code in the documentation that informs Observers:

On the node that is selling the FungibleToken's (they have a copy of the SignedTransaction that created the EvolvableTokenType the FungibleToken's point to)

SignedTransaction forwardFtStx = getServiceHub().getValidatedTransactions().getTransaction(forwardFtStateAndRef.getRef().getTxhash());

if(forwardFtStx != null) {
    otherSideSession.send(forwardFtStx);
} else {
    throw new FlowException("Unable to locate SignedTransaction that created ForwardFt");
}

On the node that is buying the FungibleToken's:

SignedTransaction forwardFtStx = otherSideSession.receive(SignedTransaction.class).unwrap(stx -> {

    if (stx.getId().equals(forwardFtStateAndRef.getRef().getTxhash())) {
        return stx;
    } else {
        throw new FlowException("SignedTransaction received by seller that created ForwardFt does not match StateAndRef<ForwardFt> sent earlier");
    }
});

getServiceHub().recordTransactions(StatesToRecord.ALL_VISIBLE, Collections.singletonList(forwardFtStx));

Solution 2:

You could reverse the transaction so the node that has the EvolvableTokenType in its vault builds the TransactionBuilder. The problem with this approach is it won’t handle situations where FungibleToken’s that point to an EvolvableTokenType are being traded for different FungibleToken’s that point to an EvolvableTokenType.

Related