Small RPC improvements (#57)

* Few tweaks to improve output of `getblock`

* Adds few more fields and corrects witness

* Bumps version

* Only reverse when marshalling for moment

* Adds README for rpc package

* Few updates

* Typo

* Adds link in main readme

* Fix readme link
This commit is contained in:
Steven Jack 2018-03-30 07:15:03 +01:00 committed by Anthony De Meulemeester
parent c51a6d3e57
commit 0b023c5c5c
11 changed files with 179 additions and 20 deletions

View file

@ -4,7 +4,7 @@ VERSION = $(shell cat ./VERSION)
NETMODE ?= "privnet"
build:
@go build -ldflags "-X github.com/CityOfZion/neo-go/pkg/network.Version=${VERSION}-dev -X github.com/CityOfZion/neo-go/pkg/network.BuildTime=${BUILD_TIME}" -o ./bin/neo-go ./cli/main.go
@go build -ldflags "-X github.com/CityOfZion/neo-go/config.Version=${VERSION}-dev -X github.com/CityOfZion/neo-go/config.BuildTime=${BUILD_TIME}" -o ./bin/neo-go ./cli/main.go
check-version:
git fetch && (! git rev-list ${VERSION})

View file

@ -29,7 +29,7 @@ This project aims to be a full port of the original C# [NEO project](https://git
A complete toolkit for the NEO blockchain, including:
- consensus node
- RPC node
- [RPC node & client](https://github.com/CityOfZion/neo-go/tree/master/pkg/rpc/README.md)
- RPC client
- CLI tool
- Smart contract compiler

View file

@ -1 +1 @@
0.35.1
0.36.0

View file

@ -34,7 +34,7 @@ type BlockBase struct {
ConsensusData uint64 `json:"nonce"`
// Contract addresss of the next miner
NextConsensus util.Uint160 `json:"nextminer"`
NextConsensus util.Uint160 `json:"next_consensus"`
// Padding that is fixed to 1
_ uint8

View file

@ -16,7 +16,7 @@ type Transaction struct {
Type TXType `json:"type"`
// The trading version which is currently 0.
Version uint8 `json:"-"`
Version uint8 `json:"version"`
// Data specific to the type of the transaction.
// This is always a pointer to a <Type>Transaction.

View file

@ -2,6 +2,8 @@ package transaction
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"io"
"github.com/CityOfZion/neo-go/pkg/util"
@ -9,32 +11,42 @@ import (
// Witness contains 2 scripts.
type Witness struct {
InvocationScript []byte `json:"stack"`
VerificationScript []byte `json:"redeem"`
InvocationScript []byte
VerificationScript []byte
}
// DecodeBinary implements the payload interface.
func (wit *Witness) DecodeBinary(r io.Reader) error {
func (w *Witness) DecodeBinary(r io.Reader) error {
lenb := util.ReadVarUint(r)
wit.InvocationScript = make([]byte, lenb)
if err := binary.Read(r, binary.LittleEndian, wit.InvocationScript); err != nil {
w.InvocationScript = make([]byte, lenb)
if err := binary.Read(r, binary.LittleEndian, w.InvocationScript); err != nil {
return err
}
lenb = util.ReadVarUint(r)
wit.VerificationScript = make([]byte, lenb)
return binary.Read(r, binary.LittleEndian, wit.VerificationScript)
w.VerificationScript = make([]byte, lenb)
return binary.Read(r, binary.LittleEndian, w.VerificationScript)
}
// EncodeBinary implements the payload interface.
func (wit *Witness) EncodeBinary(w io.Writer) error {
if err := util.WriteVarUint(w, uint64(len(wit.InvocationScript))); err != nil {
func (w *Witness) EncodeBinary(writer io.Writer) error {
if err := util.WriteVarUint(writer, uint64(len(w.InvocationScript))); err != nil {
return err
}
if err := binary.Write(w, binary.LittleEndian, wit.InvocationScript); err != nil {
if err := binary.Write(writer, binary.LittleEndian, w.InvocationScript); err != nil {
return err
}
if err := util.WriteVarUint(w, uint64(len(wit.VerificationScript))); err != nil {
if err := util.WriteVarUint(writer, uint64(len(w.VerificationScript))); err != nil {
return err
}
return binary.Write(w, binary.LittleEndian, wit.VerificationScript)
return binary.Write(writer, binary.LittleEndian, w.VerificationScript)
}
// MarshalJSON implements the json marshaller interface.
func (w *Witness) MarshalJSON() ([]byte, error) {
data := map[string]interface{}{
"invocation": hex.EncodeToString(w.InvocationScript),
"verification": hex.EncodeToString(w.VerificationScript),
}
return json.Marshal(data)
}

110
pkg/rpc/README.md Normal file
View file

@ -0,0 +1,110 @@
# RPC
## What
* Structs used by `JSON-RPC` server and for interacting with a `JSON-RPC` endpoint.
* Server for running the `JSON-RPC` protocol based on port in configuration.
> This package is currently in `alpha` and is subject to change.
## Reference
* [JSON-RPC 2.0 Specification](http://www.jsonrpc.org/specification)
* [NEO JSON-RPC 2.0 docs](http://docs.neo.org/en-us/node/api.html)
## Client
You can create a new client and start interacting with any NEO node that exposes their
`JSON-RPC` endpoint. See [godocs](https://godoc.org/github.com/CityOfZion/neo-go/pkg/rpc) for example.
> Not all methods are currently supported in the client, please see table below for supported methods.
### TODO
* Merge structs so can be used by both server and client.
* Add missing methods to client.
* Allow client to connect using client cert.
### Supported methods
| Method | Implemented | Required to implement |
| ------- | ------------| --------------------- |
| `getblock` | Yes | - |
| `getaccountstate` | Yes | - |
| `invokescript` | Yes | - |
| `invokefunction` | Yes | - |
| `sendrawtransaction` | Yes | - |
| `validateaddress` | No | Handler and result struct |
| `getblocksysfee` | No | Handler and result struct |
| `getcontractstate` | No | Handler and result struct |
| `getrawmempool` | No | Handler and result struct |
| `getrawtransaction` | No | Handler and result struct |
| `getstorage` | No | Handler and result struct |
| `submitblock` | No | Handler and result struct |
| `gettxout` | No | Handler and result struct |
| `invoke` | No | Handler and result struct |
| `getassetstate` | No | Handler and result struct |
| `getpeers` | No | Handler and result struct |
| `getversion` | No | Handler and result struct |
| `getconnectioncount` | No | Handler and result struct |
| `getblockhash` | No | Handler and result struct |
| `getblockcount` | No | Handler and result struct |
| `getbestblockhash` | No | Handler and result struct |
## Server
The server is written to support as much of the [JSON-RPC 2.0 Spec](http://www.jsonrpc.org/specification) as possible. The server is run as part of the node currently.
### TODO
* Implement HTTPS server.
* Add remaining methods (Documented below).
* Add Swagger spec and test using dredd in circleCI.
### Example call
An example would be viewing the version of the node:
```bash
curl -X POST -d '{"jsonrpc": "2.0", "method": "getversion", "params": [], "id": 1}" http://localhost:20332
```
which would yield the response:
```json
{
"jsonrpc" : "2.0",
"id" : 1,
"result" : {
"port" : 20333,
"useragent" : "/NEO-GO:0.36.0-dev/",
"nonce" : 9318417
}
}
```
### Supported methods
| Method | Implemented | Required to implement |
| ------- | ------------| --------------------- |
| `getblock` | Yes | - |
| `getaccountstate` | No | Result struct & wallet functionality |
| `invokescript` | No | VM |
| `invokefunction` | No | VM |
| `sendrawtransaction` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `validateaddress` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `getblocksysfee` | No | N/A |
| `getcontractstate` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `getrawmempool` | No | Needs to be implemented on in `pkg/network/server.go` |
| `getrawtransaction` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `getstorage` | No | VM |
| `submitblock` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `gettxout` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `invoke` | No | VM |
| `getassetstate` | No | Needs to be implemented in `pkg/core/blockchain.go` |
| `getpeers` | Yes | - |
| `getversion` | Yes | - |
| `getconnectioncount` | Yes | - |
| `getblockhash` | Yes | - |
| `getblockcount` | Yes | - |
| `getbestblockhash` | Yes | - |

View file

@ -9,6 +9,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/network"
"github.com/CityOfZion/neo-go/pkg/rpc/result"
"github.com/CityOfZion/neo-go/pkg/rpc/wrappers"
"github.com/CityOfZion/neo-go/pkg/util"
log "github.com/sirupsen/logrus"
)
@ -133,12 +134,13 @@ Methods:
break
}
results, err = s.chain.GetBlock(hash)
block, err := s.chain.GetBlock(hash)
if err != nil {
resultsErr = NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
break
}
results = wrappers.NewBlock(block, s.chain)
case "getblockcount":
results = s.chain.BlockHeight()

33
pkg/rpc/wrappers/block.go Normal file
View file

@ -0,0 +1,33 @@
package wrappers
import (
"github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/util"
)
type (
// Block wrapper used for the representation of
// core.Block / core.BlockBase on the RPC Server.
Block struct {
*core.Block
Confirmations uint32 `json:"confirmations"`
NextBlockHash util.Uint256 `json:"nextblockhash,omitempty"`
Hash util.Uint256 `json:"hash"`
}
)
// NewBlock creates a new Block wrapper.
func NewBlock(block *core.Block, chain core.Blockchainer) Block {
blockWrapper := Block{
Block: block,
Hash: block.Hash(),
}
hash := chain.GetHeaderHash(int(block.Index) + 1)
if !hash.Equals(util.Uint256{}) {
blockWrapper.NextBlockHash = hash
}
blockWrapper.Confirmations = chain.BlockHeight() - block.Index - 1
return blockWrapper
}

View file

@ -79,5 +79,7 @@ func (u Uint160) Equals(other Uint160) bool {
// MarshalJSON implements the json marshaller interface.
func (u Uint160) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
return json.Marshal(
fmt.Sprintf("0x%s", hex.EncodeToString(ArrayReverse(u.Bytes()))),
)
}

View file

@ -61,5 +61,5 @@ func (u Uint256) String() string {
// MarshalJSON implements the json marshaller interface.
func (u Uint256) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
return json.Marshal(fmt.Sprintf("0x%s", u.String()))
}