java区块链web应用(一天入门java区块链-jdchain)

  java区块链web应用(一天入门java区块链-jdchain)


  

jdchain是京东数科开源的区块链平台,目标是实现一个面向企业应用场景的通用区块链框架系统,能够作为企业级基础设施,为业务创新提供高效、灵活和安全的解决方案。之所以选择jdchain研究是因为jdchain是为数不多的底层也是采用java实现的一个区块链平台
项目地址:https!//github。com/blockchain。。。
文档地址:http!//ledger。jd。com/setup。html

  

部署组件

  • peer:区块链主节点,参与共识、账本操作等
  • gateway:与Peer节点通信,负责区块链浏览器及消息传递
  • 客户端:采用SDK和网关链接,比特币交易通过网关发起交易

获取部署包

有两种途径可以拿到部署包,一、直接从官网下载。二、从github上拉源码,然后自己构建,在deployment目录下会生成部署包,自己构建的需要注意,如果是在Windows系统上构建的包,包里的启动脚本在linux系统下运行会有转义字符的问题,需要在assembly。xml里设置lineEnding为unix,具体设置点我查看

  

解压部署

部署参考文档:《从零开始部署JDChain》

  

效果预览

区块链部署工具

  


区块链浏览器

  

部署遇到的问题:

官方文档算比较详细,但是很多细节没有写明,一般体验和开发时部署的环境比较简单,可能在一个主机上部署4个节点的peer。这个时候端口的编排要非常注意,因为jdchain目前的共识算法采用的开源的bftsmart实现,共识端口在同一台主机上不能连续,不然就会端口冲突。博主就遇到了这个问题,下面是详细排错过程:采用SDK创建用户时抛如下异常,网关可以正常连接,秘钥认证没有问题:

  

Caused by! java。lang。IndexOutOfBoundsException! The accessing index is out of BytesSlice';s bounds! at com。jd。blockchain。utils。io。BytesSlice。checkBoundary(BytesSlice。java!174) at com。jd。blockchain。utils。io。BytesSlice。getInt(BytesSlice。java!97) at com。jd。blockchain。utils。io。BytesSlice。getInt(BytesSlice。java!86) at com。jd。blockchain。binaryproto。impl。HeaderEncoder。resolveCode(HeaderEncoder。java!71) at com。jd。blockchain。binaryproto。BinaryProtocol。decode(BinaryProtocol。java!41) at com。jd。blockchain。sdk。converters。BinarySerializeResponseConverter。getResponse(BinarySerializeResponseConverter。java!33) at com。jd。blockchain。utils。http。agent。HttpServiceAgent。invoke(HttpServiceAgent。java!587) 。。。 7 more

网关里的异常

  

11!57!05。537 ERROR com。jd。blockchain。gateway。web。GatewayGlobalExceptionHandler 34 json - Unexpected exception occurred! --[RequestURL=[POST] http!//192。168。1。190!8081/rpc/tx][class java。lang。IllegalStateException]Returned object not currently part of this pool java。lang。IllegalStateException! Returned object not currently part of this pool at org。apache。commons。pool2。impl。GenericObjectPool。returnObject(GenericObjectPool。java!530) ~[commons-pool2-2。5。0。jar!/!2。5。0] at com。jd。blockchain。consensus。bftsmart。client。BftsmartMessageService。sendOrderedMessage(BftsmartMessageService。java!46) ~[consensus-bftsmart-1。1。1。RELEASE。jar!/!1。1。1。RELEASE] at com。jd。blockchain。consensus。bftsmart。client。BftsmartMessageService。sendOrdered(BftsmartMessageService。java!22) ~[consensus-bftsmart-1。1。1。RELEASE。jar!/!1。1。1。RELEASE] at com。jd。blockchain。sdk。service。NodeSigningAppender。process(NodeSigningAppender。java!84) ~[sdk-base-1。1。1。RELEASE。jar!/!1。1。1。RELEASE] at com。jd。blockchain。sdk。service。PeerServiceProxy。process(PeerServiceProxy。java!89) ~[sdk-base-1。1。1。RELEASE。jar!/!1。1。1。RELEASE] at com。jd。blockchain。gateway。web。TxProcessingController。process(TxProcessingController。java!70) ~[gateway-1。1。1。RELEASE。jar!/!1。1。1。RELEASE] at sun。reflect。NativeMethodAccessorImpl。invoke0(Native Method) ~[?!1。8。0_231] at sun。reflect。NativeMethodAccessorImpl。invoke(NativeMethodAccessorImpl。java!62) ~[?!1。8。0_231] at sun。reflect。DelegatingMethodAccessorImpl。invoke(DelegatingMethodAccessorImpl。java!43) ~[?!1。8。0_231] at java。lang。reflect。Method。invoke(Method。java!498) ~[?!1。8。0_231]

最终查明异常是由于网关里创建AsynchServiceProxy失败导致的,这部分实现采用了Apache-commons-pool2。实现如下:

  

public class BftsmartPeerProxyFactory extends BasePooledObjectFactory<;AsynchServiceProxy>; { private BftsmartClientSettings bftsmartClientSettings; private int gatewayId; private AtomicInteger index = new AtomicInteger(1); public BftsmartPeerProxyFactory(BftsmartClientSettings bftsmartClientSettings, int gatewayId) { this。bftsmartClientSettings = bftsmartClientSettings; this。gatewayId = gatewayId; } @Override public AsynchServiceProxy create() throws Exception { BftsmartTopology topology = BinarySerializeUtils。deserialize(bftsmartClientSettings。getTopology()); MemoryBasedViewStorage viewStorage = new MemoryBasedViewStorage(topology。getView()); TOMConfiguration tomConfiguration = BinarySerializeUtils。deserialize(bftsmartClientSettings。getTomConfig()); //every proxy client has unique id; tomConfiguration。setProcessId(gatewayId + index。getAndIncrement()); AsynchServiceProxy peerProxy = new AsynchServiceProxy(tomConfiguration, viewStorage); return peerProxy; } @Override public PooledObject<;AsynchServiceProxy>; wrap(AsynchServiceProxy asynchServiceProxy) { return new DefaultPooledObject<;>;(asynchServiceProxy); }}

这个代码BinarySerializeUtils。deserialize(bftsmartClientSettings。getTopology())返回的是null,没有正确拿到Bftsmart的网络拓扑。进而查看peer节点,发现只有节点0成功了,其他都抛如下异常,初步判断bftsmart的副本服务因为端口占用启动失败了:

  

11!36!48。479 ERROR bftsmart。tom。ServiceReplica 247 init - null java。net。bindException! 地址已在使用 at sun。nio。ch。Net。bind0(Native Method) ~[?!1。8。0_231] at sun。nio。ch。Net。bind(Net。java!433) ~[?!1。8。0_231] at sun。nio。ch。Net。bind(Net。java!425) ~[?!1。8。0_231] at sun。nio。ch。ServerSocketChannelImpl。bind(ServerSocketChannelImpl。java!223) ~[?!1。8。0_231] at io。netty。channel。socket。nio。NioServerSocketChannel。doBind(NioServerSocketChannel。java!130) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。AbstractChannel$AbstractUnsafe。bind(AbstractChannel。java!558) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。DefaultChannelPipeline$HeadContext。bind(DefaultChannelPipeline。java!1358) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。AbstractChannelHandlerContext。invokeBind(AbstractChannelHandlerContext。java!501) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。AbstractChannelHandlerContext。bind(AbstractChannelHandlerContext。java!486) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。DefaultChannelPipeline。bind(DefaultChannelPipeline。java!1019) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。AbstractChannel。bind(AbstractChannel。java!254) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。bootstrap。AbstractBootstrap$2。run(AbstractBootstrap。java!366) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。util。concurrent。AbstractEventExecutor。safeExecute(AbstractEventExecutor。java!163) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。util。concurrent。SingleThreadEventExecutor。runAllTasks(SingleThreadEventExecutor。java!404) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。channel。nio。NioEventLoop。run(NioEventLoop。java!446) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。util。concurrent。SingleThreadEventExecutor$5。run(SingleThreadEventExecutor。java!884) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at io。netty。util。concurrent。FastThreadLocalRunnable。run(FastThreadLocalRunnable。java!30) ~[netty-all-4。1。29。Final。jar!4。1。29。Final] at java。lang。Thread。run(Thread。java!748) ~[?!1。8。0_231]

从bftsmart官方文档得知,如果在同一个主机运行,不能使用顺序的端口号,即一开始编排的peer的共识端口,6000、6001、6002、6003是不行的,原因如下:如果在同一台计算机(127。0。0。1)中部署/执行了某些(或全部)副本,config/hosts。config则不能具有顺序的端口号(例如10000、10001、10002、10003)。这是因为每个副本都绑定了两个端口:一个用于接收来自客户端的消息,另一个用于接收来自其他副本的消息(通过获取下一个端口号选择) 。更一般而言,如果为副本R分配了端口号P,它将尝试将端口P(绑定到接收到的客户端请求)和端口P + 1(绑定到其他副本)进行绑定。如果不执行此准则,则副本可能无法绑定所有需要的端口。

  

  • 文档地址:https!//github。com/bft-smart/。。。

结语

jdchain是完整采用java实现的区块链项目,是java开发者研究区块链的一大福音,而且项目开源后一直在迭代,文档和社区支持方面都比较友好。入门虽然很简单,但是要深入到这个项目后面还有很多的东西要研究。楼主计划,后面先把SDK和网关的交互搞清楚,然后在研究下最新的共识实现(基于RabbitMQ),然后在研究下智能合约的应用,最后深入代码实现,可能后面还会有其他的关于jdchain的内容输出。最后希望全部掌握后能给社区贡献点代码、提供点案例、解答点问题。为开源尽自己的绵薄之力

  

  
","content_hash"!"fb3ebbe5

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

评论