Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ func (client *Client) Close() error {
}

func (client *Client) BroadcastTransactionSynchronous(ctx context.Context, chainID []byte, operations []types.Operation, keys ...*key.PrivateKey) (*network_broadcast.BroadcastResponse, error) {
stx, err := client.createSignedTransaction(ctx, chainID, operations, keys...)
stx, err := client.CreateSignedTransaction(ctx, chainID, operations, keys...)
if err != nil {
return nil, err
}
return client.NetworkBroadcast.BroadcastTransactionSynchronous(ctx, stx.Transaction)
}

func (client *Client) BroadcastTransaction(ctx context.Context, chainID []byte, operations []types.Operation, keys ...*key.PrivateKey) (string, error) {
stx, err := client.createSignedTransaction(ctx, chainID, operations, keys...)
stx, err := client.CreateSignedTransaction(ctx, chainID, operations, keys...)
if err != nil {
return "", err
}
Expand All @@ -82,7 +82,7 @@ func (client *Client) BroadcastTransaction(ctx context.Context, chainID []byte,
return hex.EncodeToString(id), client.NetworkBroadcast.BroadcastTransaction(ctx, stx.Transaction)
}

func (client *Client) createSignedTransaction(ctx context.Context, chainID []byte, operations []types.Operation, keys ...*key.PrivateKey) (*sign.SignedTransaction, error) {
func (client *Client) CreateSignedTransaction(ctx context.Context, chainID []byte, operations []types.Operation, keys ...*key.PrivateKey) (*sign.SignedTransaction, error) {
props, err := client.Chain.GetChainProperties(ctx)
if err != nil {
return nil, fmt.Errorf("get chainID properties: %w", err)
Expand Down
10 changes: 5 additions & 5 deletions sign/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"bytes"
"encoding/binary"
"encoding/hex"

"github.com/pkg/errors"
"errors"
"fmt"
)

func RefBlockNum(blockNumber uint32) uint16 {
Expand All @@ -16,20 +16,20 @@ func RefBlockPrefix(blockID string) (uint32, error) {
// Block ID is hex-encoded.
rawBlockID, err := hex.DecodeString(blockID)
if err != nil {
return 0, errors.Wrapf(err, "network_broadcast: failed to decode block ID: %v", blockID)
return 0, fmt.Errorf("failed to decode block ID: %w", err)
}

// Raw prefix = raw block ID [4:8].
// Make sure we don't trigger a slice bounds out of range panic.
if len(rawBlockID) < 8 {
return 0, errors.Errorf("network_broadcast: invalid block ID: %v", blockID)
return 0, errors.New("invalid blockID")
}
rawPrefix := rawBlockID[4:8]

// Decode the prefix.
var prefix uint32
if err := binary.Read(bytes.NewReader(rawPrefix), binary.LittleEndian, &prefix); err != nil {
return 0, errors.Wrapf(err, "network_broadcast: failed to read block prefix: %v", rawPrefix)
return 0, fmt.Errorf("failed to read block prefix: %w", err)
}

// Done, return the prefix.
Expand Down
24 changes: 24 additions & 0 deletions transport/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package transport

import "sync"

type SequenceGenerator struct {
requestID uint64
mtx sync.Mutex
}

func NewSequenceGenerator(initial uint64) *SequenceGenerator {
return &SequenceGenerator{
requestID: initial,
mtx: sync.Mutex{},
}
}

func (r *SequenceGenerator) Generate() uint64 {
r.mtx.Lock()
defer r.mtx.Unlock()

r.requestID++

return r.requestID
}
62 changes: 34 additions & 28 deletions transport/http/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,29 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math"
"net/http"
"sync"
"time"

"github.com/pkg/errors"
"github.com/scorum/scorum-go/transport"
)

type requestIDGenerator interface {
Generate() uint64
}

type Transport struct {
Url string
client *http.Client

requestID uint64
reqMutex sync.Mutex
requestID requestIDGenerator
}

func NewTransport(url string, options ...func(*Transport)) *Transport {
t := Transport{
Url: url,
Url: url,
requestID: transport.NewSequenceGenerator(0),
}

for _, o := range options {
Expand All @@ -48,59 +50,45 @@ func WithHttpClient(client *http.Client) func(*Transport) {
}

func (caller *Transport) Call(ctx context.Context, api string, method string, args []interface{}, reply interface{}) error {
caller.reqMutex.Lock()
defer caller.reqMutex.Unlock()

// increase request id
if caller.requestID == math.MaxUint64 {
caller.requestID = 0
}
caller.requestID++

request := transport.RPCRequest{
Method: "call",
ID: caller.requestID,
ID: caller.requestID.Generate(),
Params: []interface{}{api, method, args},
}

reqBody, err := json.Marshal(request)
if err != nil {
return err
return fmt.Errorf("json marshall: %w", err)
}

req, err := http.NewRequestWithContext(ctx, "POST", caller.Url, bytes.NewBuffer(reqBody))
if err != nil {
return err
return fmt.Errorf("http new request: %w", err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := caller.client.Do(req)
if err != nil {
return err
return fmt.Errorf("http client do: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return errors.Wrap(err, "failed to read body")
}

var rpcResponse transport.RPCResponse
if err = json.Unmarshal(respBody, &rpcResponse); err != nil {
return errors.Wrapf(err, "failed to unmarshal response: %+v", string(respBody))
if err := decodeJSON(resp.Body, &rpcResponse); err != nil {
return fmt.Errorf("failed decode rpc response: %w", err)
}

if rpcResponse.Error != nil {
return rpcResponse.Error
}

if rpcResponse.Result != nil {
if err := json.Unmarshal(*rpcResponse.Result, reply); err != nil {
return errors.Wrapf(err, "failed to unmarshal rpc result: %+v", string(*rpcResponse.Result))
if err := decodeJSON(bytes.NewReader(*rpcResponse.Result), reply); err != nil {
return fmt.Errorf("failed decode rpc result: %w", err)
}
}

Expand All @@ -114,3 +102,21 @@ func (caller *Transport) SetCallback(api string, method string, notice func(args
func (caller *Transport) Close() error {
return nil
}

func decodeJSON(reader io.Reader, out interface{}) error {
buf := new(bytes.Buffer)
tr := io.TeeReader(reader, buf)

data, err := ioutil.ReadAll(tr)
if err != nil {
return fmt.Errorf("failed to read body: %w", err)
}
if !json.Valid(data) {
return fmt.Errorf("invalid json: %q", buf.String())
}

if err := json.NewDecoder(buf).Decode(out); err != nil {
return fmt.Errorf("failed to decode json: %w", err)
}
return nil
}
2 changes: 1 addition & 1 deletion types/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package types

import (
"encoding/json"
"github.com/pkg/errors"
"errors"
"reflect"
)

Expand Down