From dbf4e40e13956f3f20b1e89571143c13d17a6e61 Mon Sep 17 00:00:00 2001 From: swdee Date: Thu, 19 Mar 2020 10:54:28 +1300 Subject: [PATCH 1/7] ignore GoLand IDE project metafiles directory --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index b2daa0e..f2b8820 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ awscpu # Output of the go coverage tool, specifically when used with LiteIDE *.out +# ignore GoLand metafiles directory +.idea/ + *logs/ .vscode* From 7c821abfaf967de91e221dbfa0cbd26371d5c596 Mon Sep 17 00:00:00 2001 From: swdee Date: Sun, 22 Mar 2020 12:25:47 +1300 Subject: [PATCH 2/7] changed gecko command line arguments to use flagset so we can control the exit code --- main/params.go | 79 +++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/main/params.go b/main/params.go index 88a3722..b8961c3 100644 --- a/main/params.go +++ b/main/params.go @@ -8,6 +8,7 @@ import ( "flag" "fmt" "net" + "os" "path" "strings" @@ -44,64 +45,76 @@ func init() { loggingConfig, err := logging.DefaultConfig() errs.Add(err) + fs := flag.NewFlagSet("gecko", flag.ContinueOnError) + // NetworkID: - networkName := flag.String("network-id", genesis.LocalName, "Network ID this node will connect to") + networkName := fs.String("network-id", genesis.LocalName, "Network ID this node will connect to") // Ava fees: - flag.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva") + fs.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva") // Assertions: - flag.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution") + fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution") // Crypto: - flag.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification") + fs.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification") // Database: - db := flag.Bool("db-enabled", true, "Turn on persistent storage") - dbDir := flag.String("db-dir", "db", "Database directory for Ava state") + db := fs.Bool("db-enabled", true, "Turn on persistent storage") + dbDir := fs.String("db-dir", "db", "Database directory for Ava state") // IP: - consensusIP := flag.String("public-ip", "", "Public IP of this node") + consensusIP := fs.String("public-ip", "", "Public IP of this node") // HTTP Server: - httpPort := flag.Uint("http-port", 9650, "Port of the HTTP server") - flag.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs") - flag.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server") - flag.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server") + httpPort := fs.Uint("http-port", 9650, "Port of the HTTP server") + fs.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs") + fs.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server") + fs.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server") // Bootstrapping: - bootstrapIPs := flag.String("bootstrap-ips", "", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631") - bootstrapIDs := flag.String("bootstrap-ids", "", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z") + bootstrapIPs := fs.String("bootstrap-ips", "", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631") + bootstrapIDs := fs.String("bootstrap-ids", "", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z") // Staking: - consensusPort := flag.Uint("staking-port", 9651, "Port of the consensus server") - flag.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections") - flag.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", "", "TLS private key file for staking connections") - flag.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", "", "TLS certificate file for staking connections") + consensusPort := fs.Uint("staking-port", 9651, "Port of the consensus server") + fs.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections") + fs.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", "", "TLS private key file for staking connections") + fs.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", "", "TLS certificate file for staking connections") // Logging: - logsDir := flag.String("log-dir", "", "Logging directory for Ava") - logLevel := flag.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}") - logDisplayLevel := flag.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}") + logsDir := fs.String("log-dir", "", "Logging directory for Ava") + logLevel := fs.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}") + logDisplayLevel := fs.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}") - flag.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 20, "Number of nodes to query for each network poll") - flag.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 18, "Alpha value to use for required number positive results") - flag.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions") - flag.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions") - flag.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex") - flag.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex") + fs.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 20, "Number of nodes to query for each network poll") + fs.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 18, "Alpha value to use for required number positive results") + fs.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions") + fs.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions") + fs.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex") + fs.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex") // Enable/Disable APIs: - flag.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API") - flag.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API") - flag.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API") - flag.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened") + fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API") + fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API") + fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API") + fs.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened") // Throughput Server - throughputPort := flag.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server") - flag.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created") + throughputPort := fs.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server") + fs.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created") - flag.Parse() + ferr := fs.Parse(os.Args[1:]) + + if ferr == flag.ErrHelp { + // display usage/help text and exit successfully + os.Exit(0) + } + + if ferr != nil { + // other type of error occurred when parsing args + os.Exit(2) + } networkID, err := genesis.NetworkID(*networkName) errs.Add(err) From a0900b79034c5f447ce811aa31ba6d1e1eb234bc Mon Sep 17 00:00:00 2001 From: swdee Date: Sun, 22 Mar 2020 12:31:10 +1300 Subject: [PATCH 3/7] changed xputtest command line arguments to use flagset so we can control the exit code --- xputtest/params.go | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/xputtest/params.go b/xputtest/params.go index f3017dc..006ef75 100644 --- a/xputtest/params.go +++ b/xputtest/params.go @@ -6,6 +6,7 @@ package main import ( "flag" "fmt" + "os" stdnet "net" @@ -28,35 +29,47 @@ func init() { loggingConfig, err := logging.DefaultConfig() errs.Add(err) + fs := flag.NewFlagSet("xputtest", flag.ContinueOnError) + // NetworkID: - networkName := flag.String("network-id", genesis.LocalName, "Network ID this node will connect to") + networkName := fs.String("network-id", genesis.LocalName, "Network ID this node will connect to") // Ava fees: - flag.Uint64Var(&config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva") + fs.Uint64Var(&config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva") // Assertions: - flag.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution") + fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution") // Crypto: - flag.BoolVar(&config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification") + fs.BoolVar(&config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification") // Remote Server: - ip := flag.String("ip", "127.0.0.1", "IP address of the remote server socket") - port := flag.Uint("port", 9652, "Port of the remote server socket") + ip := fs.String("ip", "127.0.0.1", "IP address of the remote server socket") + port := fs.Uint("port", 9652, "Port of the remote server socket") // Logging: - logsDir := flag.String("log-dir", "", "Logging directory for Ava") - logLevel := flag.String("log-level", "info", "The log level. Should be one of {all, debug, info, warn, error, fatal, off}") + logsDir := fs.String("log-dir", "", "Logging directory for Ava") + logLevel := fs.String("log-level", "info", "The log level. Should be one of {all, debug, info, warn, error, fatal, off}") // Test Variables: - spchain := flag.Bool("sp-chain", false, "Execute simple payment chain transactions") - spdag := flag.Bool("sp-dag", false, "Execute simple payment dag transactions") - avm := flag.Bool("avm", false, "Execute avm transactions") - flag.IntVar(&config.Key, "key", 0, "Index of the genesis key list to use") - flag.IntVar(&config.NumTxs, "num-txs", 25000, "Total number of transaction to issue") - flag.IntVar(&config.MaxOutstandingTxs, "max-outstanding", 1000, "Maximum number of transactions to leave outstanding") + spchain := fs.Bool("sp-chain", false, "Execute simple payment chain transactions") + spdag := fs.Bool("sp-dag", false, "Execute simple payment dag transactions") + avm := fs.Bool("avm", false, "Execute avm transactions") + fs.IntVar(&config.Key, "key", 0, "Index of the genesis key list to use") + fs.IntVar(&config.NumTxs, "num-txs", 25000, "Total number of transaction to issue") + fs.IntVar(&config.MaxOutstandingTxs, "max-outstanding", 1000, "Maximum number of transactions to leave outstanding") - flag.Parse() + ferr := fs.Parse(os.Args[1:]) + + if ferr == flag.ErrHelp { + // display usage/help text and exit successfully + os.Exit(0) + } + + if ferr != nil { + // other type of error occurred when parsing args + os.Exit(2) + } networkID, err := genesis.NetworkID(*networkName) errs.Add(err) From 611ada56553e7bf27613ece251517921519d6c9a Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Tue, 24 Mar 2020 19:08:53 -0400 Subject: [PATCH 4/7] Fixed early termination of bootstrap fetching --- snow/engine/avalanche/bootstrapper.go | 13 ++++-- snow/engine/avalanche/bootstrapper_test.go | 50 +++++++++++++++++++++ snow/engine/snowman/bootstrapper.go | 13 ++++-- snow/engine/snowman/bootstrapper_test.go | 51 ++++++++++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) diff --git a/snow/engine/avalanche/bootstrapper.go b/snow/engine/avalanche/bootstrapper.go index 7d3d7c8..0f58194 100644 --- a/snow/engine/avalanche/bootstrapper.go +++ b/snow/engine/avalanche/bootstrapper.go @@ -119,7 +119,7 @@ func (b *bootstrapper) fetch(vtxID ids.ID) { b.sendRequest(vtxID) return } - b.addVertex(vtx) + b.storeVertex(vtx) } func (b *bootstrapper) sendRequest(vtxID ids.ID) { @@ -138,6 +138,14 @@ func (b *bootstrapper) sendRequest(vtxID ids.ID) { } func (b *bootstrapper) addVertex(vtx avalanche.Vertex) { + b.storeVertex(vtx) + + if numPending := b.pending.Len(); numPending == 0 { + b.finish() + } +} + +func (b *bootstrapper) storeVertex(vtx avalanche.Vertex) { vts := []avalanche.Vertex{vtx} for len(vts) > 0 { @@ -181,9 +189,6 @@ func (b *bootstrapper) addVertex(vtx avalanche.Vertex) { numPending := b.pending.Len() b.numPendingRequests.Set(float64(numPending)) - if numPending == 0 { - b.finish() - } } func (b *bootstrapper) finish() { diff --git a/snow/engine/avalanche/bootstrapper_test.go b/snow/engine/avalanche/bootstrapper_test.go index d1be936..bcfd3dc 100644 --- a/snow/engine/avalanche/bootstrapper_test.go +++ b/snow/engine/avalanche/bootstrapper_test.go @@ -957,3 +957,53 @@ func TestBootstrapperFilterAccepted(t *testing.T) { t.Fatalf("Vtx shouldn't be accepted") } } + +func TestBootstrapperPartialFetch(t *testing.T) { + config, _, sender, state, _ := newConfig(t) + + vtxID0 := ids.Empty.Prefix(0) + vtxID1 := ids.Empty.Prefix(1) + + vtxBytes0 := []byte{0} + + vtx0 := &Vtx{ + id: vtxID0, + height: 0, + status: choices.Processing, + bytes: vtxBytes0, + } + + bs := bootstrapper{} + bs.metrics.Initialize(config.Context.Log, fmt.Sprintf("gecko_%s", config.Context.ChainID), prometheus.NewRegistry()) + bs.Initialize(config) + + acceptedIDs := ids.Set{} + acceptedIDs.Add( + vtxID0, + vtxID1, + ) + + state.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) { + switch { + case vtxID.Equals(vtxID0): + return vtx0, nil + case vtxID.Equals(vtxID1): + return nil, errUnknownVertex + default: + t.Fatal(errUnknownVertex) + panic(errUnknownVertex) + } + } + + sender.CantGet = false + + bs.ForceAccepted(acceptedIDs) + + if bs.finished { + t.Fatalf("should have requested a vertex") + } + + if bs.pending.Len() != 1 { + t.Fatalf("wrong number pending") + } +} diff --git a/snow/engine/snowman/bootstrapper.go b/snow/engine/snowman/bootstrapper.go index 88724ed..46ced68 100644 --- a/snow/engine/snowman/bootstrapper.go +++ b/snow/engine/snowman/bootstrapper.go @@ -113,7 +113,7 @@ func (b *bootstrapper) fetch(blkID ids.ID) { b.sendRequest(blkID) return } - b.addBlock(blk) + b.storeBlock(blk) } func (b *bootstrapper) sendRequest(blkID ids.ID) { @@ -132,6 +132,14 @@ func (b *bootstrapper) sendRequest(blkID ids.ID) { } func (b *bootstrapper) addBlock(blk snowman.Block) { + b.storeBlock(blk) + + if numPending := b.pending.Len(); numPending == 0 { + b.finish() + } +} + +func (b *bootstrapper) storeBlock(blk snowman.Block) { status := blk.Status() blkID := blk.ID() for status == choices.Processing { @@ -161,9 +169,6 @@ func (b *bootstrapper) addBlock(blk snowman.Block) { numPending := b.pending.Len() b.numPendingRequests.Set(float64(numPending)) - if numPending == 0 { - b.finish() - } } func (b *bootstrapper) finish() { diff --git a/snow/engine/snowman/bootstrapper_test.go b/snow/engine/snowman/bootstrapper_test.go index 9cb0968..1b56d0d 100644 --- a/snow/engine/snowman/bootstrapper_test.go +++ b/snow/engine/snowman/bootstrapper_test.go @@ -425,3 +425,54 @@ func TestBootstrapperFilterAccepted(t *testing.T) { t.Fatalf("Blk shouldn't be accepted") } } + +func TestBootstrapperPartialFetch(t *testing.T) { + config, _, sender, vm := newConfig(t) + + blkID0 := ids.Empty.Prefix(0) + blkID1 := ids.Empty.Prefix(1) + + blkBytes0 := []byte{0} + + blk0 := &Blk{ + id: blkID0, + height: 0, + status: choices.Accepted, + bytes: blkBytes0, + } + + bs := bootstrapper{} + bs.metrics.Initialize(config.Context.Log, fmt.Sprintf("gecko_%s", config.Context.ChainID), prometheus.NewRegistry()) + bs.Initialize(config) + + acceptedIDs := ids.Set{} + acceptedIDs.Add( + blkID0, + blkID1, + ) + + vm.GetBlockF = func(blkID ids.ID) (snowman.Block, error) { + switch { + case blkID.Equals(blkID0): + return blk0, nil + case blkID.Equals(blkID1): + return nil, errUnknownBlock + default: + t.Fatal(errUnknownBlock) + panic(errUnknownBlock) + } + } + + sender.CantGet = false + bs.onFinished = func() {} + + bs.ForceAccepted(acceptedIDs) + + if bs.finished { + t.Fatalf("should have requested a block") + } + + if bs.pending.Len() != 1 { + t.Fatalf("wrong number pending") + } +} From a308beea3388f2cb3683b2e518d27ad9d8a3b127 Mon Sep 17 00:00:00 2001 From: StephenButtolph Date: Wed, 25 Mar 2020 10:46:49 -0400 Subject: [PATCH 5/7] Fixed off by one error in bootstrapping Alpha value --- chains/manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chains/manager.go b/chains/manager.go index efb4372..bacc9b6 100644 --- a/chains/manager.go +++ b/chains/manager.go @@ -382,7 +382,7 @@ func (m *manager) createAvalancheChain( Context: ctx, Validators: validators, Beacons: beacons, - Alpha: (beacons.Len() + 1) / 2, + Alpha: beacons.Len()/2 + 1, // must be > 50% Sender: &sender, }, VtxBlocked: vtxBlocker, @@ -462,7 +462,7 @@ func (m *manager) createSnowmanChain( Context: ctx, Validators: validators, Beacons: beacons, - Alpha: (beacons.Len() + 1) / 2, + Alpha: beacons.Len()/2 + 1, // must be > 50% Sender: &sender, }, Blocked: blocked, From c1abff8c3d9ba6e4d44ae0cb657dfec5ff6c5112 Mon Sep 17 00:00:00 2001 From: Dan Laine Date: Thu, 26 Mar 2020 15:14:45 -0400 Subject: [PATCH 6/7] fix bug where unmarshalling into improper type causes panic. Add test for this --- vms/components/codec/codec.go | 5 ++++ vms/components/codec/codec_test.go | 39 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/vms/components/codec/codec.go b/vms/components/codec/codec.go index a80d9bc..efbc5a0 100644 --- a/vms/components/codec/codec.go +++ b/vms/components/codec/codec.go @@ -324,6 +324,11 @@ func (c codec) unmarshal(p *wrappers.Packer, field reflect.Value) error { if !ok { return errUnmarshalUnregisteredType } + // Ensure struct actually does implement the interface + fieldType := field.Type() + if !typ.Implements(fieldType) { + return fmt.Errorf("%s does not implement interface %s", typ, fieldType) + } concreteInstancePtr := reflect.New(typ) // instance of the proper type // Unmarshal into the struct if err := c.unmarshal(p, concreteInstancePtr.Elem()); err != nil { diff --git a/vms/components/codec/codec_test.go b/vms/components/codec/codec_test.go index 6fc4f25..336837f 100644 --- a/vms/components/codec/codec_test.go +++ b/vms/components/codec/codec_test.go @@ -538,3 +538,42 @@ func TestTooLargeUnmarshal(t *testing.T) { t.Fatalf("Should have errored due to too many bytes provided") } } + +type outerInterface interface { + ToInt() int +} + +type outer struct { + Interface outerInterface `serialize:"true"` +} + +type innerInterface struct{} + +func (it *innerInterface) ToInt() int { + return 0 +} + +type innerNoInterface struct{} + +// Ensure deserializing structs into the wrong interface errors gracefully +func TestUnmarshalInvalidInterface(t *testing.T) { + codec := NewDefault() + + codec.RegisterType(&innerInterface{}) + codec.RegisterType(&innerNoInterface{}) + + { + bytes := []byte{0, 0, 0, 0} + s := outer{} + if err := codec.Unmarshal(bytes, &s); err != nil { + t.Fatal(err) + } + } + { + bytes := []byte{0, 0, 0, 1} + s := outer{} + if err := codec.Unmarshal(bytes, &s); err == nil { + t.Fatalf("should have errored") + } + } +} From 976db1ec91020f973666a1d817e7a49fb6bce197 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 26 Mar 2020 16:02:30 -0700 Subject: [PATCH 7/7] Fixing docker container example command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c860d1a..c48ba93 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The Gecko binary, named `ava`, is in the `build` directory. - Build the docker image of latest gecko branch by `scripts/build_image.sh`. - Check the built image by `docker image ls`, you should see some image tagged `gecko-xxxxxxxx`, where `xxxxxxxx` is the commit id of the Gecko source it was built from. -- Test Gecko by `docker run -ti -p 9651:9651 gecko-xxxxxxxx /gecko/build/ava +- Test Gecko by `docker run -ti -p 9650:9650 -p 9651:9651 gecko-xxxxxxxx /gecko/build/ava --public-ip=127.0.0.1 --snow-sample-size=1 --snow-quorum-size=1 --staking-tls-enabled=false`. (For a production deployment, you may want to extend the docker image with required credentials for staking and TLS.)