From ddbc9057c8be2dfb359d2f8c7635652c1e74df03 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 19 May 2020 01:01:35 +0300 Subject: [PATCH] docs: update RPC document, add notifications spec --- docs/notifications.md | 339 ++++++++++++++++++++++++++++++++++++++++++ docs/rpc.md | 35 ++++- 2 files changed, 366 insertions(+), 8 deletions(-) create mode 100644 docs/notifications.md diff --git a/docs/notifications.md b/docs/notifications.md new file mode 100644 index 000000000..0561a3282 --- /dev/null +++ b/docs/notifications.md @@ -0,0 +1,339 @@ +# Notification subsystem + +Original motivation, requirements and general solution strategy are described +in the issue #895. + +This extension allows a websocket client to subscribe to various events and +receive them as JSON-RPC notifications from the server. + +## Events +Currently supported events: + * new block added + Contents: block. + Filters: none. + * new transaction in the block + Contents: transaction. + Filters: type. + * notification generated during execution + Contents: container hash, contract script hash, stack item. + Filters: contract script hash. + * transaction executed + Contents: application execution result. + Filters: VM state. + +## Ordering and persistence guarantees + * new block is only announced after its processing is complete and the chain + is updated to the new height + * no disk-level persistence guarantees are given + * new in-block transaction is announced after block processing, but before + announcing the block itself + * transaction notifications are only announced for successful transactions + * all announcements are being done in the same order they happen on the chain + At first transaction execution is announced, then followed by notifications + generated during this execution, then followed by transaction announcement. + Transaction announcements are ordered the same way they're in the block. + * unsubscription may not cancel pending, but not yet sent events + +## Subscription management + +Errors are not described down below, but they can be returned as standard +JSON-RPC errors (most often caused by invalid parameters). + +### `subscribe` method + +Parameters: event stream name, stream-specific filter rules hash (can be +omitted if empty). + +Recognized stream names: + * `block_added` + No filter parameters defined. + * `transaction_added` + Filter: `type` as a string containing standard transaction types + (MinerTransaction, InvocationTransaction, etc) + * `notification_from_execution` + Filter: `contract` field containing string with hex-encoded Uint160 (LE + representation). + * `transaction_executed` + Filter: `state` field containing `HALT` or `FAULT` string for successful + and failed executions respectively. + +Response: returns subscription ID (string) as a result. This ID can be used to +cancel this subscription and has no meaning other than that. + +Example request (subscribe to notifications from contract +0x6293a440ed80a427038e175a507d3def1e04fb67 generated when executing +transactions): + +``` +{ + "jsonrpc": "2.0", + "method": "subscribe", + "params": ["notification_from_execution", {"contract": "6293a440ed80a427038e175a507d3def1e04fb67"}], + "id": 1 +} + +``` + +Example response: + +``` +{ + "jsonrpc": "2.0", + "id": 1, + "result": "55aaff00" +} +``` + +### `unsubscribe` method + +Parameters: subscription ID as a string. + +Response: boolean true. + +Example request (unsubscribe from "55aaff00"): + +``` +{ + "jsonrpc": "2.0", + "method": "unsubscribe", + "params": ["55aaff00"], + "id": 1 +} +``` + +Example response: + +``` +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +``` + +## Events + +Events are sent as JSON-RPC notifications from the server with `method` field +being used for notification names. Notification names are identical to stream +names described for `subscribe` method with one important addition for +`event_missed` which can be sent for any subscription to signify that some +events were not delivered (usually when client isn't able to keep up with +event flow). + +Verbose responses for various structures like blocks and transactions are used +to simplify working with notifications on client side. Returned structures +mostly follow the one used by standard Neo RPC calls, but may have some minor +differences. + +### `block_added` notification +As a first parameter (`params` section) contains block converted to JSON +structure which is similar to verbose `getblock` response but with the +following differences: + * it doesn't have `size` field (you can calculate it client-side) + * it doesn't have `nextblockhash` field (it's supposed to be the latest one + anyway) + * it doesn't have `confirmations` field (see previous) + * transactions contained don't have `net_fee` and `sys_fee` fields + +No other parameters are sent. + +Example: +``` +{ + "jsonrpc" : "2.0", + "method" : "block_added", + "params" : [ + { + "previousblockhash" : "0x33f3e0e24542b2ec3b6420e6881c31f6460a39a4e733d88f7557cbcc3b5ed560", + "nextconsensus" : "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", + "index" : 205, + "nonce" : "0000000000000457", + "version" : 0, + "tx" : [ + { + "version" : 0, + "attributes" : [], + "txid" : "0xf9adfde059810f37b3d0686d67f6b29034e0c669537df7e59b40c14a0508b9ed", + "size" : 10, + "vin" : [], + "type" : "MinerTransaction", + "scripts" : [], + "vout" : [] + }, + { + "version" : 1, + "txid" : "0x93670859cc8a42f6ea994869c944879678d33d7501d388f5a446a8c7de147df7", + "attributes" : [], + "size" : 60, + "script" : "097465737476616c756507746573746b657952c103507574676f20ccfbd5f01d5b9633387428b8bab95a9e78c2", + "vin" : [], + "scripts" : [], + "type" : "InvocationTransaction", + "vout" : [] + } + ], + "time" : 1586154525, + "hash" : "0x48fba8aebf88278818a3dc0caecb230873d1d4ce1ea8bf473634317f94a609e5", + "script" : { + "invocation" : "4047a444a51218ac856f1cbc629f251c7c88187910534d6ba87847c86a9a73ed4951d203fd0a87f3e65657a7259269473896841f65c0a0c8efc79d270d917f4ff640435ee2f073c94a02f0276dfe4465037475e44e1c34c0decb87ec9c2f43edf688059fc4366a41c673d72ba772b4782c39e79f01cb981247353216d52d2df1651140527eb0dfd80a800fdd7ac8fbe68fc9366db2d71655d8ba235525a97a69a7181b1e069b82091be711c25e504a17c3c55eee6e76e6af13cb488fbe35d5c5d025c34041f39a02ebe9bb08be0e4aaa890f447dc9453209bbfb4705d8f2d869c2b55ee2d41dbec2ee476a059d77fb7c26400284328d05aece5f3168b48f1db1c6f7be0b", + "verification" : "532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae" + }, + "merkleroot" : "0x9d922c5cfd4c8cd1da7a6b2265061998dc438bd0dea7145192e2858155e6c57a" + } + ] +} +``` + +### `transaction_added` notification + +In the first parameter (`params` section) contains transaction converted to +JSON which is similar to verbose `getrawtransaction` response, but with the +following differences: + * `net_fee` and `sys_fee` fields are always missing + * block's metadata is missing (`blockhash`, `confirmations`, `blocktime`) + +No other parameters are sent. + +Example: +``` +{ + "params" : [ + { + "vin" : [], + "scripts" : [], + "attributes" : [], + "txid" : "0x93670859cc8a42f6ea994869c944879678d33d7501d388f5a446a8c7de147df7", + "size" : 60, + "vout" : [], + "type" : "InvocationTransaction", + "version" : 1, + "script" : "097465737476616c756507746573746b657952c103507574676f20ccfbd5f01d5b9633387428b8bab95a9e78c2" + } + ], + "method" : "transaction_added", + "jsonrpc" : "2.0" +} +``` + +### `notification_from_execution` notification + +Contains three parameters: container hash (hex-encoded LE Uint256 in a +string), contract script hash (hex-encoded LE Uint160 in a string) and stack +item (encoded the same way as `state` field contents for notifications from +`getapplicationlog` response). + +Example: + +``` +{ + "method" : "notification_from_execution", + "jsonrpc" : "2.0", + "params" : [ + { + "state" : { + "value" : [ + { + "value" : "636f6e74726163742063616c6c", + "type" : "ByteArray" + }, + { + "value" : "507574", + "type" : "ByteArray" + }, + { + "value" : [ + { + "type" : "ByteArray", + "value" : "746573746b6579" + }, + { + "value" : "7465737476616c7565", + "type" : "ByteArray" + } + ], + "type" : "Array" + } + ], + "type" : "Array" + }, + "contract" : "0xc2789e5ab9bab828743833965b1df0d5fbcc206f" + } + ] +} +``` + +### `transaction_executed` notification + +Contains the same result as from `getapplicationlog` method in the first +parameter and no other parameters. One difference from `getapplicationlog` is +that it always contains zero in the `contract` field. + +Example: +``` +{ + "method" : "transaction_executed", + "params" : [ + { + "executions" : [ + { + "vmstate" : "HALT", + "contract" : "0x0000000000000000000000000000000000000000", + "notifications" : [ + { + "state" : { + "type" : "Array", + "value" : [ + { + "type" : "ByteArray", + "value" : "636f6e74726163742063616c6c" + }, + { + "type" : "ByteArray", + "value" : "507574" + }, + { + "value" : [ + { + "value" : "746573746b6579", + "type" : "ByteArray" + }, + { + "type" : "ByteArray", + "value" : "7465737476616c7565" + } + ], + "type" : "Array" + } + ] + }, + "contract" : "0xc2789e5ab9bab828743833965b1df0d5fbcc206f" + } + ], + "gas_consumed" : "1.048", + "stack" : [ + { + "type" : "Integer", + "value" : "1" + } + ], + "trigger" : "Application" + } + ], + "txid" : "0x93670859cc8a42f6ea994869c944879678d33d7501d388f5a446a8c7de147df7" + } + ], + "jsonrpc" : "2.0" +} +``` + +### `event_missed` notification + +Never has any parameters. Example: + +``` +{ + "jsonrpc": "2.0", + "method": "event_missed", + "params": [] +} +``` diff --git a/docs/rpc.md b/docs/rpc.md index 9cae46a16..ba025c07d 100644 --- a/docs/rpc.md +++ b/docs/rpc.md @@ -65,6 +65,18 @@ which would yield the response: | `submitblock` | | `validateaddress` | +#### Implementation notices + +##### `invokefunction` and `invoke` + +neo-go's implementation of `invokefunction` and `invoke` does not return `tx` +field in the answer because that requires signing the transaction with some +key in the server which doesn't fit the model of our node-client interactions. +Lacking this signature the transaction is almost useless, so there is no point +in returning it. + +Both methods also don't currently support arrays in function parameters. + ### Unsupported methods Methods listed down below are not going to be supported for various reasons @@ -86,17 +98,24 @@ and we're not accepting issues related to them. | `sendmany` | Not applicable to neo-go, see `claimgas` comment | | `sendtoaddress` | Not applicable to neo-go, see `claimgas` comment | -#### Implementation notices +### Extensions -##### `invokefunction` and `invoke` +Some additional extensions are implemented as a part of this RPC server. -neo-go's implementation of `invokefunction` and `invoke` does not return `tx` -field in the answer because that requires signing the transaction with some -key in the server which doesn't fit the model of our node-client interactions. -Lacking this signature the transaction is almost useless, so there is no point -in returning it. +#### Websocket server -Both methods also don't currently support arrays in function parameters. +This server accepts websocket connections on `ws://$BASE_URL/ws` address. You +can use it to perform regular RPC calls over websockets (it's supposed to be a +little faster than going regular HTTP route) and you can also use it for +additional functionality provided only via websockets (like notifications). + +#### Notification subsystem + +Notification subsystem consists of two additional RPC methods (`subscribe` and +`unsubscribe` working only over websocket connection) that allow to subscribe +to various blockchain events (with simple event filtering) and receive them on +the client as JSON-RPC notifications. More details on that are written in the +[notifications specification](notifications.md). ## Reference