forked from TrueCloudLab/neoneo-go
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:
parent
c51a6d3e57
commit
0b023c5c5c
11 changed files with 179 additions and 20 deletions
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ VERSION = $(shell cat ./VERSION)
|
||||||
NETMODE ?= "privnet"
|
NETMODE ?= "privnet"
|
||||||
|
|
||||||
build:
|
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:
|
check-version:
|
||||||
git fetch && (! git rev-list ${VERSION})
|
git fetch && (! git rev-list ${VERSION})
|
||||||
|
|
|
@ -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:
|
A complete toolkit for the NEO blockchain, including:
|
||||||
|
|
||||||
- consensus node
|
- consensus node
|
||||||
- RPC node
|
- [RPC node & client](https://github.com/CityOfZion/neo-go/tree/master/pkg/rpc/README.md)
|
||||||
- RPC client
|
- RPC client
|
||||||
- CLI tool
|
- CLI tool
|
||||||
- Smart contract compiler
|
- Smart contract compiler
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
0.35.1
|
0.36.0
|
||||||
|
|
|
@ -34,7 +34,7 @@ type BlockBase struct {
|
||||||
ConsensusData uint64 `json:"nonce"`
|
ConsensusData uint64 `json:"nonce"`
|
||||||
|
|
||||||
// Contract addresss of the next miner
|
// Contract addresss of the next miner
|
||||||
NextConsensus util.Uint160 `json:"nextminer"`
|
NextConsensus util.Uint160 `json:"next_consensus"`
|
||||||
|
|
||||||
// Padding that is fixed to 1
|
// Padding that is fixed to 1
|
||||||
_ uint8
|
_ uint8
|
||||||
|
|
|
@ -16,7 +16,7 @@ type Transaction struct {
|
||||||
Type TXType `json:"type"`
|
Type TXType `json:"type"`
|
||||||
|
|
||||||
// The trading version which is currently 0.
|
// The trading version which is currently 0.
|
||||||
Version uint8 `json:"-"`
|
Version uint8 `json:"version"`
|
||||||
|
|
||||||
// Data specific to the type of the transaction.
|
// Data specific to the type of the transaction.
|
||||||
// This is always a pointer to a <Type>Transaction.
|
// This is always a pointer to a <Type>Transaction.
|
||||||
|
|
|
@ -2,6 +2,8 @@ package transaction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
|
@ -9,32 +11,42 @@ import (
|
||||||
|
|
||||||
// Witness contains 2 scripts.
|
// Witness contains 2 scripts.
|
||||||
type Witness struct {
|
type Witness struct {
|
||||||
InvocationScript []byte `json:"stack"`
|
InvocationScript []byte
|
||||||
VerificationScript []byte `json:"redeem"`
|
VerificationScript []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements the payload interface.
|
// 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)
|
lenb := util.ReadVarUint(r)
|
||||||
wit.InvocationScript = make([]byte, lenb)
|
w.InvocationScript = make([]byte, lenb)
|
||||||
if err := binary.Read(r, binary.LittleEndian, wit.InvocationScript); err != nil {
|
if err := binary.Read(r, binary.LittleEndian, w.InvocationScript); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
lenb = util.ReadVarUint(r)
|
lenb = util.ReadVarUint(r)
|
||||||
wit.VerificationScript = make([]byte, lenb)
|
w.VerificationScript = make([]byte, lenb)
|
||||||
return binary.Read(r, binary.LittleEndian, wit.VerificationScript)
|
return binary.Read(r, binary.LittleEndian, w.VerificationScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements the payload interface.
|
// EncodeBinary implements the payload interface.
|
||||||
func (wit *Witness) EncodeBinary(w io.Writer) error {
|
func (w *Witness) EncodeBinary(writer io.Writer) error {
|
||||||
if err := util.WriteVarUint(w, uint64(len(wit.InvocationScript))); err != nil {
|
if err := util.WriteVarUint(writer, uint64(len(w.InvocationScript))); err != nil {
|
||||||
return err
|
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
|
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 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
110
pkg/rpc/README.md
Normal 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 | - |
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
"github.com/CityOfZion/neo-go/pkg/network"
|
"github.com/CityOfZion/neo-go/pkg/network"
|
||||||
"github.com/CityOfZion/neo-go/pkg/rpc/result"
|
"github.com/CityOfZion/neo-go/pkg/rpc/result"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/rpc/wrappers"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -133,12 +134,13 @@ Methods:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
results, err = s.chain.GetBlock(hash)
|
block, err := s.chain.GetBlock(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultsErr = NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
|
resultsErr = NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
results = wrappers.NewBlock(block, s.chain)
|
||||||
case "getblockcount":
|
case "getblockcount":
|
||||||
results = s.chain.BlockHeight()
|
results = s.chain.BlockHeight()
|
||||||
|
|
||||||
|
|
33
pkg/rpc/wrappers/block.go
Normal file
33
pkg/rpc/wrappers/block.go
Normal 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
|
||||||
|
}
|
|
@ -79,5 +79,7 @@ func (u Uint160) Equals(other Uint160) bool {
|
||||||
|
|
||||||
// MarshalJSON implements the json marshaller interface.
|
// MarshalJSON implements the json marshaller interface.
|
||||||
func (u Uint160) MarshalJSON() ([]byte, error) {
|
func (u Uint160) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(u.String())
|
return json.Marshal(
|
||||||
|
fmt.Sprintf("0x%s", hex.EncodeToString(ArrayReverse(u.Bytes()))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,5 +61,5 @@ func (u Uint256) String() string {
|
||||||
|
|
||||||
// MarshalJSON implements the json marshaller interface.
|
// MarshalJSON implements the json marshaller interface.
|
||||||
func (u Uint256) MarshalJSON() ([]byte, error) {
|
func (u Uint256) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(u.String())
|
return json.Marshal(fmt.Sprintf("0x%s", u.String()))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue