📜 ⬆️ ⬇️

Vibrant.kt - rapid prototyping and development of distributed applications (DApps) on JVM

Nihao!


Introduction


I haven’t written anything for a long time, because the Unified State Examination will not surrender itself, but I could not write something cool for the Baltic competition . I couldn’t squeeze out good ideas from nowhere, so I decided to plunge into a completely unfamiliar topic at that time (half a month ago), the world of the blockchain, cryptocurrency, smart contracts and other clever English words. At lessons I stuck to the phone, reading a lot of texts about the blockchain, peer2peer networks and all that, gradually sorting out. Everything went easier when I started writing simple prototypes in Javascript: once again I am convinced that everything is clearer in the code than in the text. As a result, when I sort of figured out, I decided on the topic of work, which can be seen in the title of the article.


What it is and why it is


Vibrant is a library written in Kotlin for rapid prototyping of distributed applications. The idea is that you can focus on certain aspects of the future system, replacing unrealized code with ready-made solutions. For example, you have conceived to write a distributed chat.


Immediately there are several points that require implementation: how to provide a connection between peers, what communication protocol to use, and do I need UDP in LAN, if I just try to make a chat, or can do it over TCP, or maybe just HTTP ... In general, there are many primary tasks, without which nothing will work. And to write a simple chat on a distributed platform, you have to implement a certain amount of functionality. This problem is solved by Vibrant, consisting of 2 packages, org.vibrant.core - architecture abstraction and org.vibrant.base - various implementations of abstractions from the core package, for example, HTTPPeer , HTTPJsonRPCPeer - classes of peers communicating via http, the first is more abstract, the second uses the JSON RPC 2.0 protocol for communication between nodes.
In general, instead of writing a feast from scratch, take a ready-made JSON RPC feast and use it. If there is a need to change the protocol or a keen desire to write something of your own - abstraction allows, flag in hand.


And how to use it?


 class Peer(port: Int, rpc: BaseJSONRPCProtocol): HTTPJsonRPCPeer(port, rpc){ val miners = arrayListOf<RemoteNode>() fun broadcastMiners(jsonrpcRequest: JSONRPCRequest): List<JSONRPCResponse<*>> { return this.broadcast(jsonrpcRequest, this.miners) } fun addUniqueRemoteNode(remoteNode: RemoteNode, isMiner: Boolean = false) { super.addUniqueRemoteNode(remoteNode) if (isMiner && this.miners.find { it.address == remoteNode.address && it.port == remoteNode.port } == null) { this.miners.add(remoteNode) } } } 

Here is a simple implementation of HTTPJsonPeer . According to it, it is impossible to say that it can only if it does not notice the argument of the constructor rpc: BaseJSONRPCProtocol . If you initialize this class and run, the HTTP server will be launched on the selected port, which accepts POST JSON RPC requests for the /rpc endpoint, transforms them into Kotlin objects and calls the appropriate method in the passed BaseJSONRPCProtocol . So to speak, plug and play.
Here is an example of methods that can be run via a JSON RPC request:


 @JSONRPCMethod fun getLastBlock(request: JSONRPCRequest, remoteNode: RemoteNode): JSONRPCResponse<*>{ return JSONRPCResponse( result = node.chain.latestBlock().serialize(), error = null, id = request.id ) } @JSONRPCMethod fun newBlock(request: JSONRPCRequest, remoteNode: RemoteNode): JSONRPCResponse<*>{ val blockModel = BaseJSONSerializer.deserialize(request.params[0].toString().toByteArray()) as BaseBlockModel node.handleLastBlock(blockModel, remoteNode) return JSONRPCResponse( result = node.chain.latestBlock().serialize(), error = null, id = request.id ) } 

This is how you can quickly make a feast.
But where is the blockchain ?! Here he is.


 abstract class InMemoryBlockChain<B: BlockModel, out T: BlockChainModel>: BlockChain<B, T>() { protected val blocks = arrayListOf(this.createGenesisBlock()) override fun latestBlock(): B = this.blocks.last() override fun addBlock(block: B): B { synchronized(this.blocks, { this.blocks.add(block) this.notifyNewBlock() return this.latestBlock() }) } } 

This is a class from the org.vibrant.base package, by inheriting it you can safely use the blockchain, which exists only in memory. Such a blockchain is well suited, for example, to test an application.


It is worth noting that the presence of InMemoryBlockChain does not limit the developer: you can write your InMemoryBlockChain , where h2 database is used instead of arraylist, but this already refers to the item “I don’t want to steam over the boilerplate, give me a ready boilerplate and the ability to write my code”.


Preliminary conclusion


I am actively puffing on this project, there are a lot of things that I would like to add, for example, implement Tangle in the image of Iota , write a quality UDPPeer, using, for example, Netty channels. Oh yeah, now I'm working on smart contracts, which can also be plug and play . I think it will be fun.


Conclusion


I would be very pleased with the enthusiasm of readers in the form of pull requests.
Links to github:
Core abstraction package
Base package with implementations
Work Chat Application


')

Source: https://habr.com/ru/post/347080/


All Articles