1 VerySimpleFlow

好像还是由某个party出发/调用某个flow的呀,可是节点之间如何利用flow进行交互呢?

public class verySimpleFlow extends FlowLogic<Void> {
    
    @Suspendable
    public Void call() throws Exception {
        int a = 5;
        int b = 6;
        return a+b;
    }
}
public class verySimpleFlow extends FlowLogic<Void> {
    
    @Suspendable
    public Void call() throws Exception {
        int a = 5;
        int b = 6;
        return a+b;
    }
}

首先需要加上@suspendable标识

其次,要在开头指定谁可以调用这个flow

@InitiatingFlow
@StartableByRPC
@InitiatingFlow
@StartableByRPC

InitiatingFlow:可以被任意人调用

StartableByRPC:可以被PRC调用

2 TwoPartyFlow

需求:A向B发送一个数字,B将只是单纯地将这个数字返回给A

2.1 TwoPartyInitatingFlow

这里不需要发送txBuilder,因为这里的需求就是发送数字,问题是、、、、subflow怎么用?

就是如何A如何召唤出使用B的subflow?b又如何相应它?????

!!!!第一件事情就是加上@Suspendable

1、加上@Suspendable

2、确定谁来触发它

  • 主动者:@InitiatingFlow@StartableByRPC
  • 被动者:@InitiatedBy(TwoPartyInitiatingFlow.class)

这里很好理解啊,我需要指定一个接收者:

private Party counterparty;
private Party counterparty;

然后是构造器:

public TwoPartyInitiatingFlow(Party counterParty) {
    this.counterParty = counterParty;
}
public TwoPartyInitiatingFlow(Party counterParty) {
    this.counterParty = counterParty;
}

接着在call方法里,通过initateFlow()来新建一个会话,以此来和它进行通信

public Integer call() throws Exception {
    FlowSession flowSession = initiate(counterParty);
}
public Integer call() throws Exception {
    FlowSession flowSession = initiate(counterParty);
}

然后定义数字并发送过去:

int number = 5;
session.send(number);


2.2 TwoPartyResponderFlow

然后我们开始来写响应流

这里的私有成员不需要再有party,因为已经建立了会话了

private FlowSession flowSession
private FlowSession flowSession

然后是构造器:

public TwoPartyResponderResponderFlow (FlowSeesion flowSession) {
    this.flowSession = flowSession;
}
public TwoPartyResponderResponderFlow (FlowSeesion flowSession) {
    this.flowSession = flowSession;
}

然后接收数字就可以了:

public Void call() throws Exception {
    int recevieNumber = flowSeion.receive(Integer.class).unwrap(it-> {
        if(it>10)
            throw new IllegalArgumentException("Number is too high");
        return it;
    })
     int receivedIntPlusOne = receiveInt + 1;
    return 
}
public Void call() throws Exception {
    int recevieNumber = flowSeion.receive(Integer.class).unwrap(it-> {
        if(it>10)
            throw new IllegalArgumentException("Number is too high");
        return it;
    })
     int receivedIntPlusOne = receiveInt + 1;
    return 
}

unwrap其实是进行验证,这里可以写一个简单,如果大于10就返回错误,结构类似于:unwrap(it->{判断与抛出错误})

.unwrap(it->{
    if(it > 10)
        throw new IllegalArgumentException("Number is too high");
})
.unwrap(it->{
    if(it > 10)
        throw new IllegalArgumentException("Number is too high");
})

然后将接收到的数字加一并返回

int ans = receiveNumber + 1;
flowSession.send(ans);
int ans = receiveNumber + 1;
flowSession.send(ans);

2.1 TwoPartyInitatingFlow

这时我们再回到初始流,接受并返回

int ans = flowSession.receive(Integer.class).unwrap(it->it);
return ans;
int ans = flowSession.receive(Integer.class).unwrap(it->it);
return ans;


3、ServiceHub

这里介绍另一个重要的组件——servicehub,顾名思义就是很多服务的集合,比如:

3.1 几个比较重要的service

valutService:资料库、读取某个节点中所有的资料

KeyManagementService:得到该点的所有公钥

NetworkMapCache:发现在一个corda网络存在的节点

3.2 service使用实例

3.2.1 VaultService

比如读取该节点的所有的houstate:

serviceHub.getVaultService().queryBy(HouState.class).getState();
serviceHub.getVaultService().queryBy(HouState.class).getState();

将其存在一个list中,注意,因为它都已经commit掉了,所以会有notrary的索引

List<StateAndRef<HouseState>> stateSFromVault= serviceHub.getVaultService().queryBy(HouState.class).getState();
List<StateAndRef<HouseState>> stateSFromVault= serviceHub.getVaultService().queryBy(HouState.class).getState();

3.2.2 NetworkMapCache

比如根据名字得到一个公证人:

Party notrary = serviceHue().getNetworkMapCache().getNodeByLegalName()
Party notrary = serviceHue().getNetworkMapCache().getNodeByLegalName()

这里所谓的“legalName”指的就是cordaX500Name,这是一个指定了格式的名字,因为没有,所以我们得生成一个:

CordaX500Name aliceName = new CordaX500Name("Alice", "shanghai","CN");
CordaX500Name aliceName = new CordaX500Name("Alice", "shanghai","CN");

不过通过名字只能找到node,需要先getIdentity

NodeInfo aliceNode = serviceHub.getNetworkMapCache().getNodeByLegalName(aliceName);
Party alice = aliceNode.getLegaldentities().get(0);
NodeInfo aliceNode = serviceHub.getNetworkMapCache().getNodeByLegalName(aliceName);
Party alice = aliceNode.getLegaldentities().get(0);

因此,如果你想直接和指定的node进行交互,就可以使用networkMapCache

3.2.3 MyInfo

获取平台版本:

int platformVersion = serviceHub().getMyInfo().getPlatformVersion();
int platformVersion = serviceHub().getMyInfo().getPlatformVersion();

4、IOUIssuerFlow逻辑

  • 选择公证人
  • 我们要编写的代码
  • 创建txBuilder
  • 生成IOUState
  • 将IOUState及其contract的引用传给txBuilder
  • 生成命令
  • 将IOUState的isssuer作为签名者签署commnad
  • 将命令添加到tx
  • 验证交易tx
  • 签署交易tx
  • 传给公证再记录交易

来到IOUIssuerFlow,有三行最重要的代码,我曾经为这个问题纠缠了好久,其实他们实现的逻辑也很简单:

  1. 首先issuer自己签名
  2. 然后交给其他人签名
  3. 最后交给公证方形成哈希&广播出去
//we sign the tx with our private key, making it immutable
SignedTransaction signedTransaction = getServiceHub().signInitialTransaction(transactionBuilder);


//The counterparty signs the transaction
SignedTransaction fullySignedTransaction = subFlow(new CollectSignaturesFlow(signedTransaction, singleton(session))));

//We get the tx notatried & record automatically by the platform
return subFlow(new FinalityFlow(fullSignedTransaction, singletonList(session)));
//we sign the tx with our private key, making it immutable
SignedTransaction signedTransaction = getServiceHub().signInitialTransaction(transactionBuilder);


//The counterparty signs the transaction
SignedTransaction fullySignedTransaction = subFlow(new CollectSignaturesFlow(signedTransaction, singleton(session))));

//We get the tx notatried & record automatically by the platform
return subFlow(new FinalityFlow(fullSignedTransaction, singletonList(session)));

是不是可以这么理解,一个issuerState需要两方来签署认可,一个是issuer,一个是owner,之所以需要开一个flow向owner发送session是因为这个需要它的签名。但是,如果你的一个state,只有你自己,那么就不需要和其他流交互,只要经过公证即可!