diff --git a/.gitignore b/.gitignore index 496ee2c..f14c809 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -.DS_Store \ No newline at end of file +.DS_Store + +vendor/ +build/ \ No newline at end of file diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..3c7d028 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,190 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" + name = "github.com/fsnotify/fsnotify" + packages = ["."] + pruneopts = "UT" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token", + ] + pruneopts = "UT" + revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241" + version = "v1.0.0" + +[[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + pruneopts = "UT" + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e" + version = "v1.0.2" + +[[projects]] + digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7" + name = "github.com/magiconair/properties" + packages = ["."] + pruneopts = "UT" + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" + +[[projects]] + digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + pruneopts = "UT" + revision = "af06845cf3004701891bf4fdb884bfe4920b3727" + version = "v1.1.0" + +[[projects]] + digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + pruneopts = "UT" + revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe" + version = "v1.1.2" + +[[projects]] + digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e" + name = "github.com/pelletier/go-toml" + packages = ["."] + pruneopts = "UT" + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + digest = "1:e4c72127d910a96daf869a44f3dd563b86dbe6931a172863a0e99c5ff04b59e4" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "dae0fa8d5b0c810a8ab733fbd5510c7cae84eca4" + version = "v1.4.0" + +[[projects]] + digest = "1:bb495ec276ab82d3dd08504bbc0594a65de8c3b22c6f2aaa92d05b73fbf3a82e" + name = "github.com/spf13/afero" + packages = [ + ".", + "mem", + ] + pruneopts = "UT" + revision = "588a75ec4f32903aa5e39a2619ba6a4631e28424" + version = "v1.2.2" + +[[projects]] + digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc" + name = "github.com/spf13/cast" + packages = ["."] + pruneopts = "UT" + revision = "8c9545af88b134710ab1cd196795e7f2388358d7" + version = "v1.3.0" + +[[projects]] + digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939" + name = "github.com/spf13/cobra" + packages = ["."] + pruneopts = "UT" + revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" + version = "v0.0.3" + +[[projects]] + digest = "1:1b753ec16506f5864d26a28b43703c58831255059644351bbcb019b843950900" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + pruneopts = "UT" + revision = "94f6ae3ed3bceceafa716478c5fbf8d29ca601a1" + version = "v1.1.0" + +[[projects]] + digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "UT" + revision = "298182f68c66c05229eb03ac171abe6e309ee79a" + version = "v1.0.3" + +[[projects]] + digest = "1:1b773526998f3dbde3a51a4a5881680c4d237d3600f570d900f97ac93c7ba0a8" + name = "github.com/spf13/viper" + packages = ["."] + pruneopts = "UT" + revision = "9e56dacc08fbbf8c9ee2dbc717553c758ce42bc9" + version = "v1.3.2" + +[[projects]] + branch = "master" + digest = "1:bbe51412d9915d64ffaa96b51d409e070665efc5194fcf145c4a27d4133107a4" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "a5d413f7728c81fb97d96a2b722368945f651e78" + +[[projects]] + branch = "master" + digest = "1:6b3e6ddcebac95be1d690dbd53b5aa2e520715becb7e521bb526ccf3b4c53c15" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "f49334f85ddcf0f08d7fb6dd7363e9e6d6b777eb" + +[[projects]] + digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295" + name = "golang.org/x/text" + packages = [ + "internal/gen", + "internal/triegen", + "internal/ucd", + "transform", + "unicode/cldr", + "unicode/norm", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "UT" + revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" + version = "v2.2.2" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/mitchellh/go-homedir", + "github.com/sirupsen/logrus", + "github.com/spf13/cobra", + "github.com/spf13/viper", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..d7072c2 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,30 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[prune] + go-tests = true + unused-packages = true diff --git a/README.md b/README.md index 04ee3f3..3add30c 100644 --- a/README.md +++ b/README.md @@ -15,53 +15,65 @@ A dockerized environment hosting a bitcoin and liquid daemons in regtest network ## Directions -| Preparation Time: 20 min | Cooking Difficulty: Easy | +| Preparation Time: 5 min | Cooking Difficulty: Easy | | --- | --- | Clone the repo: ```bash -$ git clone https://github.com/vulpemventures/nigiri.git && cd nigiri +$ git clone https://github.com/vulpemventures/nigiri.git ``` -Create and start nigiri (only the first time or after cleaning): +Enter project directory and install dependencies: ```bash -$ bash scripts/create +nigiri $ bash scripts/install +``` + +Build binary (Mac version): +``` +nigiri $ bash scripts/build darwin amd64 ``` At the moment bitcoind, liquidd and electrs are started on *regtest* network. -Start nigiri: +Initialize nigiri: ```bash -$ bash scripts/start +nigiri/build $ nigiri-linux-amd64 init ``` -This will start 4 containers that run the following services respectevely: +Initialize nigiri configuation file at at path `~/.nigiri/nigiri.config.json`. -* bitcoin daemon (regtest) -* liquid daemon +Create and run nigiri environment: + +```bash +nigiri/build $ nigiri-linux-amd64 create +``` + +This will start 3 containers for `regtest` bitcoin network that run the following services respectevely: + +* bitcoin daemon * electrs REST server * API passthrough with optional faucet and mining capabilities (nigiri-chopsticks) -Stop nigiri: +After command has finished, nigiri start listening at `http://localhost:3000/`. + +Start/Stop nigiri: ```bash -$ bash scripts/stop +nigiri/build $ nigiri-linux-amd64 start|stop ``` -Stop and uninstall nigiri: +Stop and delete nigiri environment: ```bash -$ bash scripts/clean +nigiri/build $ nigiri-linux-amd64 delete ``` -When setup is completed, you can call any endpoint at `http://localhost:3000/`. - ## Nutrition Facts -The [list](https://github.com/blockstream/esplora/blob/master/API.md) of all available endpoints has been extended with one more `POST /send` which expects a body `{ "address": }` +The [list](https://github.com/blockstream/esplora/blob/master/API.md) of all available endpoints can be extended with one more `POST /faucet` which expects a body `{ "address": }` by enabling faucet. ## Footnotes diff --git a/cli/builder/main.go b/cli/builder/main.go new file mode 100644 index 0000000..5ec3c72 --- /dev/null +++ b/cli/builder/main.go @@ -0,0 +1,7 @@ +package builder + +type ComposeBuilder interface { + New(rootPath string) + Build() error + Delete() error +} diff --git a/cli/cmd/create.go b/cli/cmd/create.go new file mode 100644 index 0000000..c46e76b --- /dev/null +++ b/cli/cmd/create.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "os" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/vulpemventures/nigiri/cli/builder" + "github.com/vulpemventures/nigiri/cli/config" + "github.com/vulpemventures/nigiri/cli/helpers" +) + +var composeBuilder = map[string]func(path string) builder.ComposeBuilder{ + "regtest": helpers.NewRegtestBuilder, +} + +var CreateCmd = &cobra.Command{ + Use: "create", + Short: "Build and run the entire Docker environment", + Run: create, + PreRun: createChecks, +} + +func createChecks(cmd *cobra.Command, args []string) { + if err := config.ReadFromFile(); err != nil { + log.Fatal(err) + } + + if composeExists() { + log.Fatal("Docker environment already exists, please delete it first") + } +} + +func create(cmd *cobra.Command, args []string) { + viper := config.Viper() + network := viper.GetString("network") + composePath := getComposePath() + + composer := composeBuilder[network](composePath) + if err := composer.Build(); err != nil { + log.WithError(err).Fatal("Error while composing Docker environment:") + } +} + +func composeExists() bool { + _, err := os.Stat(getComposePath()) + return !os.IsNotExist(err) +} diff --git a/cli/cmd/delete.go b/cli/cmd/delete.go new file mode 100644 index 0000000..5cc1f70 --- /dev/null +++ b/cli/cmd/delete.go @@ -0,0 +1,35 @@ +package cmd + +import ( + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/vulpemventures/nigiri/cli/config" +) + +var DeleteCmd = &cobra.Command{ + Use: "delete", + Short: "Delete all Docker environment components", + Run: delete, + PreRun: deleteChecks, +} + +func delete(cmd *cobra.Command, args []string) { + viper := config.Viper() + network := viper.GetString("network") + composePath := getComposePath() + + composer := composeBuilder[network](composePath) + if err := composer.Delete(); err != nil { + log.WithError(err).Fatal("Error while deleting Docker environment:") + } +} + +func deleteChecks(cmd *cobra.Command, args []string) { + if err := config.ReadFromFile(); err != nil { + log.Fatal(err) + } + + if !composeExists() { + log.Fatal("Docker environment does not exist") + } +} diff --git a/cli/cmd/flags.go b/cli/cmd/flags.go new file mode 100644 index 0000000..e7654d6 --- /dev/null +++ b/cli/cmd/flags.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "os" + "path/filepath" + + "github.com/mitchellh/go-homedir" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/vulpemventures/nigiri/cli/config" +) + +var ( + flagNetwork string + flagDatadir string + flagConfig string +) + +var RootCmd = &cobra.Command{ + Use: "nigiri", + Short: "Nigiri lets you manage a full dockerized bitcoin environment", + Long: "A dockerized environment with a bitcoin and liquid node + block explorer powered by an electrum server", +} + +func init() { + home, _ := homedir.Expand("~") + defaultDir := filepath.Join(home, ".nigiri") + + RootCmd.PersistentFlags().StringVar(&flagNetwork, "network", "regtest", "Set bitcoin network for containers' services - regtest only for now") + InitCmd.PersistentFlags().StringVar(&flagDatadir, "datadir", defaultDir, "Set directory for docker containers") + + RootCmd.AddCommand(InitCmd) + RootCmd.AddCommand(CreateCmd) + RootCmd.AddCommand(StartCmd) + RootCmd.AddCommand(StopCmd) + RootCmd.AddCommand(DeleteCmd) + + viper := config.Viper() + viper.BindPFlag(config.Network, RootCmd.PersistentFlags().Lookup("network")) + viper.BindPFlag(config.Datadir, InitCmd.PersistentFlags().Lookup("datadir")) + + cobra.OnInitialize(func() { + log.SetOutput(os.Stdout) + log.SetLevel(log.InfoLevel) + }) +} diff --git a/cli/cmd/init.go b/cli/cmd/init.go new file mode 100644 index 0000000..f88c6c4 --- /dev/null +++ b/cli/cmd/init.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/vulpemventures/nigiri/cli/config" +) + +var InitCmd = &cobra.Command{ + Use: "init", + Short: "Initialize configuration file", + Run: run, + PreRun: runChecks, +} + +func run(cmd *cobra.Command, args []string) { + viper := config.Viper() + + if err := viper.WriteConfig(); err != nil { + log.WithError(err).Fatal("An error occured while writing config file") + } +} + +func runChecks(cmd *cobra.Command, args []string) { + network := cmd.Flags().Lookup("network").Value.String() + + // check valid network + if !isNetworkOk(network) { + log.WithField("network_flag", network).Fatal("Invalid network") + } + + // scratch ~/.nigiri/ if not exists + if err := os.MkdirAll(config.GetPath(), 0755); err != nil { + log.WithError(err).Fatal("An error occured while scratching config dir") + } + + // check if config file already exists + if _, err := os.Stat(config.GetFullPath()); !os.IsNotExist(err) { + log.Fatal("File already exists, please delete it first") + } +} + +func isNetworkOk(network string) bool { + var ok bool + for _, n := range []string{"regtest"} { + if network == n { + ok = true + } + } + + return ok +} + +func fileExists(path string) bool { + _, err := os.Stat(filepath.Join(path, config.Filename)) + return !os.IsNotExist(err) +} diff --git a/cli/cmd/start.go b/cli/cmd/start.go new file mode 100644 index 0000000..2f62067 --- /dev/null +++ b/cli/cmd/start.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/vulpemventures/nigiri/cli/config" +) + +var StartCmd = &cobra.Command{ + Use: "start", + Short: "Start containers", + Run: start, + PreRun: startStopChecks, +} + +func start(cmd *cobra.Command, args []string) { + composePath := filepath.Join(getComposePath(), "docker-compose.yml") + cmdStart := exec.Command("docker-compose", "-f", composePath, "start") + cmdStart.Stdout = os.Stdout + cmdStart.Stderr = os.Stderr + + if err := cmdStart.Run(); err != nil { + log.WithError(err).Fatal("Error while starting Docker containers:") + } +} + +func startStopChecks(cmd *cobra.Command, args []string) { + if err := config.ReadFromFile(); err != nil { + log.Fatal(err) + } + + if !composeExists() { + log.Fatal("Docker environment does not exist") + } +} + +func getComposePath() string { + viper := config.Viper() + datadir := viper.GetString("datadir") + network := viper.GetString("network") + + return filepath.Join(datadir, fmt.Sprintf("resources-%s", network)) +} diff --git a/cli/cmd/stop.go b/cli/cmd/stop.go new file mode 100644 index 0000000..c7a16e6 --- /dev/null +++ b/cli/cmd/stop.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "os" + "os/exec" + "path/filepath" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var StopCmd = &cobra.Command{ + Use: "stop", + Short: "Stop containers", + Run: stop, + PreRun: startStopChecks, +} + +func stop(cmd *cobra.Command, args []string) { + composePath := filepath.Join(getComposePath(), "docker-compose.yml") + cmdStart := exec.Command("docker-compose", "-f", composePath, "stop") + cmdStart.Stdout = os.Stdout + cmdStart.Stderr = os.Stderr + + if err := cmdStart.Run(); err != nil { + log.WithError(err).Fatal("Error while stopping Docker containers:") + } +} diff --git a/cli/config/main.go b/cli/config/main.go new file mode 100644 index 0000000..d592897 --- /dev/null +++ b/cli/config/main.go @@ -0,0 +1,59 @@ +package config + +import ( + "path/filepath" + + "github.com/mitchellh/go-homedir" + "github.com/spf13/viper" +) + +const ( + Datadir = "datadir" + Network = "network" + Filename = "nigiri.config.json" +) + +var vip *viper.Viper + +func init() { + vip = viper.New() + vip.SetEnvPrefix("NIGIRI") + vip.AutomaticEnv() + vip.BindEnv("config") + + defaults := viper.New() + newDefaultConfig(defaults) + setConfigFromDefaults(vip, defaults) + vip.SetConfigFile(GetFullPath()) +} + +func Viper() *viper.Viper { + return vip +} + +func ReadFromFile() error { + vip.AddConfigPath(GetFullPath()) + return vip.ReadInConfig() +} + +func GetPath() string { + home, _ := homedir.Expand("~") + return filepath.Join(home, ".nigiri") +} + +func GetFullPath() string { + home, _ := homedir.Expand("~") + return filepath.Join(home, ".nigiri", Filename) +} + +func newDefaultConfig(v *viper.Viper) { + v.SetDefault("datadir", GetPath()) + v.SetDefault("network", "regtest") + v.SetDefault("version", "0.1.0") +} + +func setConfigFromDefaults(v *viper.Viper, d *viper.Viper) { + for key, value := range d.AllSettings() { + v.SetDefault(key, value) + } +} diff --git a/cli/helpers/regtestbuilder.go b/cli/helpers/regtestbuilder.go new file mode 100644 index 0000000..ce993d8 --- /dev/null +++ b/cli/helpers/regtestbuilder.go @@ -0,0 +1,246 @@ +package helpers + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/vulpemventures/nigiri/cli/builder" +) + +func NewRegtestBuilder(rootPath string) builder.ComposeBuilder { + rb := ®testbuilder{} + rb.New(rootPath) + + return rb +} + +type regtestbuilder struct { + path string +} + +func (rb *regtestbuilder) New(rootPath string) { + rb.path = rootPath +} + +func (rb *regtestbuilder) Build() error { + if err := buildComposeFile(rb.path); err != nil { + return err + } + + if err := buildBitcoinContainer(filepath.Join(rb.path, "bitcoin")); err != nil { + return err + } + + if err := buildElectrsContainer(filepath.Join(rb.path, "electrs")); err != nil { + return err + } + + return runCompose(rb.path) +} + +func (rb *regtestbuilder) Delete() error { + return deleteAll(rb.path) +} + +func runCompose(path string) error { + composePath := filepath.Join(path, "docker-compose.yml") + cmd := exec.Command("docker-compose", "-f", composePath, "up", "-d") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func buildComposeFile(path string) error { + if err := os.MkdirAll(path, os.ModePerm); err != nil { + return err + } + + r := strings.NewReplacer("\t", " ") + if err := ioutil.WriteFile(filepath.Join(path, "docker-compose.yml"), []byte(r.Replace(composeFile)), os.ModePerm); err != nil { + return err + } + + return nil +} + +func buildBitcoinContainer(path string) error { + configPath := filepath.Join(path, "config") + if err := os.MkdirAll(configPath, os.ModePerm); err != nil { + return err + } + + if err := ioutil.WriteFile(filepath.Join(path, "run"), []byte(btcRunFile), 0755); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(path, "Dockerfile"), []byte(btcDockerFile), 0644); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(configPath, "bitcoin.conf"), []byte(btcConfigFile), 0644); err != nil { + return err + } + + return nil +} + +func buildElectrsContainer(path string) error { + if err := os.MkdirAll(path, os.ModePerm); err != nil { + return err + } + + if err := ioutil.WriteFile(filepath.Join(path, "run"), []byte(electrsRunFile), 0755); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(path, "Dockerfile"), []byte(electrsDockerFile), 0644); err != nil { + return err + } + + return nil +} + +func deleteAll(path string) error { + _, basename := filepath.Split(path) + composePath := filepath.Join(path, "docker-compose.yml") + volume := fmt.Sprintf("%s_bitcoin-config", basename) + images := []string{ + fmt.Sprintf("%s_bitcoin", basename), + fmt.Sprintf("%s_electrs", basename), + } + + cmdCompose := fmt.Sprintf("docker-compose -f %s down", composePath) + cmdVolume := fmt.Sprintf("docker volume rm %s", volume) + cmdImage := fmt.Sprintf("docker rmi %s", strings.Join(images, " ")) + cmdDelete := fmt.Sprintf("rm -rf %s", path) + + cmd := exec.Command( + "/bin/sh", "-c", + fmt.Sprintf("%s; %s; %s; %s", cmdCompose, cmdVolume, cmdImage, cmdDelete), + ) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + return cmd.Run() +} + +const composeFile = `version: '3' +services: + bitcoin: + build: + context: bitcoin/ + dockerfile: Dockerfile + networks: + local: + ipv4_address: 10.10.0.10 + volumes: + - bitcoin-config:/config + electrs: + build: + context: electrs/ + dockerfile: Dockerfile + networks: + local: + ipv4_address: 10.10.0.12 + volumes: + - bitcoin-config:/config + # chopsticks: + # build: + # context: chopsticks/ + # dockerfile: Dockerfile + # ports: + # - 3000:3000 + # networks: + # local: + # ipv4_address: 10.10.0.13 + +networks: + local: + driver: bridge + ipam: + config: + - subnet: 10.10.0.0/24 + +volumes: + bitcoin-config:` + +const btcDockerFile = `FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install --yes clang cmake jq software-properties-common && \ + add-apt-repository --yes ppa:bitcoin/bitcoin && \ + apt-get update && \ + apt-get install --yes bitcoind + +RUN mkdir -p /config /script + +ADD config /config +ADD run /script + +WORKDIR /script + +EXPOSE 19001 +STOPSIGNAL SIGINT + +CMD ["./run"]` + +const btcRunFile = `#!/bin/bash +set -ex + +b1="bitcoin-cli -datadir=/config" + +function clean { + $b1 stop +} + +trap clean SIGINT + +bitcoind -datadir=/config & + +sleep 10 + +$b1 generate 200 +wait $!` + +const btcConfigFile = `regtest=1 +testnet=0 +dnsseed=0 +upnp=0 + +[regtest] +port=19000 +rpcport=19001 + +server=1 +txindex=0 + +rpcuser=admin1 +rpcpassword=123 +rpcallowip=0.0.0.0/0` + +const electrsDockerFile = `FROM ubuntu:18.04 + +RUN apt-get update && apt-get install --yes wget + +WORKDIR /build +RUN wget -qO- https://github.com/vulpemventures/electrs/releases/download/v0.4.1-bin/electrs.tar.gz | tar -xvz && rm -rf electrs.tar.gz + +WORKDIR /scripts +ADD run /scripts + +EXPOSE 3002 +STOPSIGNAL SIGINT + +CMD ["./run"]` + +const electrsRunFile = `#!/bin/bash +set -e + +function clean { + kill -9 $(pidof electrs) +} +trap clean SIGINT + +/build/electrs -vvvv --network regtest --daemon-dir /config --daemon-rpc-addr="10.10.0.10:19001" --cookie="admin1:123" --http-addr="0.0.0.0:3002" & +wait $!` diff --git a/cli/main.go b/cli/main.go new file mode 100644 index 0000000..3f83d44 --- /dev/null +++ b/cli/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/vulpemventures/nigiri/cli/cmd" + +func main() { + cmd.RootCmd.Execute() +} diff --git a/scripts/build b/scripts/build new file mode 100644 index 0000000..fdcf096 --- /dev/null +++ b/scripts/build @@ -0,0 +1,9 @@ +#!/bin/bash +set -ex + +PARENT_PATH=$(dirname $(cd $(dirname $0); pwd -P)) + +pushd $PARENT_PATH +mkdir -p build +GOOS=$1 GOARCH=$2 go build -o build/nigiri-$1-$2 ./cli +popd \ No newline at end of file diff --git a/scripts/install b/scripts/install new file mode 100644 index 0000000..73efed8 --- /dev/null +++ b/scripts/install @@ -0,0 +1,10 @@ +#!/bin/bash +set -ex + +PARENT_PATH=$(dirname $(cd $(dirname $0); pwd -P)) + +pushd $PARENT_PATH +dep ensure -v + +go generate ./... +popd \ No newline at end of file