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 (backport #14329) #14511

Closed
wants to merge 1 commit into from
Closed
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
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"`)
}