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,有三行最重要的代码,我曾经为这个问题纠缠了好久,其实他们实现的逻辑也很简单:
- 首先issuer自己签名
- 然后交给其他人签名
- 最后交给公证方形成哈希&广播出去
//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,只有你自己,那么就不需要和其他流交互,只要经过公证即可!