Skip to content

Commit

Permalink
Merge branch 'release/v1.14.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
algojack committed Mar 29, 2022
2 parents 3145026 + ff1bfcb commit efae689
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 1.14.1
- Avoid client response failure on unknown field (#307)
- Add ParticipationUpdates to BlockHeader (#306)
# 1.14.0
- Unlimited assets changes (#294)
- Update abi impl from go-algorand (#303)
Expand Down
9 changes: 5 additions & 4 deletions client/v2/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package common
import (
"bytes"
"context"
"encoding/json"

"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"

"github.com/algorand/go-algorand-sdk/encoding/json"
"github.com/algorand/go-algorand-sdk/encoding/msgpack"
"github.com/google/go-querystring/query"
)
Expand Down Expand Up @@ -123,7 +124,7 @@ func (client *Client) submitFormRaw(ctx context.Context, path string, body inter

queryURL.RawQuery = mergeRawQueries(queryURL.RawQuery, v.Encode())
if encodeJSON {
jsonValue, _ := json.Marshal(body)
jsonValue := json.Encode(body)
bodyReader = bytes.NewBuffer(jsonValue)
}
}
Expand Down Expand Up @@ -182,7 +183,7 @@ func (client *Client) submitForm(ctx context.Context, response interface{}, path
}

// Attempt to unmarshal a response regardless of whether or not there was an error.
err = json.Unmarshal(bodyBytes, response)
err = json.LenientDecode(bodyBytes, response)
if responseErr != nil {
// Even if there was an unmarshalling error, return the HTTP error first if there was one.
return responseErr
Expand Down Expand Up @@ -230,7 +231,7 @@ func (client *Client) GetRawMsgpack(ctx context.Context, response interface{}, p
return extractError(resp.StatusCode, bodyBytes)
}

dec := msgpack.NewDecoder(resp.Body)
dec := msgpack.NewLenientDecoder(resp.Body)
return dec.Decode(&response)
}

Expand Down
27 changes: 27 additions & 0 deletions encoding/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
// with our settings (canonical, paranoid about decoding errors)
var CodecHandle *codec.JsonHandle

// LenientCodecHandle is used to instantiate msgpack encoders for the REST API.
var LenientCodecHandle *codec.JsonHandle

// init configures our json encoder and decoder
func init() {
CodecHandle = new(codec.JsonHandle)
Expand All @@ -19,6 +22,14 @@ func init() {
CodecHandle.RecursiveEmptyCheck = true
CodecHandle.Indent = 2
CodecHandle.HTMLCharsAsIs = true

LenientCodecHandle = new(codec.JsonHandle)
LenientCodecHandle.ErrorIfNoField = false
LenientCodecHandle.ErrorIfNoArrayExpand = true
LenientCodecHandle.Canonical = true
LenientCodecHandle.RecursiveEmptyCheck = true
LenientCodecHandle.Indent = 2
LenientCodecHandle.HTMLCharsAsIs = true
}

// Encode returns a json-encoded byte buffer for a given object
Expand All @@ -40,7 +51,23 @@ func Decode(b []byte, objptr interface{}) error {
return nil
}

// LenientDecode attempts to decode a json-encoded byte buffer into an
// object instance pointed to by objptr
func LenientDecode(b []byte, objptr interface{}) error {
dec := codec.NewDecoderBytes(b, LenientCodecHandle)
err := dec.Decode(objptr)
if err != nil {
return err
}
return nil
}

// NewDecoder returns a json decoder
func NewDecoder(r io.Reader) *codec.Decoder {
return codec.NewDecoder(r, CodecHandle)
}

// NewLenientDecoder returns a json decoder
func NewLenientDecoder(r io.Reader) *codec.Decoder {
return codec.NewDecoder(r, LenientCodecHandle)
}
60 changes: 60 additions & 0 deletions encoding/json/json_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package json

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
)

type object struct {
subsetObject
Name string `codec:"name"`
}

type subsetObject struct {
Data string `codec:"data"`
}

func TestDecode(t *testing.T) {
obj := object{
subsetObject: subsetObject{Data: "data"},
Name: "name",
}
encodedOb := Encode(obj)

t.Run("basic encode/decode test", func(t *testing.T) {
// basic encode/decode test.
var decoded object
err := Decode(encodedOb, &decoded)
assert.NoError(t, err)
assert.Equal(t, obj, decoded)
})

t.Run("strict decode, pass", func(t *testing.T) {
// strict decode test
decoder := NewDecoder(bytes.NewReader(encodedOb))
var decoded object
err := decoder.Decode(&decoded)
assert.NoError(t, err)
assert.Equal(t, obj, decoded)
})

t.Run("strict decode subset, fail", func(t *testing.T) {
// strict decode test
decoder := NewDecoder(bytes.NewReader(encodedOb))
var decoded subsetObject
err := decoder.Decode(&decoded)
assert.Error(t, err)
assert.Contains(t, err.Error(), "no matching struct field found when decoding stream map with key name")
})

t.Run("lenient decode subset, pass", func(t *testing.T) {
// strict decode test
decoder := NewLenientDecoder(bytes.NewReader(encodedOb))
var decoded subsetObject
err := decoder.Decode(&decoded)
assert.NoError(t, err)
assert.Equal(t, obj.subsetObject, decoded)
})
}
17 changes: 17 additions & 0 deletions encoding/msgpack/msgpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
// with our settings (canonical, paranoid about decoding errors)
var CodecHandle *codec.MsgpackHandle

// LenientCodecHandle is used to instantiate msgpack encoders for the REST API.
var LenientCodecHandle *codec.MsgpackHandle

// init configures our msgpack encoder and decoder
func init() {
CodecHandle = new(codec.MsgpackHandle)
Expand All @@ -19,6 +22,15 @@ func init() {
CodecHandle.RecursiveEmptyCheck = true
CodecHandle.WriteExt = true
CodecHandle.PositiveIntUnsigned = true

LenientCodecHandle = new(codec.MsgpackHandle)
// allow unknown fields to ensure forward compatibility.
LenientCodecHandle.ErrorIfNoField = false
LenientCodecHandle.ErrorIfNoArrayExpand = true
LenientCodecHandle.Canonical = true
LenientCodecHandle.RecursiveEmptyCheck = true
LenientCodecHandle.WriteExt = true
LenientCodecHandle.PositiveIntUnsigned = true
}

// Encode returns a msgpack-encoded byte buffer for a given object
Expand All @@ -44,3 +56,8 @@ func Decode(b []byte, objptr interface{}) error {
func NewDecoder(r io.Reader) *codec.Decoder {
return codec.NewDecoder(r, CodecHandle)
}

// NewLenientDecoder returns a msgpack decoder
func NewLenientDecoder(r io.Reader) *codec.Decoder {
return codec.NewDecoder(r, LenientCodecHandle)
}
60 changes: 60 additions & 0 deletions encoding/msgpack/msgpack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package msgpack

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
)

type object struct {
subsetObject
Name string `codec:"name"`
}

type subsetObject struct {
Data string `codec:"data"`
}

func TestDecode(t *testing.T) {
obj := object{
subsetObject: subsetObject{Data: "data"},
Name: "name",
}
encodedOb := Encode(obj)

t.Run("basic encode/decode test", func(t *testing.T) {
// basic encode/decode test.
var decoded object
err := Decode(encodedOb, &decoded)
assert.NoError(t, err)
assert.Equal(t, obj, decoded)
})

t.Run("strict decode, pass", func(t *testing.T) {
// strict decode test
decoder := NewDecoder(bytes.NewReader(encodedOb))
var decoded object
err := decoder.Decode(&decoded)
assert.NoError(t, err)
assert.Equal(t, obj, decoded)
})

t.Run("strict decode subset, fail", func(t *testing.T) {
// strict decode test
decoder := NewDecoder(bytes.NewReader(encodedOb))
var decoded subsetObject
err := decoder.Decode(&decoded)
assert.Error(t, err)
assert.Contains(t, err.Error(), "no matching struct field found when decoding stream map with key name")
})

t.Run("lenient decode subset, pass", func(t *testing.T) {
// strict decode test
decoder := NewLenientDecoder(bytes.NewReader(encodedOb))
var decoded subsetObject
err := decoder.Decode(&decoded)
assert.NoError(t, err)
assert.Equal(t, obj.subsetObject, decoded)
})
}
15 changes: 15 additions & 0 deletions types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ type (
// transactions have ever been committed (since TxnCounter
// started being supported).
TxnCounter uint64 `codec:"tc"`

// ParticipationUpdates contains the information needed to mark
// certain accounts offline because their participation keys expired
ParticipationUpdates
}

// ParticipationUpdates represents participation account data that
// needs to be checked/acted on by the network
ParticipationUpdates struct {
_struct struct{} `codec:",omitempty,omitemptyarray"`

// ExpiredParticipationAccounts contains a list of online accounts
// that needs to be converted to offline since their
// participation key expired.
ExpiredParticipationAccounts []Address `codec:"partupdrmv"`
}

// RewardsState represents the global parameters controlling the rate
Expand Down

0 comments on commit efae689

Please sign in to comment.