NeoGo adds remote notification subsystem
Neo is widely known for its VM supporting a variety of languages for smart contract development. But a complete distributed application usually includes not only a smart contract but also a backend subsystem that monitors on-chain smart contract executions and does some associated actions.
So what options are available for backend development? Up until very recently, it was just writing plugins for the C# node. Nowadays there also is a public WebSocket service available and a different WebSocket option presented with NeoGo 0.75.0 release.
Websockets for RPC and things
First of all, we’ve never considered the plugin route for NeoGo, partly because Go itself is not very much friendly to plugins, but mostly because that would limit the developer the same way he’s limited by the requirement to produce some dotnet-compatible code to work with the original node. We wanted to enable easy use of this subsystem from different languages, you can write your smart contract in Go, Python, TypeScript — you should also be able to use these languages for backend development.
So some networked option was needed and we looked at what we’ve got on that side. We already had the JSON-RPC server in our node and were expecting most of the real backends to be using that for their purposes. At the same time, we needed to push event notifications to the client, and using HTTP doesn’t work well for that (and don’t suggest long polling, please!). Which turned our eyes to a generic messaging subsystem that an HTTP connection could be upgraded to, WebSockets.
First, we’ve extended our JSON-RPC server to also accept WebSocket connections at
ws://$SERVER/ws address, so if your node is available for RPC connections at
http://192.168.42.42:10332 the WebSocket URL for that would be
ws://192.168.42.42:10332/ws. Using this interface is actually beneficial for regular JSON-RPC communication too (because it doesn’t need re-establishing a connection), you can use it normally with any WebSocket client and of course, we’ve created a Go client with Neo RPC functions for you too. But that, of course, wasn’t the main goal and we started adding WebSocket-specific functionality.
As we needed full compatibility with standard JSON-RPC calls we couldn’t just push events to the client, one needs to subscribe first using regular JSON-RPC call. That call accepts notification feed type and filters in its parameters and returns a subscription ID that can later be used for unsubscribing. Once subscribed, you’ll start receiving events.
Multiple subscriptions with different types/filters are perfectly supported, but an event is only sent once to the client even if it matches several subscriptions.
Events and filters
As of 0.75.0 release NeoGo allows subscription to four types of events: blocks, transactions (and that means transactions in the block as separate events, not mempool activity), application execution results (for invocation transactions) and those notifications from smart contracts that started all of this.
But the most interesting thing is that you can filter all of these events. Being a dApp developer you’re probably concerned with notifications generated by your smart contract and the filtering mechanism we have allows you to specify the script hash of your contract to only receive events generated by it. You can also choose between successful and unsuccessful transaction executions for application execution results and select a type of transaction for transaction events.
All events generated are delivered as JSON-RPC notifications (as that’s the base communication protocol we have here) via parameters. In general, they follow the format you would expect based on experience with JSON-RPC server: verbose representations for blocks and transactions,
getapplicationlog result for transaction executions, and a part of that for contract’s notifications. That follows our approach to making this interface as easy to use as possible in any environment if you have anything working with JSON-RPC server adjusting that to catch these events would be easy.
There also is one very special event type:
event_missed. We want dApp backends to be reliable and we don’t want them to lose any events, but obviously, if the client wouldn’t be able to receive events in time server queues might get overflown and that’s exactly when this event is being generated. You shouldn’t ever receive it, but if we wouldn’t be able to deliver your event at least you would know that.
Releasing that functionality is not just about code, we also have an open
specification for this protocol so that you could quickly implement a client in whatever language of your choice if that choice is not Go.
Relation to neo-PubSub work
As a disclaimer, we should note that we only found neo-PubSub just recently and wasn’t aware of its existence when our solution was designed and built. If we were aware of that we would probably make some minor adjustments to our solution, but implement it anyway as there are obvious differences in provided functionality following from the fact that our solution is tied to a full node while neo-PubSub is intended to provide a public service. We also think that having more options is beneficial to the community as it allows to cover more different use cases and usage scenarios.
If you’re considering a node for your dApp, the notification subsystem presented here might be one of the reasons to choose NeoGo as it allows you to get everything you need without writing additional node plugins or relying on third-party services. And we will extend this subsystem with even more functionality in future releases of NeoGo (of course this subsystem is also present in our currently developed Neo 3 node, see specification for Neo 3 version).