From 564300aaa2125d5881ecf62f024a22db190db17c Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 27 Jun 2023 14:44:55 +0200 Subject: [PATCH] feat(proof.go): adding JSON marshal/unmarshal (#214) Adds json marshaling/unmarshaling to `nmt.Proof`. As found elsewhere in the go stdlib, `UnmarshalJSON` must be defined on the pointer receiver although `MarshalJSON` is a value receiver. This is needed because the fields are private. Does this need to be the case? If we make them public, JSON marshaling will work by default. --- proof.go | 34 ++++++++++++++++++++++++++++++++++ proof_test.go | 23 +++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/proof.go b/proof.go index 2a1037c..de307db 100644 --- a/proof.go +++ b/proof.go @@ -2,6 +2,7 @@ package nmt import ( "bytes" + "encoding/json" "errors" "fmt" "hash" @@ -47,6 +48,39 @@ type Proof struct { isMaxNamespaceIDIgnored bool } +type jsonProof struct { + Start int `json:"start"` + End int `json:"end"` + Nodes [][]byte `json:"nodes"` + LeafHash []byte `json:"leaf_hash"` + IsMaxNamespaceIDIgnored bool `json:"is_max_namespace_id_ignored"` +} + +func (proof Proof) MarshalJSON() ([]byte, error) { + jsonProofObj := jsonProof{ + Start: proof.start, + End: proof.end, + Nodes: proof.nodes, + LeafHash: proof.leafHash, + IsMaxNamespaceIDIgnored: proof.isMaxNamespaceIDIgnored, + } + return json.Marshal(jsonProofObj) +} + +func (proof *Proof) UnmarshalJSON(data []byte) error { + var jsonProofObj jsonProof + err := json.Unmarshal(data, &jsonProofObj) + if err != nil { + return err + } + proof.start = jsonProofObj.Start + proof.end = jsonProofObj.End + proof.nodes = jsonProofObj.Nodes + proof.leafHash = jsonProofObj.LeafHash + proof.isMaxNamespaceIDIgnored = jsonProofObj.IsMaxNamespaceIDIgnored + return nil +} + // Start index of this proof. func (proof Proof) Start() int { return proof.start diff --git a/proof_test.go b/proof_test.go index df0f90f..cb2cccc 100644 --- a/proof_test.go +++ b/proof_test.go @@ -13,6 +13,29 @@ import ( "github.com/celestiaorg/nmt/namespace" ) +func TestJsonMarshal_Proof(t *testing.T) { + // create a tree with 4 leaves + nIDSize := 1 + tree := exampleNMT(nIDSize, true, 1, 2, 3, 4) + + // build a proof for an NID that is within the namespace range of the tree + nID := []byte{1} + proof, err := tree.ProveNamespace(nID) + require.NoError(t, err) + + // marshal the proof to JSON + jsonProof, err := proof.MarshalJSON() + require.NoError(t, err) + + // unmarshal the proof from JSON + var unmarshalledProof Proof + err = unmarshalledProof.UnmarshalJSON(jsonProof) + require.NoError(t, err) + + // verify that the unmarshalled proof is equal to the original proof + assert.Equal(t, proof, unmarshalledProof) +} + // TestVerifyNamespace_EmptyProof tests the correct behaviour of VerifyNamespace for valid and invalid empty proofs. func TestVerifyNamespace_EmptyProof(t *testing.T) { // create a tree with 4 leaves