Skip to content

Commit

Permalink
feat: cmd: implement import-runtime subcommand (#1483)
Browse files Browse the repository at this point in the history
  • Loading branch information
noot authored Mar 23, 2021
1 parent b8c4dd7 commit d82b2da
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 30 deletions.
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

0 comments on commit d82b2da

Please sign in to comment.