Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement basic core API genesis source and target #14329

Merged
merged 12 commits into from
Jan 5, 2023
31 changes: 31 additions & 0 deletions core/genesis/source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package genesis

import (
"bytes"
"encoding/json"
"io"

"cosmossdk.io/core/appmodule"
)

// SourceFromRawJSON returns a genesis source based on a raw JSON message.
func SourceFromRawJSON(message json.RawMessage) (appmodule.GenesisSource, error) {
var m map[string]json.RawMessage
err := json.Unmarshal(message, &m)
if err != nil {
return nil, err
}
return func(field string) (io.ReadCloser, error) {
j, ok := m[field]
if !ok {
return nil, nil
}
return readCloserWrapper{bytes.NewReader(j)}, nil
}, nil
}

type readCloserWrapper struct {
io.Reader
}

func (r readCloserWrapper) Close() error { return nil }
44 changes: 44 additions & 0 deletions core/genesis/source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package genesis

import (
"encoding/json"
"io"
"testing"

"github.com/stretchr/testify/require"

"cosmossdk.io/core/appmodule"
)

func TestSource(t *testing.T) {
source, err := SourceFromRawJSON(json.RawMessage(testJSON))
require.NoError(t, err)

expectJSON(t, source, "foo", fooContents)
expectJSON(t, source, "bar", barContents)

// missing fields just return nil, nil
r, err := source("baz")
require.NoError(t, err)
require.Nil(t, r)
}

func expectJSON(t *testing.T, source appmodule.GenesisSource, field, contents string) {
r, err := source(field)
require.NoError(t, err)
bz, err := io.ReadAll(r)
require.NoError(t, err)
require.Equal(t, contents, string(bz))

}

const (
testJSON = `
{
"foo":{"x":1,"y":"abc"},
"bar":[1,2,3,4]
}
`
fooContents = `{"x":1,"y":"abc"}`
barContents = `[1,2,3,4]`
)
44 changes: 44 additions & 0 deletions core/genesis/target.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package genesis

import (
"bytes"
"encoding/json"
"io"

"cosmossdk.io/core/appmodule"
)

// RawJSONTarget returns a struct which encapsulates a genesis target that is
// backed by raw JSON messages. Its Target method should be used to retrieve
// an actual genesis target function. When genesis writing is done, the JSON
// method should be called to retrieve the raw message that has been written.
type RawJSONTarget struct {
m map[string]json.RawMessage
}

// Target returns the actual genesis target function.
func (r *RawJSONTarget) Target() appmodule.GenesisTarget {
return func(field string) (io.WriteCloser, error) {
if r.m == nil {
r.m = map[string]json.RawMessage{}
}

return &genesisWriter{Buffer: &bytes.Buffer{}, sink: r, field: field}, nil
}
}

// JSON returns the raw JSON message that has been written.
func (r *RawJSONTarget) JSON() (json.RawMessage, error) {
return json.MarshalIndent(r.m, "", " ")
}

type genesisWriter struct {
*bytes.Buffer
field string
sink *RawJSONTarget
}

func (r genesisWriter) Close() error {
r.sink.m[r.field] = r.Buffer.Bytes()
return nil
}
33 changes: 33 additions & 0 deletions core/genesis/target_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package genesis

import (
"testing"

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

func TestTarget(t *testing.T) {
target := &RawJSONTarget{}

w, err := target.Target()("foo")
require.NoError(t, err)
_, err = w.Write([]byte("1"))
require.NoError(t, err)
require.NoError(t, w.Close())

w, err = target.Target()("bar")
require.NoError(t, err)
_, err = w.Write([]byte(`"abc"`))
require.NoError(t, err)
require.NoError(t, w.Close())

bz, err := target.JSON()
require.NoError(t, err)

// test that it's correct by reading back with a source
source, err := SourceFromRawJSON(bz)
require.NoError(t, err)

expectJSON(t, source, "foo", "1")
expectJSON(t, source, "bar", `"abc"`)
}