Skip to content

Commit

Permalink
Merge pull request #31 from evanlinjin/feature/new-startup-behavior
Browse files Browse the repository at this point in the history
New startup behavior.
  • Loading branch information
evanlinjin authored Mar 9, 2021
2 parents 90447b3 + 603c7ca commit 8071a1c
Show file tree
Hide file tree
Showing 17 changed files with 898 additions and 166 deletions.
22 changes: 17 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Added


### Fixed

### Changed

### Removed

## [0.76.0] - 2021-03-09

### Added

* Added functionality to locate cx spec via a local file or `cx-tracker` based on a command line flag (https://github.com/skycoin/cx-chains/pull/31/commits/8b3369d981f6b5b6cc7a8007484c1a947c264ba7).
* Added force client node flag for `cxchain` (https://github.com/skycoin/cx-chains/pull/31/commits/0806031ddc3fd9fb4eebb432ee1cf6bcfd096dfa).
* Implemented `cxchain-cli post` subcommand (https://github.com/skycoin/cx-chains/pull/31/commits/cd615f99680b6a692eab914d729aa309ddce9810).
* Implemented `cxchain-cli key` subcommand (https://github.com/skycoin/cx-chains/pull/31/commits/3025f6be7db135a3cf526af51c7901528912eb5f, https://github.com/skycoin/cx-chains/pull/31/commits/ebe2d204516b45ac875c234dff694639e98ebb32)
* Implemented `cxchain-cli genesis` subcommand (https://github.com/skycoin/cx-chains/pull/31/commits/ebe2d204516b45ac875c234dff694639e98ebb32).
* Initial work on integration tests (https://github.com/skycoin/cx-chains/pull/31/commits/8b533cb1e6de6bf47047d4f6f2f216cf21fcc9ea, https://github.com/skycoin/cx-chains/pull/31/commits/4dbb0cac096630c9025c0ca1ebc125980624b4ab).

### Fixed

### Changed

Complete refactor. Preparing for CX Version 1.0 milestone
* General commandline interface changes for `cxchain` and `cxchain-cli` (https://github.com/skycoin/cx-chains/pull/31/commits/13761d78ea86499d8f3005cc114eca985c68cc1c).

### Removed


## [0.75.0] - 2020-12-01

### Added
Expand All @@ -27,8 +41,6 @@ Preparing for Version 1.0 milestone. Complete refactor. Massive code changes.

### Fixed


### Changed


### Removed
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,36 +35,50 @@ You will need to specify an address of a `cx-tracker` for a `cxchain` instance t

*This local environment has two `cxchain` instances and a `cx-tracker`.*

Start `cx-tracker` with default setting.
Start `cx-tracker`.
```bash
$ cx-tracker
$ cx-tracker -addr ":9091"
```

Generate new chain spec (assuming that the repository root is your working directory).
```bash
$ cxchain-cli new ./cx/examples/counter-bc.cx
```

Post chain spec to `cx-tracker`.
```bash
$ export CXCHAIN_SK=$(cxchain-cli key -in skycoin.chain_keys.json -field "seckey")
$ cxchain-cli post -t "http://127.0.0.1:9091" -s skycoin.chain_spec.json
```

At this point, you can head to [http://127.0.0.1:9091/api/specs](http://127.0.0.1:9091/api/specs) to see whether the spec is posted to `cx-tracker`.

Run publisher node with generated chain spec.
* Obtain the chain secret key from generated `{coin}.chain_keys.json` file.
```bash
$ CXCHAIN_SK=publisher_secret_key cxchain -enable-all-api-sets
$ export CXCHAIN_SK=$(cxchain-cli key -in skycoin.chain_keys.json -field "seckey")
$ export CXCHAIN_HASH=$(cxchain-cli genesis -in skycoin.chain_spec.json)
$ cxchain -chain "tracker:$CXCHAIN_HASH" -tracker "http://127.0.0.1:9091" -enable-all-api-sets -data-dir ./master_node -port 6001 -web-interface-port 6421
```

Run client node with generated chain spec (use different data dir, and ports to publisher node).
* As no `CXCHAIN_SK` is provided, a random key pair is generated for the node.
```bash
$ cxchain -enable-all-api-sets -data-dir "$HOME/.cxchain/skycoin_client" -port 6002 -web-interface-port 6422
$ export CXCHAIN_HASH=$(cxchain-cli genesis -in skycoin.chain_spec.json)
$ cxchain -chain "tracker:$CXCHAIN_HASH" -tracker "http://127.0.0.1:9091" -client -enable-all-api-sets -data-dir ./client_node -port 6002 -web-interface-port 6422
```

Run transaction against publisher node.
```bash
$ cxchain-cli run ./cx/examples/counter-tx.cx
$ export CXCHAIN_HASH=$(cxchain-cli genesis -in skycoin.chain_spec.json)
$ cxchain-cli run -chain "tracker:$CXCHAIN_HASH" -tracker "http://127.0.0.1:9091" ./cx/examples/counter-tx.cx
```

Run transaction against client node and inject.
```bash
$ CXCHAIN_GEN_SK=genesis_secret_key cxchain-cli run -n "http://127.0.0.1:6422" -i ./cx/examples/counter-tx.cx
$ export CXCHAIN_GEN_SK=$(cxchain-cli key -in skycoin.genesis_keys.json -field "seckey")
$ export CXCHAIN_HASH=$(cxchain-cli genesis -in skycoin.chain_spec.json)
$ cxchain-cli run -chain "tracker:$CXCHAIN_HASH" -tracker "http://127.0.0.1:9091" -node "http://127.0.0.1:6422" -inject ./cx/examples/counter-tx.cx
```

## Resources
Expand Down
69 changes: 69 additions & 0 deletions cmd/cxchain-cli/cmd_genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"os"

"github.com/skycoin/cx-chains/src/cx/cxspec"
"github.com/skycoin/cx-chains/src/cx/cxutil"
)

type genesisFlags struct {
cmd *flag.FlagSet

in string
}

func processGenesisFlags(args []string) genesisFlags {
// Specify default flag values.
f := genesisFlags{
cmd: flag.NewFlagSet("cxchain-cli genesis", flag.ExitOnError),
in: "skycoin.chain_spec.json",
}

f.cmd.Usage = func() {
usage := cxutil.DefaultUsageFormat("flags")
usage(f.cmd, nil)
}

f.cmd.StringVar(&f.in, "in", f.in, "`FILENAME` of file to read in")

if err := f.cmd.Parse(args); err != nil {
os.Exit(1)
}

return f
}

func cmdGenesis(args []string) {
flags := processGenesisFlags(args)

f, err := os.Open(flags.in)
if err != nil {
log.WithError(err).
Fatal("Failed to read in file.")
}
defer func() {
if err := f.Close(); err != nil {
log.WithError(err).
Fatal("Failed to close file.")
}
}()

var cSpec cxspec.ChainSpec
if err := json.NewDecoder(f).Decode(&cSpec); err != nil {
log.WithError(err).
Fatal("Failed to decode file")
}

block, err := cSpec.GenerateGenesisBlock()
if err != nil {
log.WithError(err).
Fatal("Failed to generate genesis block.")
}

hash := block.HashHeader()
fmt.Println(hash.Hex())
}
83 changes: 83 additions & 0 deletions cmd/cxchain-cli/cmd_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"os"

"github.com/skycoin/cx-chains/src/cx/cxspec"
"github.com/skycoin/cx-chains/src/cx/cxutil"
)

type keyFlags struct {
cmd *flag.FlagSet

in string
field string
}

func processKeyFlags(args []string) keyFlags {
// Specify default flag values.
f := keyFlags{
cmd: flag.NewFlagSet("cxchain-cli key", flag.ExitOnError),
in: "skycoin.chain_keys.json", // TODO @evanlinjin: Find const for this value.
field: "seckey",
}

f.cmd.Usage = func() {
usage := cxutil.DefaultUsageFormat("flags")
usage(f.cmd, nil)
}

f.cmd.StringVar(&f.in, "in", f.in, "`FILENAME` of file to read in")
f.cmd.StringVar(&f.field, "field", f.field, "`NAME` of field to print")

if err := f.cmd.Parse(args); err != nil {
os.Exit(1)
}

return f
}

func cmdKey(args []string) {
flags := processKeyFlags(args)

f, err := os.Open(flags.in)
if err != nil {
log.WithError(err).
Fatal("Failed to read in file.")
}
defer func() {
if err := f.Close(); err != nil {
log.WithError(err).
Fatal("Failed to close file.")
}
}()

var kSpec cxspec.KeySpec
if err := json.NewDecoder(f).Decode(&kSpec); err != nil {
log.WithError(err).
Fatal("Failed to decode file.")
}

var out string

switch flags.field {
case "spec_era":
out = kSpec.SpecEra
case "key_type":
out = kSpec.KeyType
case "pubkey":
out = kSpec.PubKey
case "seckey":
out = kSpec.SecKey
case "address":
out = kSpec.Address
default:
log.WithField("field", flags.field).
Fatal("Invalid field input.")
}

fmt.Println(out)
}
8 changes: 2 additions & 6 deletions cmd/cxchain-cli/cmd_peers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"encoding/json"
"flag"
"fmt"
Expand All @@ -13,14 +14,9 @@ import (
)

func cmdPeers(args []string) {
// spec is the chain spec obtained from ENV
if err := globals.specErr; err != nil {
log.WithError(err).Fatal()
}
spec := globals.spec

// rootCmd is the root command of the 'peers' subcommand
rootCmd := flag.NewFlagSet("cxchain-cli peers", flag.ExitOnError)
spec := processSpecFlags(context.Background(), rootCmd, args)

// nodeAddr holds the value parsed from the flags 'node' and 'n'
nodeAddr := fmt.Sprintf("http://127.0.0.1:%d", spec.Node.WebInterfacePort)
Expand Down
102 changes: 102 additions & 0 deletions cmd/cxchain-cli/cmd_post.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package main

import (
"context"
"flag"
"github.com/skycoin/cx-chains/src/cx/cxspec"
"github.com/skycoin/cx-chains/src/cx/cxutil"
"github.com/skycoin/skycoin/src/cipher"
"os"
)

type postFlags struct {
cmd *flag.FlagSet

specInput string // chain spec input filename
signedOutput string // signed chain spec output filename
dryRun bool // if set, spec file will not be posted to cx-tracker
tracker string // cx tracker URL
}

func processPostFlags(args []string) (postFlags, cipher.SecKey) {
// Specify default flag values.
f := postFlags{
cmd: flag.NewFlagSet("cxchain-cli post", flag.ExitOnError),

specInput: cxspec.DefaultSpecFilepath,
signedOutput: "", // empty for no output
dryRun: false,
tracker: cxspec.DefaultTrackerURL,
}

f.cmd.Usage = func() {
usage := cxutil.DefaultUsageFormat("flags")
usage(f.cmd, nil)
printChainSKENV(f.cmd)
}

f.cmd.StringVar(&f.specInput, "spec", f.specInput, "`FILENAME` of chain spec file input")
f.cmd.StringVar(&f.specInput, "s", f.specInput, "shorthand for 'spec'")

f.cmd.StringVar(&f.signedOutput, "output", f.signedOutput, "`FILENAME` for signed chain spec output (empty for no output)")
f.cmd.StringVar(&f.signedOutput, "o", f.signedOutput, "shorthand for 'output'")

f.cmd.BoolVar(&f.dryRun, "dry", f.dryRun, "whether to do a dry run (no actual post to cx-tracker)")

f.cmd.StringVar(&f.tracker, "tracker", f.tracker, "`URL` for cx-tracker")
f.cmd.StringVar(&f.tracker, "t", f.tracker, "shorthand for 'tracker'")

// Parse flags.
if err := f.cmd.Parse(args); err != nil {
os.Exit(1)
}

// Parse ENVs.
genSK, err := parseSKEnv(chainSKEnv)
if err != nil {
log.WithError(err).
WithField(chainSKEnv, genSK.Hex()).
Fatal("Failed to read secret key from ENV.")
}

return f, genSK
}

func cmdPost(args []string) {
flags, genSK := processPostFlags(args)

// Obtain chain spec.
spec, err := cxspec.ReadSpecFile(flags.specInput)
if err != nil {
log.WithError(err).
Fatal("Failed to read spec file.")
}

// Sign chain spec.
signed, err := cxspec.MakeSignedChainSpec(spec, genSK)
if err != nil {
log.WithError(err).
Fatal("Failed to make signed chain spec.")
}

if flags.signedOutput != "" {
// TODO @evanlinjin: Write signed output.
panic("flag 'output,o' is not implemented yet")
}

// tracker client.
tC := cxspec.NewCXTrackerClient(log, nil, flags.tracker)

if !flags.dryRun {
if err := tC.PostSpec(context.Background(), signed); err != nil {
log.WithError(err).Fatal("Failed to post spec to cx-tracker.")
}
} else {
log.WithField("dry_run", flags.dryRun).
Info("This is a dry run.")
}

log.WithField("spec_file", flags.specInput).
WithField("cx_tracker", flags.tracker).
Info("Chain spec file successfully posted!")
}
Loading

0 comments on commit 8071a1c

Please sign in to comment.