Skip to content

Commit

Permalink
feat: Add properties and chainId on build-spec command (ChainSafe#1520)
Browse files Browse the repository at this point in the history
  • Loading branch information
EclesioMeloJunior committed Apr 16, 2021
1 parent 02b53b6 commit b18290c
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 3 deletions.
5 changes: 5 additions & 0 deletions cmd/gossamer/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ var (
Name: "genesis-spec",
Usage: "Path to human-readable genesis JSON file",
}
OutputSpecFlag = cli.StringFlag{
Name: "output",
Usage: "Path to output the recently created genesis JSON file",
}
)

// Network service configuration flags
Expand Down Expand Up @@ -321,6 +325,7 @@ var (
BuildSpecFlags = append([]cli.Flag{
RawFlag,
GenesisSpecFlag,
OutputSpecFlag,
}, GlobalFlags...)

// ExportFlags are the flags that are valid for use with the export subcommand
Expand Down
14 changes: 11 additions & 3 deletions cmd/gossamer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ func buildSpecAction(ctx *cli.Context) error {
}

var bs *dot.BuildSpec

if genesis := ctx.String(GenesisSpecFlag.Name); genesis != "" {
bspec, e := dot.BuildFromGenesis(genesis, 0)
if e != nil {
Expand Down Expand Up @@ -380,17 +381,24 @@ func buildSpecAction(ctx *cli.Context) error {
}

var res []byte

if ctx.Bool(RawFlag.Name) {
res, err = bs.ToJSONRaw()
} else {
res, err = bs.ToJSON()
}

if err != nil {
return err
}
// TODO implement --output flag so that user can specify redirecting output a file.
// then this can be removed (See issue #1029)
fmt.Printf("%s", res)

if outputPath := ctx.String(OutputSpecFlag.Name); outputPath != "" {
if err = dot.WriteGenesisSpecFile(res, outputPath); err != nil {
return err
}
} else {
fmt.Printf("%s", res)
}

return nil
}
19 changes: 19 additions & 0 deletions cmd/gossamer/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,25 @@ func TestGossamerCommand(t *testing.T) {

}

func TestBuildSpecCommandWithOutput(t *testing.T) {
tmpOutputfile := "/tmp/raw-genesis-spec-output.json"
buildSpecCommand := runTestGossamer(t,
"build-spec",
"--raw",
"--genesis-spec", "../../chain/gssmr/genesis-spec.json",
"--output", tmpOutputfile)

time.Sleep(5 * time.Second)

_, err := os.Stat(tmpOutputfile)
require.False(t, os.IsNotExist(err))
defer os.Remove(tmpOutputfile)

outb, errb := buildSpecCommand.GetOutput()
require.Empty(t, outb)
require.Empty(t, errb)
}

// TODO: TestExportCommand test "gossamer export" does not error

// TODO: TestInitCommand test "gossamer init" does not error
Expand Down
22 changes: 22 additions & 0 deletions dot/build_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ package dot

import (
"encoding/json"
"fmt"
"os"
"path/filepath"

"github.com/ChainSafe/gossamer/dot/state"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/genesis"
"github.com/ChainSafe/gossamer/lib/utils"
log "github.com/ChainSafe/log15"
)

Expand All @@ -35,8 +39,10 @@ func (b *BuildSpec) ToJSON() ([]byte, error) {
tmpGen := &genesis.Genesis{
Name: b.genesis.Name,
ID: b.genesis.ID,
ChainType: b.genesis.ChainType,
Bootnodes: b.genesis.Bootnodes,
ProtocolID: b.genesis.ProtocolID,
Properties: b.genesis.Properties,
Genesis: genesis.Fields{
Runtime: b.genesis.GenesisFields().Runtime,
},
Expand All @@ -52,6 +58,7 @@ func (b *BuildSpec) ToJSONRaw() ([]byte, error) {
ChainType: b.genesis.ChainType,
Bootnodes: b.genesis.Bootnodes,
ProtocolID: b.genesis.ProtocolID,
Properties: b.genesis.Properties,
Genesis: genesis.Fields{
Raw: b.genesis.GenesisFields().Raw,
},
Expand All @@ -71,6 +78,21 @@ func BuildFromGenesis(path string, authCount int) (*BuildSpec, error) {
return bs, nil
}

// WriteGenesisSpecFile writes the build-spec in the output filepath
func WriteGenesisSpecFile(data []byte, fp string) error {
// if file already exists then dont apply any written on it
if utils.PathExists(fp) {
return fmt.Errorf("file %s already exists, rename to avoid overwriting", fp)
}

if err := os.MkdirAll(filepath.Dir(fp), os.ModeDir|os.ModePerm); err != nil {
return err
}

WriteConfig(data, fp)
return nil
}

// BuildFromDB builds a BuildSpec from the DB located at path
func BuildFromDB(path string) (*BuildSpec, error) {
tmpGen := &genesis.Genesis{
Expand Down
79 changes: 79 additions & 0 deletions dot/build_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package dot

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

Expand All @@ -29,6 +31,17 @@ func TestBuildFromGenesis(t *testing.T) {
defer os.Remove(file)
require.NoError(t, err)
bs, err := BuildFromGenesis(file, 0)

expectedChainType := "TESTCHAINTYPE"
expectedProperties := map[string]interface{}{
"ss58Format": 0.0,
"tokenDecimals": 0.0,
"tokenSymbol": "TEST",
}

bs.genesis.ChainType = expectedChainType
bs.genesis.Properties = expectedProperties

require.NoError(t, err)

// confirm human-readable fields
Expand All @@ -39,6 +52,8 @@ func TestBuildFromGenesis(t *testing.T) {
require.NoError(t, err)
genesis.TestGenesis.Genesis = genesis.TestFieldsHR
require.Equal(t, genesis.TestGenesis.Genesis.Runtime, jGen.Genesis.Runtime)
require.Equal(t, expectedChainType, jGen.ChainType)
require.Equal(t, expectedProperties, jGen.Properties)

// confirm raw fields
raw, err := bs.ToJSONRaw()
Expand All @@ -48,6 +63,70 @@ func TestBuildFromGenesis(t *testing.T) {
require.NoError(t, err)
genesis.TestGenesis.Genesis = genesis.TestFieldsRaw
require.Equal(t, genesis.TestGenesis.Genesis.Raw, jGenRaw.Genesis.Raw)
require.Equal(t, expectedChainType, jGenRaw.ChainType)
require.Equal(t, expectedProperties, jGenRaw.Properties)
}

func TestBuildFromGenesis_WhenGenesisDoesNotExists(t *testing.T) {
bs, err := BuildFromGenesis("/not/exists/genesis.json", 0)
require.Nil(t, bs)
require.Error(t, err, os.ErrNotExist)
}

func TestWriteGenesisSpecFileWhenFileAlreadyExists(t *testing.T) {
f, err := ioutil.TempFile("", "existing file data")
require.NoError(t, err)
defer os.Remove(f.Name())

someBytes := []byte("Testing some bytes")
err = WriteGenesisSpecFile(someBytes, f.Name())

require.Error(t, err,
fmt.Sprintf("file %s already exists, rename to avoid overwritten", f.Name()))
}

func TestWriteGenesisSpecFile(t *testing.T) {
cfg := NewTestConfig(t)
cfg.Init.Genesis = "../chain/gssmr/genesis.json"

expected, err := genesis.NewGenesisFromJSONRaw(cfg.Init.Genesis)
require.NoError(t, err)

err = InitNode(cfg)
require.NoError(t, err)

bs, err := BuildFromGenesis(cfg.Init.Genesis, 0)
require.NoError(t, err)

data, err := bs.ToJSONRaw()
require.NoError(t, err)

tmpFiles := []string{
"/tmp/unique-raw-genesis.json",
"./unique-raw-genesis.json",
}

for _, tmpFile := range tmpFiles {
err = WriteGenesisSpecFile(data, tmpFile)
require.NoError(t, err)
require.FileExists(t, tmpFile)

defer os.Remove(tmpFile)

file, err := os.Open(tmpFile)
require.NoError(t, err)
defer file.Close()

genesisBytes, err := ioutil.ReadAll(file)
require.NoError(t, err)

gen := new(genesis.Genesis)
err = json.Unmarshal(genesisBytes, gen)
require.NoError(t, err)

require.Equal(t, expected.ChainType, gen.ChainType)
require.Equal(t, expected.Properties, gen.Properties)
}
}

func TestBuildFromDB(t *testing.T) {
Expand Down

0 comments on commit b18290c

Please sign in to comment.