区块链开发之Corda训练营笔记12:Flow习题答案

1、IOUIssueFlow

一、类的成员与构造器

flow是用来定义tx的流转过程的,用来新建tx,然后交给需要的人进行签名,这只是第一步用来生成flow,最关键的还是新建flow,来进行会话

首先我们先进行声明,它扩展了抽象类flowLogic:

kjkjpublic class IOUIssueFlow extends FlowLogic<SignedTransaction> 

如果我现在想issue一个债券,需要指定给定、多少钱,为什么没有issuer,就是谁调用它谁就是issuer?

债券是干嘛的?就是表示你欠我多少嘛,就是指定owner欠issuer多少钱,那么响应flow的那个class是干嘛的?

所以我们可以指定欠钱的人和欠的钱

private final Party owner;
private final int amunt;

然后是构造器:

public IOUIssueFlow(Party owner, int amount) {
        this.owner = owner;UIssueFlow
一、类的成员与构造器
flow是用来定义tx的流转过程的,用来新建tx,然后交给需要的人进行签名,这只是第一步用来生成flow,最关键的还是新建flow,来进行会话

首先我们先进行声明,它扩展了抽象类flowLogic:


kjkjpublic class IOUIssueFlow extends FlowLogic<SignedTransaction> 
如果我现在想issue一个债券,需要指定给定、多少钱,为什么没有issuer,就是谁调用它谁就是issuer?

债券是干嘛的?就是表示你欠我多少嘛,就是指定owner欠issuer多少钱,那么响应flow的那个class是干嘛的?

所以我们可以指定欠钱的人和欠的钱


private final Party owner;
private final int amunt;
然后是构造器:


        this.amount = amount;
    }

这个类总共有三个数据成员,第三个就是一个progressTracker

private final ProgressTracker progressTracker = new ProgressTracker();

它不用用户去指定,用户不知道这些东西,你也不可能要求懂这些底层的东西!但是他有get方法

@Override
public ProgressTracker getProgressTracker() {
    return progressTracker;
}

二、class()方法

我们扩展了flowLogic类,这个类最重要的就是call方法,下面是这个函数的声明

@Suspendable
@Override
public signedTransaction call() throws FlowException 

接下来是分为三大步:

  1. 新建state
    • 将state及其contract加入到tx中去
    • notrary需要放在outputState之前
  2. 新建tx
    • 将command加入到tx中去
  3. tx的流转

I、新建state

此外我们还需要依靠公证人达成共识

Party issuer = getOurIdentity();

接下来是第一步,建立state:

一个iou需要issuer,谁启动这个流、谁就是issuer,流也是由party启动的!

IOUState iouState = new IOUState(issuer, owner, amount);
IOUContract.Commands.Issue command = new IOUContract.Commands.Issue();

II、新建tx

我个人感觉,从便于理解的角度,整个corda,乃至所有的区块链网络,都是以tx为核心的。

corda中的tx需要这些东西:

  • 公证人
  • 输入输出的state
  • 检验命令的contract的引用
  • 命令及其签名者
Party notrary = getServiceHub().getNetworkMapCache().getNotraryIdentities(0);
tx.setNotrary(notrary);
notrary.setOutputState(iouState, IOUContact.ID);
List<PublicKey> requiredSigner = ImmutableList.of(IOUState.getIssuer().getOwingKey());
tx.addCommnad(command,requiredSigner);

III、发送流更新账本

大致分为以下几步:

  • 通过servicehub来验证tx
  • 新建一个会话
  • 将tx签名认证
  • (————————————————————前方高能——————————————)
  • 这应该就开始和responder进行交互

完全签名的tx的意思是不是需要其他方面的签名之后的,所以我们需要建立子流和其他节点进行交互,

所以需要收前面所有签名的流+会话,

最后返回的用完全签名流+单例会话形成的新的终止子流

等等,这张图是不是就是前面那张图的总结????????很有可能啊!!!我只要能弄懂应答流的程序&这个流的交换过程&读读文献我可能就打通了整个corda了!

根据contract验证tx的合法性

txBuidler.verify(getServiceHub())

生成流会话

Flow Session = initiateFlow(owner);

用私钥签署这个交易让它不可改变了

SignedTransaction signedTransaction = getSeriveHub().signInitialTransaction(txBuilder);

2、IOUIssueFlowResponder

2.1、类的声明与构造器

作为被启动流,它必须打上注释:

@InitiatedBy(IOUIssueFlow.class)

该类扩展flowLogic,返回的call的类型是Void

public class IOUIssueFlowResponder extends FlowLogic<Void> {
    
    @Override
    @Suspendable
    public Void call() throws Exception {
        
    }
}

它只有一个私有成员,就是另一边发来的会话?

private final FlowSession otherSide

然后Alt + Insert生成构造器

public IOUIssuerFlowResponder(FlowSession otherSide) {
    this.other = otherSide
}

2.2 call()方法

说来也奇怪,这个call方法我完全看不懂嘞、、、

首先是生成一个stx,生成的方法是subFlow、、,subFlow就是调用子流的意思,一旦子流和它里面的call方法完成,生成结果就调用它呗

/*
*
*/
@Suspendable
    @Throws(FlowException::class)
    open fun <R> subFlow(subLogic: FlowLogic<R>): R {
        subLogic.stateMachine = stateMachine
        maybeWireUpProgressTracking(subLogic)
        logger.debug { "Calling subflow: $subLogic" }
        val result = stateMachine.subFlow(subLogic)
        logger.debug { "Subflow finished with result ${result.toString().abbreviate(300)}" }
        return result
    }

传进去的也是flowLogic

3、完整代码

3.1 IOUIssueFlow

package bootcamp;

import co.paralleluniverse.fibers.Suspendable;
import com.google.common.collect.ImmutableList;
import net.corda.core.flows.*;
import net.corda.core.identity.Party;
import net.corda.core.transactions.SignedTransaction;
import net.corda.core.transactions.TransactionBuilder;
import net.corda.core.utilities.ProgressTracker;

import java.security.PublicKey;
import java.util.List;

import static java.util.Collections.singletonList;

@InitiatingFlow
@StartableByRPC
public class IOUIssueFlow extends FlowLogic<SignedTransaction> {
    private final Party owner;
    private final int amount;

    public IOUIssueFlow(Party owner, int amount) {
        this.owner = owner;
        this.amount = amount;
    }

    private final ProgressTracker progressTracker = new ProgressTracker();

    @Override
    public ProgressTracker getProgressTracker() {
        return progressTracker;
    }

    @Suspendable
    @Override
    public SignedTransaction call() throws FlowException {
        // We choose our transaction's notary (the notary prevents double-spends).
        Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
        // We get a reference to our own identity.
        Party issuer = getOurIdentity();

        /* ============================================================================
         *         TODO 1 - Create our TokenState to represent on-ledger tokens!
         * ===========================================================================*/
        // We create our new TokenState.
        IOUState IOUState = new IOUState(issuer, owner, amount);
        IOUContract.Commands.Issue command = new IOUContract.Commands.Issue();


        /* ============================================================================
         *      TODO 3 - Build our token issuance transaction to update the ledger!
         * ====================ommand(command, IOUState.getIssuer().getOwningKey());    //step5,把命令加到tx
        transactionBuilder.setN=======================================================*/
        // We build our transaction.
        TransactionBuilder transactionBuilder = new TransactionBuilder();
        transactionBuilder.setNotary(notary);
        transactionBuilder.addOutputState(IOUState, IOUContract.ID);    //把IOUState加上跟IOUStateContract的参考值,然后加到transactionBuilder
        List<PublicKey> requiredSigners = ImmutableList.of(IOUState.getIssuer().getOwningKey(), owner.getOwningKey());
        transactionBuilder.addCommand(command, requiredSigners);    //step5,把命令加到tx


        /* ============================================================================
         *          TODO 2 - Write our TokenContract to control token issuance!
         * ===========================================================================*/
        transactionBuilder.verify(getServiceHub());
        FlowSession session = initiateFlow(owner);
        SignedTransaction signedTransaction = getServiceHub().signInitialTransaction(transactionBuilder);

        SignedTransaction fullySignedTransaction = subFlow(new CollectSignaturesFlow(signedTransaction,
                singletonList(session)));
        return subFlow(new FinalityFlow(fullySignedTransaction, singletonList(session)));
    }
}

3.2 IOUIssueFlowResponder

package bootcamp;

import co.paralleluniverse.fibers.Suspendable;
import net.corda.core.flows.*;
import net.corda.core.transactions.SignedTransaction;

@InitiatedBy(IOUIssueFlow.class)
public class IOUIssuerFlowResponder extends FlowLogic<Void> {

    private final FlowSession otherSide;

    public IOUIssuerFlowResponder(FlowSession otherSide) {
        this.otherSide = otherSide;
    }

    @Override
    @Suspendable
    public Void call() throws FlowException {
        SignedTransaction signedTransaction = subFlow(new SignTransactionFlow(otherSide) {
            @Suspendable
            @Override
            protected void checkTransaction(SignedTransaction stx) throws FlowException {

            }
        });
        subFlow(new ReceiveFinalityFlow(otherSide, signedTransaction.getId()));
        return null;
    }
}
上一篇:WPF 窗口 最前端 Topmost Owner


下一篇:Factory Method模式