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: cmd: implement import-runtime subcommand #1483

Merged
merged 4 commits into from
Mar 23, 2021
Merged
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
48 changes: 48 additions & 0 deletions cmd/gossamer/import_runtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2019 ChainSafe Systems (ON) Corp.
// This file is part of gossamer.
//
// The gossamer library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The gossamer library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the gossamer library. If not, see <http://www.gnu.org/licenses/>.

package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"

"github.com/ChainSafe/gossamer/lib/genesis"
)

var defaultGenesisSpecPath = "./chain/gssmr/genesis.json"

func createGenesisWithRuntime(fp string) (string, error) {
runtime, err := ioutil.ReadFile(filepath.Clean(fp))
if err != nil {
return "", err
}

genesis, err := genesis.NewGenesisSpecFromJSON(defaultGenesisSpecPath)
if err != nil {
return "", err
}

genesis.Genesis.Runtime["system"]["code"] = fmt.Sprintf("0x%x", runtime)
bz, err := json.MarshalIndent(genesis, "", "\t")
if err != nil {
return "", err
}

return string(bz), nil
}
50 changes: 50 additions & 0 deletions cmd/gossamer/import_runtime_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2019 ChainSafe Systems (ON) Corp.
// This file is part of gossamer.
//
// The gossamer library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The gossamer library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the gossamer library. If not, see <http://www.gnu.org/licenses/>.

package main

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

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/genesis"

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

func TestCreateGenesisWithRuntime(t *testing.T) {
defaultGenesisSpecPath = "../../chain/gssmr/genesis.json"

testCode := []byte("somecode")
testHex := common.BytesToHex(testCode)
testFile, err := ioutil.TempFile("", "testcode-*.wasm")
require.NoError(t, err)
defer os.Remove(testFile.Name())

err = ioutil.WriteFile(testFile.Name(), testCode, 0777)
require.NoError(t, err)

out, err := createGenesisWithRuntime(testFile.Name())
require.NoError(t, err)

g := new(genesis.Genesis)
err = json.Unmarshal([]byte(out), g)
require.NoError(t, err)
require.Equal(t, testHex, g.Genesis.Runtime["system"]["code"].(string))
}
34 changes: 17 additions & 17 deletions cmd/gossamer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/ChainSafe/gossamer/dot"
"github.com/ChainSafe/gossamer/lib/keystore"
Expand Down Expand Up @@ -71,7 +69,7 @@ var (
"\tTo import a keystore file: gossamer account --import=path/to/file\n" +
"\tTo list keys: gossamer account --list",
}
// initCommand defines the "init" subcommand (ie, `gossamer init`)
// buildSpecCommand creates a raw genesis file from a human readable genesis file.
buildSpecCommand = cli.Command{
Action: FixFlagOrder(buildSpecAction),
Name: "build-spec",
Expand All @@ -81,18 +79,20 @@ var (
Category: "BUILD-SPEC",
Description: "The build-spec command outputs current genesis JSON data.\n" +
"\tUsage: gossamer build-spec\n" +
"\tTo generate raw genesis file: gossamer build-spec --raw",
"\tTo generate raw genesis file from default: gossamer build-spec --raw > genesis-raw.json" +
"\tTo generate raw genesis file from specific genesis file: gossamer build-spec --raw --genesis genesis.json > genesis-raw.json",
}
// TODO: update this to put the wasm into a genesis file
wasmToHexCommand = cli.Command{
Action: FixFlagOrder(wasmToHexAction),
Name: "convert-wasm",
Usage: "Converts a .wasm file to a hex string to be used in a genesis file",

// importRuntime generates a genesis file given a .wasm runtime binary.
importRuntimeCommand = cli.Command{
Action: FixFlagOrder(importRuntimeAction),
Name: "import-runtime",
Usage: "Generates a genesis file given a .wasm runtime binary",
ArgsUsage: "",
Flags: RootFlags,
Category: "CONVERT-WASM",
Description: "The convert-wasm command converts a .wasm file to a hex string to be used in a genesis file.\n" +
"\tUsage: gossamer convert-wasm runtime.wasm\n",
Category: "IMPORT-RUNTIME",
Description: "The import-runtime command generates a genesis file given a .wasm runtime binary.\n" +
"\tUsage: gossamer import-runtime runtime.wasm > genesis.json\n",
}

importStateCommand = cli.Command{
Expand Down Expand Up @@ -121,7 +121,7 @@ func init() {
initCommand,
accountCommand,
buildSpecCommand,
wasmToHexCommand,
importRuntimeCommand,
importStateCommand,
}
app.Flags = RootFlags
Expand Down Expand Up @@ -163,20 +163,20 @@ func importStateAction(ctx *cli.Context) error {
return dot.ImportState(cfg.Global.BasePath, stateFP, headerFP, uint64(firstSlot))
}

// wasmToHexAction converts a .wasm file to a hex string and outputs it to stdout
func wasmToHexAction(ctx *cli.Context) error {
// importRuntimeAction generates a genesis file given a .wasm runtime binary.
func importRuntimeAction(ctx *cli.Context) error {
arguments := ctx.Args()
if len(arguments) == 0 {
return fmt.Errorf("no args provided, please provide wasm file")
}

fp := arguments[0]
bytes, err := ioutil.ReadFile(filepath.Clean(fp))
out, err := createGenesisWithRuntime(fp)
if err != nil {
return err
}

fmt.Printf("0x%x", bytes)
fmt.Println(out)
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion lib/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Data struct {

// Fields stores genesis raw data, and human readable runtime data
type Fields struct {
Raw map[string]map[string]string `json:"raw"`
Raw map[string]map[string]string `json:"raw,omitempty"`
Runtime map[string]map[string]interface{} `json:"runtime,omitempty"`
}

Expand Down
34 changes: 22 additions & 12 deletions lib/genesis/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,37 +111,47 @@ func trimGenesisAuthority(g *Genesis, authCount int) {
// NewGenesisFromJSON parses Human Readable JSON formatted genesis file.Name. If authCount > 0,
// then it keeps only `authCount` number of authorities for babe and grandpa.
func NewGenesisFromJSON(file string, authCount int) (*Genesis, error) {
fp, err := filepath.Abs(file)
g, err := NewGenesisSpecFromJSON(file)
if err != nil {
return nil, err
}

data, err := ioutil.ReadFile(filepath.Clean(fp))
if authCount > 0 {
trimGenesisAuthority(g, authCount)
}

grt := g.Genesis.Runtime
res, err := buildRawMap(grt)
if err != nil {
return nil, err
}

g := new(Genesis)
g.Genesis.Raw = make(map[string]map[string]string)
g.Genesis.Raw["top"] = res

err = json.Unmarshal(data, g)
return g, err
}

// NewGenesisSpecFromJSON returns a new Genesis (without raw fields) from a human-readable genesis file
func NewGenesisSpecFromJSON(file string) (*Genesis, error) {
fp, err := filepath.Abs(file)
if err != nil {
return nil, err
}

if authCount > 0 {
trimGenesisAuthority(g, authCount)
data, err := ioutil.ReadFile(filepath.Clean(fp))
if err != nil {
return nil, err
}

grt := g.Genesis.Runtime
res, err := buildRawMap(grt)
g := new(Genesis)

err = json.Unmarshal(data, g)
if err != nil {
return nil, err
}

g.Genesis.Raw = make(map[string]map[string]string)
g.Genesis.Raw["top"] = res

return g, err
return g, nil
}

// keyValue struct to hold data regarding entry
Expand Down