快速使用指南
点融区块链云服务平台现在支持在公有云上快速部署一套基于Corda的分布式账本系统,目前是开发测试版。开发者可以用它来体验Corda和CorDapp的基本功能,以及研究Corda公有云方案的可行性。需申明的是该系统仅用于开发测试目的,不适用于生产系统。
1. 通过点融区块链云服务部署Corda
第一步:登录点融区块链云服务平台。然后点击"创建区块链"按钮。
第二步:完善创建Corda区块链的配置信息。填写区块链名称,选择“配置类型”为“开发者配置-Corda3.0”将切换到相关的配置模版。开发者配置的节点数量不可修改。接着点击“下一步”。
第三步:配置节点信息。可以修改节点名,它代表参与网络的组织,建议以组织名命名。还需要为每个普通节点设置RPC访问的用户名和密码,请注意服务端不会保存您的用户和密码,请妥善保管它们。接着点击“下一步”。
第四步:设置节点硬件配置以及公有云提供商。对于开发者配置,目前仅支持Ucloud。接着点击“下一步”。
第五步:确认将创建的节点列表。点击"创建"按钮
第六步:进入Corda区块链详情页面。其中列出了每个节点的当前部署状态,如果部署成功,状态栏将显示“服务正在运行”。页面中也显示了每台虚拟机的ssh初始登录密码(用户名为ubuntu),请马上登录虚拟机修改为自己的密码。
第七步:检查Corda网络是否正常。平台已默认部署了Corda官网提供的java版的cordapp应用示例(cordapp-example-0.1.jar, 来源于这里),并在每个普通节点上部署并启动了corda-webserver,因此可以通过访问网页来发起对cordapp-example的调用。web-server默认端口为10007,请打开浏览器,输入以下网址:
http://normal_node_ip_address:10007/web/example
会出现以下页面:
部署说明
- 系统版本为Corda v3.0开源版本
- 该系统一共创建4个节点,包括: 1个公证节点(notary node)、和3个普通节点(general node)。这些节点分别属于不同的组织,平台已为您默认生成了相关的证书和密钥。
- 用户可以在网站上指定RPC访问的用户名和密码。开发者配置没有开放细粒度设置RPC访问权限的功能,默认权限是"ALL"。
关于数据安全风险的申明: corda-webserver只会部署在开发测试版中,目的是为了开发测试的便利性。它没有采用设置密码、或使用SSL等保护措施,所以请不要使用敏感数据进行测试,以发生免数据泄漏的风险。同样为了开发测试的便利性,开发测试版也没有对RPC调用使用SSL进行保护。
安装路径
- 查看区块链详情页面,通过ssh的用户名和密码登录到节点。
- Notary节点和普通节点的corda安装路径(也即工作目录):/home/setup/config
- 日志文件路径:/home/setup/config/logs
- 以下是某普通节点的工作目录下的文件清单:
ubuntu@10-23-182-145:/home/setup/config$ tree .
.
|-- additional-node-infos
| |-- nodeInfo-777DA369F066FE34BEDE3E6334A1006A4026A02DD76AFA798204BD015C9965DE
| |-- nodeInfo-B1F1FD9F15FCFDE1C9EE7A59504A44D669AB67B655597D60B691138E9C12E93C
| |-- nodeInfo-E4477B559304AADFC0638772C0956A38FA2E2A7A5EB0E65D0D83E5884831879A
| `-- nodeInfo-FFBDA48A181D794D611797BE2B7BD976BD1C5DA477611401F6F0D1F049E8896E
|-- artemis
| |-- bindings
| | |-- activemq-bindings-1.bindings
| | `-- activemq-bindings-2.bindings
| |-- journal
| | |-- activemq-data-1.amq
| | |-- activemq-data-2.amq
| | `-- server.lock
| `-- large-messages
|-- brokers
| `-- rpc
| |-- bindings
| | |-- activemq-bindings-1.bindings
| | `-- activemq-bindings-2.bindings
| |-- journal
| | |-- activemq-data-1.amq
| | |-- activemq-data-2.amq
| | `-- server.lock
| `-- large-messages
|-- certificates
| |-- nodekeystore.jks
| |-- sslkeystore.jks
| `-- truststore.jks
|-- corda.jar
|-- cordapps
| |-- corda-finance-corda-3.0.jar
| `-- cordapp-example-0.1.jar
|-- corda-webserver.jar
|-- logs
| |-- node-info-gen.log
| `-- node-localhost.log
|-- network-parameters
|-- node.conf
|-- nodeInfo-777DA369F066FE34BEDE3E6334A1006A4026A02DD76AFA798204BD015C9965DE
|-- persistence.mv.db
|-- process-id
`-- shell-commands
2. 使用RPC方式访问已在公有云部署的Corda
cordapp-example是Corda官方提供的一个示例程序。它通过Gradle插件,可以在本地运行一个Corda网络、部署cordapp-example应用程序,并通过RPC(或者web)调用IOU智能合约。详细请看这里。当你成功地在点融区块链云服务平台部署了Corda系统之后,只需要对cordapp-example做很小的修改就可以使用它来调用已部署在公有云上的cordapp-example应用程序。具体步骤如下:
- 下载cordapp-example的源代码(如果已下载,可跳过)
git clone https://github.com/corda/cordapp-example
- 进到cordapp-example根目录
cd cordapp-example
- 修改java-source目录下的build.gradle文件,将ExampleClient的目的地址改为公有云上某个普通节点的RPC通信地址。
cd java-source
vi build.gradle
将 gradle task runExampleClientRPCJava的参数args改为公有云上某个普通节点的RPC通信地址(格式为:虚拟机的外网地址:10006,10006为默认RPC端口)。
task runExampleClientRPCJava(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'com.example.client.ExampleClientRPC'
args '106.75.223.77:10006'
}
- 修改java代码,设置RPC访问的用户名和密码。
cd cordapp-example/java-source/src/main/java/com/example/client
vi ExampleClientRPC.java
将代码中的用户名和密码改为您设置的RPC用户名和密码。
public static void main(String[] args) throws ActiveMQException, InterruptedException, ExecutionException {
... omitted ...
// Can be amended in the com.example.Main file.
final CordaRPCOps proxy = client.start("user1", "111111").getProxy();
... omitted ...
}
- 最后运行ExampleClientRPC,访问公有云上的cordapp-example。
cd cordapp-example
./gradlew runExampleClientRPCJava
- 该程序将获取所有发生在节点上的交易信息,并继续监听交易行为,并将发生的交易打印到日志。此时,你可以打开浏览器,访问普通节点的web地址( http://normalnodeip_address:10007/web/example ),发起IOU调用,然后观察日志的变化。
richiedeMacBook-Pro:cordapp-example richie$ ./gradlew runExampleClientRPCJava
Starting a Gradle Daemon, 1 busy Daemon could not be reused, use --status for details
> Task :java-source:runExampleClientRPCJava
I 16:51:12 1 RPCClient.logElapsedTime - Startup took 3428 msec
I 16:51:15 1 ExampleClientRPC.iou - Transaction to (O=PartyC, L=Paris, C=FR) committed to ledger, txId=9725978C41DD6C80F937E6A005EA3AD149C798BFF5A7F7F678E0EC6B95232CF2
> :I 16:51:16 1 ExampleClientRPC.iou - Transaction to (O=PartyB, L=New York, C=US) committed to ledger, txId=5E0E189AE38872B8B30C65E529B90F86032AFF618E1ECE6292DCCC3BA89F4B98
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=20, lender=O=PartyB, L=New York, C=US, borrower=O=PartyA, L=London, C=GB, linearId=f53c461d-75b9-431e-a685-fa4ae96b2420)
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=20, lender=O=PartyB, L=New York, C=US, borrower=O=PartyA, L=London, C=GB, linearId=dc27cca5-dbd2-42b6-9199-e543304ce06c)
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=20, lender=O=PartyB, L=New York, C=US, borrower=O=PartyA, L=London, C=GB, linearId=610b2454-7956-4429-9766-5479b8a6e1f3)
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=98, lender=O=PartyA, L=London, C=GB, borrower=O=PartyC, L=Paris, C=FR, linearId=04aa9414-0abe-4745-b5ce-baa3a2757cad)
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=11, lender=O=PartyA, L=London, C=GB, borrower=O=PartyB, L=New York, C=US, linearId=34be94a8-27f1-458b-9b92-c1a8f7260b23)
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=69, lender=O=PartyA, L=London, C=GB, borrower=O=PartyC, L=Paris, C=FR, linearId=4a7382c5-db22-4899-9727-6de71c17bf6f)
I 16:51:16 1 ExampleClientRPC.logState - IOUState(value=16, lender=O=PartyA, L=London, C=GB, borrower=O=PartyB, L=New York, C=US, linearId=0953f0e0-0162-43b6-8adc-dd2130b9bdd4)
<=========----> 75% EXECUTING [6m 9s]
> :java-source:runExampleClientRPCJava
- 如果希望通过ExampleClientRPC实现创建IOU的功能,可以参考com.example.api.ExamplApi.java的实现。以下是一段示例代码,可以添加在ExampleClientRPC.java中。它的主要逻辑是向另外两个对手方分别发起一笔IOU交易。
public static void main(String[] args) throws ActiveMQException, InterruptedException, ExecutionException {
... Omitted ...
final Vault.Page<IOUState> snapshot = dataFeed.getSnapshot();
final Observable<Vault.Update<IOUState>> updates = dataFeed.getUpdates();
// 添加这条代码:在监听交易之前,先创建一些交易
generateTransactions(proxy);
// Log the 'placed' IOUs and listen for new ones.
snapshot.getStates().forEach(ExampleClientRPC::logState);
updates.toBlocking().subscribe(update -> update.getProduced().forEach(ExampleClientRPC::logState));
}
// 创建IOU交易的实例代码:向Corda网络中的每一个对手方发起IOU交易
private static void generateTransactions(CordaRPCOps proxy){
CordaX500Name myLegalName = proxy.nodeInfo().getLegalIdentities().get(0).getName();
List<NodeInfo> nodeInfoSnapshot = proxy.networkMapSnapshot();
List<CordaX500Name> counterPartyNames = nodeInfoSnapshot
.stream()
.map(node -> node.getLegalIdentities().get(0).getName())
.filter(name -> !name.equals(myLegalName) && !serviceNames.contains(name.getOrganisation()))
.collect(toList());
for(CordaX500Name partyName: counterPartyNames) {
final Party otherParty = proxy.wellKnownPartyFromX500Name(partyName);
iou(proxy, otherParty, new Random().nextInt(100));
}
}
// 向一个对手方发起IOU交易
private static void iou(CordaRPCOps myProxy, Party counterParty, int iouValue){
if (counterParty == null) {
logger.info("Party is empty.\n");
return;
}
try {
final SignedTransaction signedTx = myProxy
.startTrackedFlowDynamic(ExampleFlow.Initiator.class, iouValue, counterParty)
.getReturnValue()
.get();
final String msg = String.format("Transaction to (%s) committed to ledger, txId=%s\n", counterParty.getName(), signedTx.getId());
logger.info(msg);
} catch (Throwable ex) {
final String msg = ex.getMessage();
logger.error(ex.getMessage(), ex);
}
}
3. 学习Corda
- 入门:通过学习Corda官网文档了解Corda的基本概念,按照The example CorDapp中的步骤在本地运行示例程序可以帮助加深对CorDapp的理解。
- 进阶:开发CorDapp的教程,可参考这里。Corda提供了开发CorDapp的模版代码(cordapp-template-java),可从这里下载。