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.
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.
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”.
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.
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