今日实时汇率
持有
美元 USD 人民币 CNY 欧元 EUR 英镑 GBP 澳元 AUD 加元 CAD 日元 JPY 港币 HKD 印度卢比 INR 澳门元 MOP 韩元 KRW 墨西哥比索 MXN 阿联酋迪拉姆 AED 阿富汗尼 AFN 阿尔巴尼列克 ALL 亚美尼亚德拉姆 AMD 荷兰盾 ANG 安哥拉宽扎 AOA 阿根廷比索 ARS 阿鲁巴弗罗林 AWG 阿塞拜疆马纳特 AZN 波黑可兑换马克 BAM 巴巴多斯元 BBD 孟加拉国塔卡 BDT 保加利亚列弗 BGN 巴林第纳尔 BHD 布隆迪法郎 BIF 百慕达元 BMD 文莱元 BND 玻利维亚诺 BOB 巴西雷亚尔 BRL 巴哈马元 BSD 不丹努尔特鲁姆 BTN 博茨瓦纳普拉 BWP 白俄罗斯卢布 BYN 伯利兹元 BZD 刚果法郎 CDF 瑞士法郎 CHF 智利比索 CLP 哥伦比亚比索 COP 哥斯达黎加科朗 CRC 古巴比索 CUP 佛得角埃斯库多 CVE 捷克克朗 CZK 吉布提法郎 DJF 丹麦克朗 DKK 多米尼加比索 DOP 阿尔及利亚第纳尔 DZD 埃及镑 EGP 厄立特里亚纳克法 ERN 埃塞俄比亚比尔 ETB 斐济元 FJD 福克兰镑 FKP FOK募集币 FOK 格鲁吉亚拉里 GEL 格恩西岛磅 GGP 加纳塞地 GHS 直布罗陀镑 GIP 冈比亚达拉西 GMD 几内亚法郎 GNF 危地马拉格查尔 GTQ 圭亚那元 GYD 洪都拉斯伦皮拉 HNL 克罗地亚库纳 HRK 海地古德 HTG 匈牙利福林 HUF 印度尼西亚卢比 IDR 以色列新谢克尔 ILS 马恩磅 IMP 伊拉克第纳尔 IQD 伊朗里亚尔 IRR 冰岛克郎 ISK 新泽西岛磅 JEP 牙买加元 JMD 约旦第纳尔 JOD 肯尼亚先令 KES 吉尔吉斯斯坦索姆 KGS 柬埔寨瑞尔 KHR 基里巴斯 KID 科摩罗法郎 KMF 科威特第纳尔 KWD 开曼群岛元 KYD 哈萨克斯坦坚戈 KZT 老挝基普 LAK 黎巴嫩镑 LBP 斯里兰卡卢比 LKR 利比里亚元 LRD 莱索托洛蒂 LSL 利比亚第纳尔 LYD 摩洛哥迪拉姆 MAD 摩尔多瓦列伊 MDL 马达加斯加阿里亚里 MGA 马其顿代纳尔 MKD 缅甸元 MMK 蒙古货币 MNT 毛塔币 MRU 毛里求斯卢比 MUR 马尔代夫拉菲亚 MVR 马拉维克瓦查 MWK 林吉特 MYR 莫桑比克新梅蒂卡尔 MZN 纳米比亚元 NAD 尼日利亚奈拉 NGN 尼加拉瓜新科多巴 NIO 挪威克朗 NOK 尼泊尔卢比 NPR 新西兰元 NZD 阿曼里亚尔 OMR 巴拿马巴波亚 PAB 秘鲁新索尔 PEN 巴布亚新几内亚基那 PGK 菲律宾比索 PHP 巴基斯坦卢比 PKR 波兰兹罗提 PLN 巴拉圭瓜拉尼 PYG 卡塔尔里亚尔 QAR 罗马尼亚列伊 RON 塞尔维亚第纳尔 RSD 俄罗斯卢布 RUB 卢旺达法郎 RWF 沙特里亚尔 SAR 所罗门群岛元 SBD 塞舌尔卢比 SCR 苏丹镑 SDG 瑞典克朗 SEK 新加坡元 SGD 圣赫勒拿镑 SHP 英镑SLE SLE 塞拉利昂利昂 SLL 索马里先令 SOS 苏里南元 SRD 南苏丹币 SSP 圣多美多布拉 STN 叙利亚镑 SYP 斯威士兰里兰吉尼 SZL 泰铢 THB 塔吉克斯坦索莫尼 TJS 土库曼斯坦马纳特 TMT 突尼斯第纳尔 TND 汤加潘加 TOP 土耳其里拉 TRY 特立尼达多巴哥元 TTD 图瓦卢元 TVD 新台币 TWD 坦桑尼亚先令 TZS 乌克兰格里夫纳 UAH 乌干达先令 UGX 乌拉圭比索 UYU 乌兹别克斯坦苏姆 UZS 委内瑞拉玻利瓦尔 VES 越南盾 VND 瓦努阿图瓦图 VUV 萨摩亚塔拉 WST 中非法郎 XAF 东加勒比元 XCD 特别提款权 XDR 西非法郎 XOF 太平洋法郎 XPF 也门里亚尔 YER 南非兰特 ZAR 赞比亚克瓦查 ZMW 津巴布韦币 ZWL
交换
兑换
美元 USD 人民币 CNY 欧元 EUR 英镑 GBP 澳元 AUD 加元 CAD 日元 JPY 港币 HKD 印度卢比 INR 澳门元 MOP 韩元 KRW 墨西哥比索 MXN 阿联酋迪拉姆 AED 阿富汗尼 AFN 阿尔巴尼列克 ALL 亚美尼亚德拉姆 AMD 荷兰盾 ANG 安哥拉宽扎 AOA 阿根廷比索 ARS 阿鲁巴弗罗林 AWG 阿塞拜疆马纳特 AZN 波黑可兑换马克 BAM 巴巴多斯元 BBD 孟加拉国塔卡 BDT 保加利亚列弗 BGN 巴林第纳尔 BHD 布隆迪法郎 BIF 百慕达元 BMD 文莱元 BND 玻利维亚诺 BOB 巴西雷亚尔 BRL 巴哈马元 BSD 不丹努尔特鲁姆 BTN 博茨瓦纳普拉 BWP 白俄罗斯卢布 BYN 伯利兹元 BZD 刚果法郎 CDF 瑞士法郎 CHF 智利比索 CLP 哥伦比亚比索 COP 哥斯达黎加科朗 CRC 古巴比索 CUP 佛得角埃斯库多 CVE 捷克克朗 CZK 吉布提法郎 DJF 丹麦克朗 DKK 多米尼加比索 DOP 阿尔及利亚第纳尔 DZD 埃及镑 EGP 厄立特里亚纳克法 ERN 埃塞俄比亚比尔 ETB 斐济元 FJD 福克兰镑 FKP FOK募集币 FOK 格鲁吉亚拉里 GEL 格恩西岛磅 GGP 加纳塞地 GHS 直布罗陀镑 GIP 冈比亚达拉西 GMD 几内亚法郎 GNF 危地马拉格查尔 GTQ 圭亚那元 GYD 洪都拉斯伦皮拉 HNL 克罗地亚库纳 HRK 海地古德 HTG 匈牙利福林 HUF 印度尼西亚卢比 IDR 以色列新谢克尔 ILS 马恩磅 IMP 伊拉克第纳尔 IQD 伊朗里亚尔 IRR 冰岛克郎 ISK 新泽西岛磅 JEP 牙买加元 JMD 约旦第纳尔 JOD 肯尼亚先令 KES 吉尔吉斯斯坦索姆 KGS 柬埔寨瑞尔 KHR 基里巴斯 KID 科摩罗法郎 KMF 科威特第纳尔 KWD 开曼群岛元 KYD 哈萨克斯坦坚戈 KZT 老挝基普 LAK 黎巴嫩镑 LBP 斯里兰卡卢比 LKR 利比里亚元 LRD 莱索托洛蒂 LSL 利比亚第纳尔 LYD 摩洛哥迪拉姆 MAD 摩尔多瓦列伊 MDL 马达加斯加阿里亚里 MGA 马其顿代纳尔 MKD 缅甸元 MMK 蒙古货币 MNT 毛塔币 MRU 毛里求斯卢比 MUR 马尔代夫拉菲亚 MVR 马拉维克瓦查 MWK 林吉特 MYR 莫桑比克新梅蒂卡尔 MZN 纳米比亚元 NAD 尼日利亚奈拉 NGN 尼加拉瓜新科多巴 NIO 挪威克朗 NOK 尼泊尔卢比 NPR 新西兰元 NZD 阿曼里亚尔 OMR 巴拿马巴波亚 PAB 秘鲁新索尔 PEN 巴布亚新几内亚基那 PGK 菲律宾比索 PHP 巴基斯坦卢比 PKR 波兰兹罗提 PLN 巴拉圭瓜拉尼 PYG 卡塔尔里亚尔 QAR 罗马尼亚列伊 RON 塞尔维亚第纳尔 RSD 俄罗斯卢布 RUB 卢旺达法郎 RWF 沙特里亚尔 SAR 所罗门群岛元 SBD 塞舌尔卢比 SCR 苏丹镑 SDG 瑞典克朗 SEK 新加坡元 SGD 圣赫勒拿镑 SHP 英镑SLE SLE 塞拉利昂利昂 SLL 索马里先令 SOS 苏里南元 SRD 南苏丹币 SSP 圣多美多布拉 STN 叙利亚镑 SYP 斯威士兰里兰吉尼 SZL 泰铢 THB 塔吉克斯坦索莫尼 TJS 土库曼斯坦马纳特 TMT 突尼斯第纳尔 TND 汤加潘加 TOP 土耳其里拉 TRY 特立尼达多巴哥元 TTD 图瓦卢元 TVD 新台币 TWD 坦桑尼亚先令 TZS 乌克兰格里夫纳 UAH 乌干达先令 UGX 乌拉圭比索 UYU 乌兹别克斯坦苏姆 UZS 委内瑞拉玻利瓦尔 VES 越南盾 VND 瓦努阿图瓦图 VUV 萨摩亚塔拉 WST 中非法郎 XAF 东加勒比元 XCD 特别提款权 XDR 西非法郎 XOF 太平洋法郎 XPF 也门里亚尔 YER 南非兰特 ZAR 赞比亚克瓦查 ZMW 津巴布韦币 ZWL
1 美元(USD)=
7.2912 人民币(CNY)
反向汇率:1 CNY = 0.1372 USD
更新时间:2025-04-22 03:00:01
立即换算
欢迎您是全球710万活跃的Java开发人员之一,也可能是1200万在一生中学习过Java语言的开发人员之一。
在本文中,我将指导您使用Corda构建第一个区块 链应用 程序,Corda是一个在JVM中运行的区块链平台,仅使用Java。准备好在Java同行中脱颖而出!
你需要什么…
在本文中,我不会详细介绍区块链是什么以及人们为什么需要区块链。我将直接进入编码,并在进行过程中解释去中心化的逻辑。因此,以下是您需要遵循的内容:
1. 您可以选择IDE或代码编辑器。
2. 具有最小2GB RAM的JVM环境。(大多数台式机/笔记本电脑/虚拟机都能够运行Corda。我建议您在Pi上运行应用程序!)。
3. 最后,但并非最不重要的是,您的Java知识!
我们应该建造什么…
当然,我们将从“Hello World”应用程序开始!我们将构建一个应用程序,从区块链上的一方向另一方发送“Hello World”消息。
在Corda世界中,您编写的区块链应用程序称为CorDapp。它仅由三个部分组成:
状态:创建、更新、存储和使用的真实资产/对象。例如,一本借书、一辆标记化自行车或一个游戏板。
合同:规范/验证国家交易、更新和消费的规则。
流程:指示如何执行每个事务的指令。
不用多说,让我们开始编码吧。
步骤1:Corda 状态
在此处克隆Cordapp代码( https://github.com/corda/cordapp-template-java)。
使用您选择的代码编辑器打开它,然后导航到:
/contracts/src/main/java/com/template/states/TemplateState.java
@BelongsToContract(TemplateContract.class)publicclassTemplateStateimplementsContractState{/*ConstructorofyourCordastate*/publicTemplateState(){}/*Thismethodwillindicatewhoaretheparticipantsandrequiredsignerswhen*thisstateisusedinatransaction.*/@OverridepublicListgetParticipants(){returnArrays.asList();}}在Corda世界中,大多数数据都是在一个名为State的对象中处理的。每个状态都有一个@BelongsToContract()注释,指示将使用哪个合同文件在事务中验证此状态。State和合同是1比1挂钩的。继续我们的Hello world CorDapp,我们只需添加几行代码,使上面的TemplateState包含一条消息。我们的州将有3个属性。
字符串消息
发信人
信息接收者
@BelongsToContract(TemplateContract.class)publicclassTemplateStateimplementsContractState{//privatevariablesprivateStringmsg;privatePartysender;privatePartyreceiver;/*ConstructorofyourCordastate*/publicTemplateState(Stringmsg,Partysender,Partyreceiver){this.msg=msg;this.sender=sender;this.receiver=receiver;}//getterspublicStringgetMsg(){returnmsg;}publicPartygetSender(){returnsender;}publicPartygetReceiver(){returnreceiver;}/*Thismethodwillindicatewhoaretheparticipantsandrequiredsignerswhen*thisstateisusedinatransaction.*/@OverridepublicListgetParticipants(){returnArrays.asList(sender,receiver);}}创建三个变量,实例化变量,创建getter,填写参与者的列表,然后就是Corda状态。创建区块链应用程序的第一步已经完成。
步骤2:Corda合同
导航到 /contracts/src/main/java/com/template/contracts/TemplateContract.java
publicclassTemplateContractimplementsContract{//Thisisusedtoidentifyourcontractwhenbuildingatransaction.publicstaticfinalStringID="com.template.contracts.TemplateContract";//Atransactionisvalidiftheverify()functionofthecontractofallthetransaction'sinputandoutputstates//doesnotthrowanexception.@Overridepublicvoidverify(LedgerTransactiontx){}//Usedtoindicatethetransaction'sintent.publicinterfaceCommandsextendsCommandData{classActionimplementsCommands{}}}
在Corda世界中,涉及一个国家的每一笔交易都必须通过合同进行验证。每份合同由三个必要部分组成:
用于以后参考的合同Id
检查事务的verify()方法
一个命令界面,用于指示事务关于状态的意图。请注意,所有标准契约(不包括令牌契约,因为它们是预先编写的)都必须使用命令,为了方便起见,我们通常在接口中定义它们。
publicclassTemplateContractimplementsContract{//Thisisusedtoidentifyourcontractwhenbuildingatransaction.publicstaticfinalStringID="com.template.contracts.TemplateContract";//Atransactionisvalidiftheverify()functionofthecontractofallthetransaction'sinputandoutputstates//doesnotthrowanexception.@Overridepublicvoidverify(LedgerTransactiontx){/*WecanusetherequireSingleCommandfunctiontoextractcommanddatafromtransaction.*However,itispossibletohavemultiplecommandsinasignletransaction.*/finalCommandWithPartiescommand=requireSingleCommand(tx.getCommands(),Commands.class);finalCommandscommandData=command.getValue();if(commandData.equals(newCommands.Send())){//RetrievetheoutputstateofthetransactionTemplateStateoutput=tx.outputsOfType(TemplateState.class).get(0);//UsingCordaDSLfunctionrequireThattoreplicateconditions-checksrequireThat(require->{require.using("ThemessagemustbeHello-World",output.getMsg().equals("Hello-World"));returnnull;});}}//Usedtoindicatethetransaction'sintent.publicinterfaceCommandsextendsCommandData{//Inourhello-worldapp,Wewillonlyhaveonecommand.classSendimplementsCommands{}}}在Commands界面中,我们创建了一个名为send的命令,稍后我们将使用该命令指示事务的意图。
在verify()方法中,我们询问:
事务内部状态中携带的消息字符串必须是“Hello World”。
到这一步结束时,您将已经编写了合同。
步骤3:Corda流程
拥有可操作区块链应用程序之前的最后一步!导航到 /workflows/src/main/java/com/template/flows/Initiator.java
@InitiatingFlow@StartableByRPCpublicclassInitiatorextendsFlowLogic{privatefinalProgressTrackerprogressTracker=newProgressTracker();@OverridepublicProgressTrackergetProgressTracker(){returnprogressTracker;}@Suspendable@OverridepublicVoidcall()throwsFlowException{//Initiatorflowlogicgoeshere.returnnull;}}在Corda世界中,启动器流触发应用程序中的业务操作。无论是发送事务还是传递消息,都必须有一个启动器来发出操作信号。除了私有变量和构造函数之外,发起程序流还包括一个名为call()的签名方法。
每当调用启动器时,此方法将自动运行。这是将有效负载添加到事务、签名和签名集合的地方。现在,让我们根据Hello World的情况填写一下。
@InitiatingFlow@StartableByRPCpublicclassInitiatorextendsFlowLogic{//WewillnotusetheseProgressTrackerforthisHello-WorldsampleprivatefinalProgressTrackerprogressTracker=newProgressTracker();@OverridepublicProgressTrackergetProgressTracker(){returnprogressTracker;}//privatevariablesprivatePartysender;privatePartyreceiver;//publicconstructorpublicInitiator(PartysendTo){this.receiver=sendTo;}@Suspendable@OverridepublicSignedTransactioncall()throwsFlowException{//HelloWorldmessageStringmsg="Hello-World";this.sender=getOurIdentity();//Step1.Getareferencetothenotaryserviceonournetworkandourkeypair.//Note:ongoingworktosupportmultiplenotaryidentitiesisstillinprogress.finalPartynotary=getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);//ComposetheStatethatcarriestheHelloWorldmessagefinalTemplateStateoutput=newTemplateState(msg,sender,receiver);//Step3.CreateanewTransactionBuilderobject,andaddtheiouasanoutputstate,//aswellasacommandtothetransactionbuilder.finalTransactionBuilderbuilder=newTransactionBuilder(notary);builder.addOutputState(output);builder.addCommand(newTemplateContract.Commands.Send(),Arrays.asList(this.sender.getOwningKey(),this.receiver.getOwningKey()));//Step4.VerifyandsignitwithourKeyPair.builder.verify(getServiceHub());finalSignedTransactionptx=getServiceHub().signInitialTransaction(builder);//Step5.Collecttheotherparty'ssignatureusingtheSignTransactionFlow.ListotherParties=output.getParticipants().stream().map(el->(Party)el).collect(Collectors.toList());otherParties.remove(getOurIdentity());Listsessions=otherParties.stream().map(el->initiateFlow(el)).collect(Collectors.toList());SignedTransactionstx=subFlow(newCollectSignaturesFlow(ptx,sessions));//Step6.Assumingnoexceptions,wecannowfinalisethetransactionreturnsubFlow(newFinalityFlow(stx,sessions));}}在这个Hello World启动器流中,我们必须:
1. 获得公证处的证明。[防止双重开支]
2. 撰写包含Hello World消息的状态。[产生输出]
3. 创建一个新的TransactionBuilder对象,将带有Hello World消息的状态添加为输出状态,并将命令添加到事务生成器中。[组成交易]
4. 验证并用我们的密钥对签名。[自行核实并签字]
5. 使用SignTransactionFlow收集另一方的签名。[在交易对手之间达成共识]
6. 完成交易并向所有相关方广播。[将交易存储到分类账]
这将是向交易对手发送Hello World的发起方流程。但是,我们还没有结束。我们必须注意该启动器的响应部分。现在,导航到 /workflows/src/main/java/com/template/flows/Responder.java
@InitiatedBy(Initiator.class)publicclassResponderextendsFlowLogic{//privatevariableprivateFlowSessioncounterpartySession;//ConstructorpublicResponder(FlowSessioncounterpartySession){this.counterpartySession=counterpartySession;}@Suspendable@OverridepublicVoidcall()throwsFlowException{//Responderflowlogicgoeshere.returnnull;}}响应程序流,如其名称所示,将从对方方响应相应的发起程序流。这个annotation@InitiatedBy显示它与哪个启动器关联。
同样,响应者也有一个自动运行调用(),该方法将在本地重新检查并保存事务(在对方节点端,因为响应者是在对方端触发的)。
@InitiatedBy(Initiator.class)publicclassResponderextendsFlowLogic{//privatevariableprivateFlowSessioncounterpartySession;//ConstructorpublicResponder(FlowSessioncounterpartySession){this.counterpartySession=counterpartySession;}@Suspendable@OverridepublicVoidcall()throwsFlowException{SignedTransactionsignedTransaction=subFlow(newSignTransactionFlow(counterpartySession){@Suspendable@OverrideprotectedvoidcheckTransaction(SignedTransactionstx)throwsFlowException{/**SignTransactionFlowwillautomaticallyverifythetransactionanditssignaturesbeforesigningit.*However,justbecauseatransactioniscontractuallyvaliddoesn’tmeanwenecessarilywanttosign.*Whatifwedon’twanttodealwiththecounterpartyinquestion,orthevalueistoohigh,*orwe’renothappywiththetransaction’sstructure?checkTransaction*allowsustodefinetheseadditionalchecks.Ifanyoftheseconditionsarenotmet,*wewillnotsignthetransaction-evenifthetransactionanditssignaturesarecontractuallyvalid.*----------*Forthishello-worldcordapp,wewillnotimplementanyaditionalchecks.**/}});//Storedthetransactionintodatabase.subFlow(newReceiveFinalityFlow(counterpartySession,signedTransaction.getId()));returnnull;}}到目前为止,您已经完成了第一个区块链应用程序的编写。我们要试着运行它们吗?
正在运行Hello World区块链应用程序…
转到终端,导航到项目文件夹/cordapp template java/并运行以下代码来部署应用程序。
./gradlew clean deployNodes(适用于Unix)和gradlew.bat clean deployNodes(适用于Windows)
成功引导将产生以下信息:
现在,运行以下代码以运行引导环境:
/build/nodes/runnodes(适用于Unix)和.buildnodesrunnodes.bat(适用于Windows)。
我们应该期待三个节点在不同的选项卡中启动并启动它们的shell。
现在让我们从PartyA向PartyB发送“Hello world”。
转到PartyA的shell并运行:
流启动启动器发送到:PartyB
我们应该期待以下信息:
到目前为止,我们已经通过分布式系统从一方向另一方发送了“Hello World”消息!但是是吗?让我们检查一下!
导航到PartyB的节点外壳并运行:
运行Vault Query contractStateType:com.template.states.TemplateState
就在那里!携带“Hello World”并从PartyA发送到PartyB的模板状态。
这个应用程序的“区块链”是什么?
你可能会想,等一下,我只看到一个在各方之间发送消息的应用程序,块在哪里?链条在哪里?通过部署和运行该应用程序,您已经成功启动了一个通常称为“区块链”的本地分布式账本系统。
携带消息字符串的状态是块。您将通过事务连接与先前生成的状态相关的后续状态,我们可以将其视为“链”。
这种状态交易链仅在参与方之间需要了解的基础上共享。(回忆步骤1中的参与者列表)。因此,在Corda世界中,数据是分布式共享的。不会有一个记录各方交易的集中数据库。
回到Hello World示例,事务( txHash:736AA884909645171B56AD965D3B…94E4F457C)带有genesis块(状态),可以用作另一个事务的输入,该链将继续运行。与区块链的概念类似:Corda状态(块)由Corda事务(链)链接