Skip to content

Commit

Permalink
fixup! Custom JSON serialization of TipSetKey for array-of-CIDs
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg committed Nov 27, 2024
1 parent 53c3ad1 commit 5c25653
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
2 changes: 1 addition & 1 deletion certs/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type FinalityCertificate struct {
Signature []byte
// Changes between the power table used to validate this finality certificate and the power
// used to validate the next finality certificate. Sorted by ParticipantID, ascending.
PowerTableDelta PowerTableDiff `json:"omitempty"`
PowerTableDelta PowerTableDiff `json:"PowerTableDelta,omitempty"`
}

// NewFinalityCertificate constructs a new finality certificate from the given power delta (from
Expand Down
7 changes: 6 additions & 1 deletion gpbft/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func TestECChain_Eq(t *testing.T) {
}
}

func TestTipSetKeySerialization(t *testing.T) {
func TestTipSetSerialization(t *testing.T) {
t.Parallel()
var (
c1 = gpbft.MakeCid([]byte("barreleye1"))
Expand Down Expand Up @@ -268,6 +268,11 @@ func TestTipSetKeySerialization(t *testing.T) {
for j, c := range []cid.Cid{c1, c2, c3}[:len(ts.Key)/38] {
req.Equal(map[string]any{"/": c.String()}, keyField[j])
}

// check that the supplemental data is a base64 string
commitField, ok := bareMap["Commitments"].(string)
req.True(ok)
req.Len(commitField, 44)
}
})

Expand Down
30 changes: 30 additions & 0 deletions gpbft/gpbft.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"math"
Expand Down Expand Up @@ -94,6 +95,35 @@ func (d *SupplementalData) Eq(other *SupplementalData) bool {
return d.Commitments == other.Commitments && d.PowerTable == other.PowerTable
}

// Custom JSON marshalling for SupplementalData to achieve a commitment field
// that is a base64-encoded string.

type supplementalDataSub SupplementalData
type supplementalDataJson struct {
Commitments []byte
*supplementalDataSub
}

func (sd SupplementalData) MarshalJSON() ([]byte, error) {
return json.Marshal(&supplementalDataJson{
Commitments: sd.Commitments[:],
supplementalDataSub: (*supplementalDataSub)(&sd),
})
}

func (sd *SupplementalData) UnmarshalJSON(b []byte) error {
aux := &supplementalDataJson{supplementalDataSub: (*supplementalDataSub)(sd)}
var err error
if err = json.Unmarshal(b, &aux); err != nil {
return err
}

Check warning on line 119 in gpbft/gpbft.go

View check run for this annotation

Codecov / codecov/patch

gpbft/gpbft.go#L118-L119

Added lines #L118 - L119 were not covered by tests
if len(aux.Commitments) != 32 {
return errors.New("commitments must be 32 bytes")
}
copy(sd.Commitments[:], aux.Commitments)
return nil
}

// Fields of the message that make up the signature payload.
type Payload struct {
// GossiPBFT instance (epoch) number.
Expand Down
55 changes: 55 additions & 0 deletions gpbft/gpbft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gpbft_test
import (
"bytes"
"crypto/rand"
"encoding/json"
"io"
"testing"

Expand Down Expand Up @@ -1734,3 +1735,57 @@ func TestGPBFT_Sway(t *testing.T) {
require.Fail(t, "after 10 tries did not swayed to proposals 1 and 2 at CONVERGE and COMMIT, respectively.")
})
}

func TestSupplementalDataSerialization(t *testing.T) {
t.Parallel()
var (
testCases = []gpbft.SupplementalData{
{
PowerTable: gpbft.MakeCid([]byte("fish")),
Commitments: [32]byte{0x01},
},
{
PowerTable: gpbft.MakeCid([]byte("lobster")),
Commitments: [32]byte{0x02},
},
}
)

t.Run("cbor round trip", func(t *testing.T) {
req := require.New(t)
for _, ts := range testCases {
var buf bytes.Buffer
req.NoError(ts.MarshalCBOR(&buf))
t.Logf("cbor: %x", buf.Bytes())
var rt gpbft.SupplementalData
req.NoError(rt.UnmarshalCBOR(&buf))
req.Equal(ts, rt)
}
})

t.Run("json round trip", func(t *testing.T) {
req := require.New(t)
for _, ts := range testCases {
data, err := ts.MarshalJSON()
req.NoError(err)
t.Logf("json: %s", data)
var rt gpbft.SupplementalData
req.NoError(rt.UnmarshalJSON(data))
req.Equal(ts, rt)

// check that the supplemental data is a base64 string
var bareMap map[string]any
req.NoError(json.Unmarshal(data, &bareMap))
commitField, ok := bareMap["Commitments"].(string)
req.True(ok)
req.Len(commitField, 44)
}
})

t.Run("json error cases", func(t *testing.T) {
req := require.New(t)
var ts gpbft.SupplementalData
err := ts.UnmarshalJSON([]byte(`{"Commitments":"bm9wZQ==","PowerTable":{"/":"bafy2bzaced5zqzzbxzyzuq2tcxhuclnvdn3y6ijhurgaapnbayul2dd5gspc4"}}`))
req.ErrorContains(err, "32 bytes")
})
}

0 comments on commit 5c25653

Please sign in to comment.