diff --git a/cmd/netrunner/main.go b/cmd/netrunner/main.go index 3b385903..0d70b57c 100644 --- a/cmd/netrunner/main.go +++ b/cmd/netrunner/main.go @@ -13,6 +13,7 @@ import ( "github.com/luxfi/log" "github.com/luxfi/log/level" "github.com/luxfi/netrunner/cmd/netrunner/commands" + "github.com/luxfi/netrunner/cmd/server" "github.com/spf13/cobra" ) @@ -38,6 +39,7 @@ OP Stack, and more.`, // Add subcommands rootCmd.AddCommand( + server.NewCommand(), commands.NewEngineCmd(logger), commands.NewStackCmd(logger), commands.NewStatusCmd(logger), diff --git a/go.mod b/go.mod index 0d8028c2..99fc07c8 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/dgraph-io/badger/v4 v4.9.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 github.com/luxfi/config v1.0.0 - github.com/luxfi/consensus v1.22.46 + github.com/luxfi/consensus v1.22.47 github.com/luxfi/const v1.4.0 - github.com/luxfi/crypto v1.17.27 - github.com/luxfi/genesis v1.5.17 - github.com/luxfi/geth v1.16.66 + github.com/luxfi/crypto v1.17.32 + github.com/luxfi/genesis v1.5.18 + github.com/luxfi/geth v1.16.67 github.com/luxfi/go-bip39 v1.1.2 - github.com/luxfi/ids v1.2.5 + github.com/luxfi/ids v1.2.6 github.com/luxfi/keys v1.0.5 github.com/luxfi/log v1.2.1 github.com/luxfi/math v1.2.0 @@ -34,7 +34,6 @@ require ( github.com/stretchr/testify v1.11.1 go.uber.org/multierr v1.11.0 golang.org/x/crypto v0.46.0 - golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 golang.org/x/mod v0.31.0 golang.org/x/sync v0.19.0 google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a @@ -47,14 +46,14 @@ require ( github.com/DataDog/zstd v1.5.7 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251221085550-b8e13ca38217 // indirect + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251230134950-44c893854e3f // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cloudflare/circl v1.6.2-0.20251204010831-23491bd573cf // indirect + github.com/cloudflare/circl v1.6.2 // indirect github.com/cockroachdb/errors v1.12.0 // indirect github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect @@ -67,12 +66,12 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect + github.com/dgraph-io/ristretto/v2 v2.3.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/getsentry/sentry-go v0.35.1 // indirect + github.com/getsentry/sentry-go v0.40.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -82,9 +81,9 @@ require ( github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/flatbuffers v25.2.10+incompatible // indirect + github.com/google/flatbuffers v25.12.19+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect + github.com/google/pprof v0.0.0-20251213031049-b05bdaca462f // indirect github.com/google/renameio/v2 v2.0.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect @@ -93,16 +92,16 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/luxfi/address v1.0.0 // indirect github.com/luxfi/cache v1.1.0 // indirect - github.com/luxfi/database v1.2.17 // indirect + github.com/luxfi/database v1.2.18 // indirect github.com/luxfi/go-bip32 v1.0.2 // indirect github.com/luxfi/keychain v1.0.1 // indirect github.com/luxfi/mock v0.1.0 // indirect - github.com/luxfi/p2p v1.18.2 // indirect + github.com/luxfi/p2p v1.18.3 // indirect github.com/luxfi/sampler v1.0.0 // indirect github.com/luxfi/staking v1.0.0 // indirect github.com/luxfi/trace v0.1.4 // indirect @@ -132,23 +131,24 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect - github.com/tklauser/go-sysconf v0.3.15 // indirect - github.com/tklauser/numcpus v0.10.0 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect golang.org/x/net v0.48.0 // indirect golang.org/x/sys v0.39.0 // indirect golang.org/x/text v0.32.0 // indirect diff --git a/go.sum b/go.sum index 8167251f..3e7afda5 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251221085550-b8e13ca38217 h1:RNTau6sw5B3ltE+2GlzEom63eBMzoLUc+dhjmdIwNpI= -github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251221085550-b8e13ca38217/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251230134950-44c893854e3f h1:a5PUgHGinaD6XrLmIDLQmGHocjIjBsBAcR5gALjZvMU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251230134950-44c893854e3f/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/VictoriaMetrics/fastcache v1.13.2 h1:2XTB49aLSuCex7e9P5rqrfQcMkzGjh5Vq3GMFa8YpCA= github.com/VictoriaMetrics/fastcache v1.13.2/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -51,8 +51,12 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/circl v1.6.2-0.20251204010831-23491bd573cf h1:+0huF756d72ZdHxachRP5HYmvRkkOk8CLyKUmJM138c= -github.com/cloudflare/circl v1.6.2-0.20251204010831-23491bd573cf/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= +github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= +github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= +github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ= +github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo= @@ -95,14 +99,14 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjY github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgraph-io/badger/v4 v4.9.0 h1:tpqWb0NewSrCYqTvywbcXOhQdWcqephkVkbBmaaqHzc= github.com/dgraph-io/badger/v4 v4.9.0/go.mod h1:5/MEx97uzdPUHR4KtkNt8asfI2T4JiEiQlV7kWUo8c0= -github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= -github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +github.com/dgraph-io/ristretto/v2 v2.3.0 h1:qTQ38m7oIyd4GAed/QkUZyPFNMnvVWyazGXRwvOt5zk= +github.com/dgraph-io/ristretto/v2 v2.3.0/go.mod h1:gpoRV3VzrEY1a9dWAYV6T1U7YzfgttXdd/ZzL1s9OZM= github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/dot v1.9.0 h1:FyaJNctdMfaEIbTQ1FkKZ1UCZyJJSkyvkrXOVoNZPKU= -github.com/emicklei/dot v1.9.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/emicklei/dot v1.10.0 h1:z17n0ce/FBMz3QbShSzVGhiW447Qhu7fljzvp3Gs6ig= +github.com/emicklei/dot v1.10.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= @@ -120,8 +124,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gballet/go-libpcsclite v0.0.0-20250918194357-1ec6f2e601c6 h1:ko+DlyhLqUHpgrvwqs5ybydoGAqjpJQTXpAS7vUqVlM= github.com/gballet/go-libpcsclite v0.0.0-20250918194357-1ec6f2e601c6/go.mod h1:3IVE7v4II2gS2V5amIH7F7NeYQtbbORtQtjdflgS1vk= -github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ= -github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= +github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= +github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -161,8 +165,8 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= -github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs= +github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -172,8 +176,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= -github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= +github.com/google/pprof v0.0.0-20251213031049-b05bdaca462f h1:HU1RgM6NALf/KW9HEY6zry3ADbDKcmpQ+hJedoNGQYQ= +github.com/google/pprof v0.0.0-20251213031049-b05bdaca462f/go.mod h1:67FPmZWbr+KDT/VlpWtw6sO9XSjpJmLuHpoLmWiTGgY= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -185,8 +189,8 @@ github.com/gorilla/rpc v1.2.1/go.mod h1:uNpOihAlF5xRFLuTYhfR0yfCTm0WTQSQttkMSptR github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= -github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/graph-gophers/graphql-go v1.8.0 h1:NT05/H+PdH1/PONExlUycnhULYHBy98dxV63WYc0Ng8= +github.com/graph-gophers/graphql-go v1.8.0/go.mod h1:23olKZ7duEvHlF/2ELEoSZaY1aNPfShjP782SOoNTyM= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= @@ -209,8 +213,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.14.0 h1:AjbBfJuq+QoaXNcrova8smSjw github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= +github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -219,8 +223,8 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -237,24 +241,24 @@ github.com/luxfi/cache v1.1.0 h1:6LUyGGZ+rrMAJBbAU6+UwkcamXj3zsboRUodIof2Ong= github.com/luxfi/cache v1.1.0/go.mod h1:9GvlEEE9rFPaaWxvVpSPwW8ZMo2+8VMNNcuPa4AwzPg= github.com/luxfi/config v1.0.0 h1:EFIFkdus3YdDklhlwHKJNYLpSVuvWqHm+fs/TGckv5U= github.com/luxfi/config v1.0.0/go.mod h1:71q4A4m7vj+o1qnL1dNk/tVII+Ugiwvi9+jVMN2xxTU= -github.com/luxfi/consensus v1.22.46 h1:w97OZjtW/anWvgM0N/q8Y70LEJlqlFG6yeS10rKcnx4= -github.com/luxfi/consensus v1.22.46/go.mod h1:cbvtxHH5pab/XJIlHekg66tYaIChTwTt9SNMMgz8+as= +github.com/luxfi/consensus v1.22.47 h1:iMVimbKap4T7sCNWs3Pb2yq1LVD9d9/sXmWHMiyCSDQ= +github.com/luxfi/consensus v1.22.47/go.mod h1:LWAJvhE36LP8OrR3dPjjdc50vTTL4R2nbrvB+CDvb0w= github.com/luxfi/const v1.4.0 h1:8bHt5I8g76TkeuFIY478aYtfcLgbdkGNo/e/Sy3+6p0= github.com/luxfi/const v1.4.0/go.mod h1:qWfecjdImPY3kXsy3UAe4ZVpMcsp2/iUlHwUMPVREoI= -github.com/luxfi/crypto v1.17.27 h1:gFTvoQ7SJDsaBVQfQJBpDG8yVx6J61JdW+G0JFCUK3c= -github.com/luxfi/crypto v1.17.27/go.mod h1:v6eaW5ejuzW2gecChWKQqx4CtVhoM1b+e40ro/6WVPg= -github.com/luxfi/database v1.2.17 h1:1PE0FlAarorfAMl+vAvO6EDbkS+a4ktL7kvtRk58DWY= -github.com/luxfi/database v1.2.17/go.mod h1:IzvNHGFZWdRs5CL5vswqz8/uu8t796cMGlbqPWs032s= -github.com/luxfi/genesis v1.5.17 h1:GDv9m8OXBXFOq9714v1PfISPhPpoyozGUpvMT+ysjqY= -github.com/luxfi/genesis v1.5.17/go.mod h1:iDMXsNS0ZCnBY7T385Nw6ERobnq+DE5bfuVJds/TuGQ= -github.com/luxfi/geth v1.16.66 h1:XS5hMbYZtxCm/G6vjWBA7vRTpajX1FSJvAfkpL8cbN4= -github.com/luxfi/geth v1.16.66/go.mod h1:fmimbIf5oLldwc3FzEYaP8Jrf8tBhvDFi0Y/b26Tajk= +github.com/luxfi/crypto v1.17.32 h1:qEKDETNMeU7T82UMEEGYh0bbJ0ZZdx0sAMRwFXt69aQ= +github.com/luxfi/crypto v1.17.32/go.mod h1:laZTnEq0BD/fnPhd5ke/79WgFhV3TZjmfPxk+b8zbrE= +github.com/luxfi/database v1.2.18 h1:yppRuZf3FKnr3v4o+UHNfSW+cXtUIUibtyki0+EqiIs= +github.com/luxfi/database v1.2.18/go.mod h1:dYxaF30KGJQzuxA3VH7+WGU5/dhwRyzLgzSk9F3wje0= +github.com/luxfi/genesis v1.5.18 h1:DDNFDyYT+AtSX78XBV1nGeuvR4404XPAkXnnrlJSV78= +github.com/luxfi/genesis v1.5.18/go.mod h1:888i1w8e67HIpgLuveIdd+3ESWCXHgnz7cijF6dDAKI= +github.com/luxfi/geth v1.16.67 h1:ILPG59XNnNKIz1YNO1fJFV+doZXBjcQkb4oXQyz1HUM= +github.com/luxfi/geth v1.16.67/go.mod h1:QWPyY3vlGQfm8SX/PE6q4XHTBe7X4Gw+SGDJi5QU1pg= github.com/luxfi/go-bip32 v1.0.2 h1:7vFbb+Wr4Z499q2tuCLdd7wWjtn8sH+HWBlx76mhH9Y= github.com/luxfi/go-bip32 v1.0.2/go.mod h1:bc7/LXDKAJQZ/F0Xjf5yXaTZxY9/ssLb4FC+Hxn/cDk= github.com/luxfi/go-bip39 v1.1.2 h1:p+wLMPGs6MLQh7q0YIsmy2EhHL7LHiELEGTJko6t/Jg= github.com/luxfi/go-bip39 v1.1.2/go.mod h1:96de9VkR2kY/ASAnhMtvt3TSh+PZkAFAngNj0GjRGDo= -github.com/luxfi/ids v1.2.5 h1:w4YSj3S6LQiUXhiChUmcbrMCRMfkCaBFIGn0Eo4ZSxk= -github.com/luxfi/ids v1.2.5/go.mod h1:vZBjJWSmqMIZuodgnoszvTDvXIwsbnhM2pkktg6FGrg= +github.com/luxfi/ids v1.2.6 h1:Ru86pltAcWPhCT7FH/MwwuAYXkeZbt9ZwfuR883c8MI= +github.com/luxfi/ids v1.2.6/go.mod h1:svLsj7e6ixJVfRYaQqv9RWjBIW11Vz738+d08BVpeCg= github.com/luxfi/keychain v1.0.1 h1:8tTzPnZSi0M6UtKRBCypnGFrLNry9BvWfS5ol33yDF0= github.com/luxfi/keychain v1.0.1/go.mod h1:X7HLk5QRZ1VHJxovAyBL6z7f/nlosoXlveEtvUGhoaw= github.com/luxfi/keys v1.0.5 h1:ZzE2wHDxSiIcufkYlp7twmTKGB0mczjE67uM3uAP2Ag= @@ -269,10 +273,10 @@ github.com/luxfi/mock v0.1.0 h1:IwElfNu+T9sXvzFX6tudPDx1vqPuACRSRdxpD5lxW+o= github.com/luxfi/mock v0.1.0/go.mod h1:izF+9K0gGzFC9zERn6Po37v46eLdPB+EIsDjL3GLk+U= github.com/luxfi/node v1.22.75 h1:kOs6bbwP23scRTDN1YTjglcVQgncpaZqmeZIV/Cheqc= github.com/luxfi/node v1.22.75/go.mod h1:97xyVTMBFq/LmbrQ0VMA6DNNWBYSu+3jQG1ztBBEuHc= -github.com/luxfi/p2p v1.18.2 h1:elpyXr58wht1KP64D4BcKXft1AEjJ3IRACj/W8vdLI8= -github.com/luxfi/p2p v1.18.2/go.mod h1:eM6XpmBFbDjaI7fFuGYBPab77TS1esxHxAOluBLAC0Y= -github.com/luxfi/precompiles v0.1.10 h1:M90JTzW+je/uaCBSE2BvoONamBTbuUDskh4fxua6oUE= -github.com/luxfi/precompiles v0.1.10/go.mod h1:s4054PbUgIZ/CezXT3BSNGbUqimgzK7LABP0wMhNG/Y= +github.com/luxfi/p2p v1.18.3 h1:RUxZdRyQq5YLvaLUb6v86sv5ElFLR16Pq0jen9RAKho= +github.com/luxfi/p2p v1.18.3/go.mod h1:9jmpwJqTTrrz3VF+7vgIAjcixB7CvvRcT5p2o4vz3m0= +github.com/luxfi/precompile v0.4.0 h1:xvaiUi9rf11Hqn4J9mlsw+KsXWkZmZxByc0GGHn2k+o= +github.com/luxfi/precompile v0.4.0/go.mod h1:ZSc4SN4X5S6ASj8VQYVtrlzKQwGFcw9Utq3IFQ1Ua/I= github.com/luxfi/sampler v1.0.0 h1:k8Sf6otW83w4pQp0jXLA+g3J/joB7w7SqXQsWmNTOV0= github.com/luxfi/sampler v1.0.0/go.mod h1:f96/ozlj9vFfZj+akLtrHn4VpulQahwB+MQQhpeIekk= github.com/luxfi/staking v1.0.0 h1:pYI7XMGGb/zK2ATfTIkush/7HPWE7IS2yfmJqj4nzes= @@ -291,8 +295,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -306,8 +310,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo= -github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A= +github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= +github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -326,8 +330,6 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8= github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I= github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= @@ -340,14 +342,14 @@ github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOP github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= -github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= -github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/transport/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM= +github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ= github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0= github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -366,8 +368,6 @@ github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+L github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= @@ -418,39 +418,39 @@ github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5f github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/thepudds/fzgen v0.4.3 h1:srUP/34BulQaEwPP/uHZkdjUcUjIzL7Jkf4CBVryiP8= github.com/thepudds/fzgen v0.4.3/go.mod h1:BhhwtRhzgvLWAjjcHDJ9pEiLD2Z9hrVIFjBCHJ//zJ4= -github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= -github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= -github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= diff --git a/local/blockchain.go b/local/blockchain.go index 42d0a3af..6a227059 100644 --- a/local/blockchain.go +++ b/local/blockchain.go @@ -69,11 +69,15 @@ const ( // check period while waiting for all validators to be ready // Reduced from 1s to 200ms for faster validator detection waitForValidatorsPullFrequency = 200 * time.Millisecond - defaultTimeout = 10 * time.Minute // Increased for mainnet staking validators - stakingMinimumLeadTime = 25 * time.Second + // FAIL FAST: Reduced from 10 minutes to 30 seconds for local deployments + // Most P-chain API calls should complete in <5s on localhost + defaultTimeout = 30 * time.Second + stakingMinimumLeadTime = 25 * time.Second minStakeDuration = 24 * 14 * time.Hour - // dedicated timeout for waiting on chain validators to become active - chainValidatorWaitTimeout = 2 * time.Minute + // FAIL FAST: Reduced from 45s to 30s for local deployments + // For local networks, validators activate quickly (5-10s). If it takes longer, + // something is wrong - fail fast with clear error rather than waiting forever. + chainValidatorWaitTimeout = 30 * time.Second ) var ( @@ -197,8 +201,9 @@ func (ln *localNetwork) RegisterAliases( return fmt.Errorf("admin client is nil for node %v", nodeName) } // Retry with exponential backoff - nodes may not have discovered chain yet - maxRetries := 10 - baseDelay := 500 * time.Millisecond + // FAIL FAST: Reduced retries from 10 to 5, max delay from 5s to 2s + maxRetries := 5 + baseDelay := 300 * time.Millisecond var lastErr error for attempt := 0; attempt < maxRetries; attempt++ { if err := (*adminClient).AliasChain(ctx, chainID, blockchainAlias); err != nil { @@ -214,8 +219,8 @@ func (ln *localNetwork) RegisterAliases( } lastErr = err delay := baseDelay * time.Duration(1< 5*time.Second { - delay = 5 * time.Second + if delay > 2*time.Second { + delay = 2 * time.Second // FAIL FAST: reduced max delay } ln.logger.Debug("alias registration failed, retrying", "node", nodeName, @@ -253,11 +258,17 @@ func (ln *localNetwork) waitForChainsDiscoveredOnAllNodes( fmt.Println() ln.logger.Info(log.Blue.Wrap(log.Bold.Wrap("waiting for chains to be discovered on all nodes..."))) - // Use a longer timeout for chain discovery - VMs may need time to initialize - // Especially for first-time deployments where VMs need to be loaded - maxWait := 120 * time.Second // Extended timeout for VM initialization - pollInterval := 500 * time.Millisecond // Poll frequently + // FAIL FAST: Respect the context deadline, don't use hardcoded timeout + // For local networks, chain discovery should complete in <30s + // The context already has a timeout from the caller + maxWait := 30 * time.Second // Max wait for local chain discovery + pollInterval := 500 * time.Millisecond + + // Use the earlier of: context deadline or our maxWait deadline := time.Now().Add(maxWait) + if ctxDeadline, ok := ctx.Deadline(); ok && ctxDeadline.Before(deadline) { + deadline = ctxDeadline + } for _, chainInfo := range chainInfos { blockchainID := chainInfo.blockchainID.String() @@ -392,9 +403,15 @@ func (ln *localNetwork) waitForBlockchainOnPChain( fmt.Println() ln.logger.Info(log.Blue.Wrap(log.Bold.Wrap("waiting for P-Chain to sync blockchain across all nodes..."))) - maxWait := 60 * time.Second + // FAIL FAST: Respect context deadline, don't use hardcoded 60s + maxWait := 30 * time.Second // P-chain sync should be fast on localhost pollInterval := 500 * time.Millisecond + + // Use the earlier of: context deadline or our maxWait deadline := time.Now().Add(maxWait) + if ctxDeadline, ok := ctx.Deadline(); ok && ctxDeadline.Before(deadline) { + deadline = ctxDeadline + } for _, blockchainID := range blockchainIDs { ln.logger.Info("waiting for blockchain on P-Chain", @@ -490,6 +507,7 @@ func (ln *localNetwork) waitForPeerConnectivity(ctx context.Context) error { connected := false attemptCount := 0 + peerLoop: for time.Now().Before(deadline) { attemptCount++ infoClient := node.GetAPIClient().InfoAPI() @@ -500,7 +518,11 @@ func (ln *localNetwork) waitForPeerConnectivity(ctx context.Context) error { "attempts", attemptCount, ) } - time.Sleep(pollInterval) + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled while waiting for peers on node %s: %w", nodeName, ctx.Err()) + case <-time.After(pollInterval): + } continue } @@ -513,7 +535,11 @@ func (ln *localNetwork) waitForPeerConnectivity(ctx context.Context) error { "attempts", attemptCount, ) } - time.Sleep(pollInterval) + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled while waiting for peers on node %s: %w", nodeName, ctx.Err()) + case <-time.After(pollInterval): + } continue } @@ -524,7 +550,7 @@ func (ln *localNetwork) waitForPeerConnectivity(ctx context.Context) error { "numPeers", len(peers), "attempts", attemptCount, ) - break + break peerLoop } if attemptCount%10 == 0 { @@ -535,7 +561,11 @@ func (ln *localNetwork) waitForPeerConnectivity(ctx context.Context) error { "attempts", attemptCount, ) } - time.Sleep(pollInterval) + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled while waiting for peers on node %s: %w", nodeName, ctx.Err()) + case <-time.After(pollInterval): + } } if !connected { @@ -608,7 +638,11 @@ func (ln *localNetwork) waitForPChainHeightSync(ctx context.Context) error { return nil } - time.Sleep(pollInterval) + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled while waiting for P-Chain sync: %w", ctx.Err()) + case <-time.After(pollInterval): + } } // Log final state for debugging @@ -827,9 +861,9 @@ func (ln *localNetwork) installCustomChains( // Wait for subnet creation transactions to be fully committed before adding validators // The P-Chain needs time to commit the subnet creation blocks and propagate state to all nodes - // Increased from 5s to 15s to ensure state synchronization across all validators + // For local networks, this should be very fast (1-2s). For public networks, may need longer. ln.logger.Info("waiting for subnet creation to be committed...") - time.Sleep(15 * time.Second) + time.Sleep(2 * time.Second) if err = ln.addChainValidators(ctx, platformCli, w, chainIDs, participantsSpecs); err != nil { ln.logger.Error("installCustomChains: failed to add chain validators", @@ -966,10 +1000,12 @@ func (ln *localNetwork) installCustomChains( } // Reload VMs after restart to ensure any new VMs are available + // CRITICAL FIX: Return error instead of swallowing - VM reload failure means chain won't work if err := ln.reloadVMPlugins(ctx); err != nil { - ln.logger.Warn("VM hot-reload after chain creation failed (non-fatal)", + ln.logger.Error("VM hot-reload after chain creation failed", "error", err.Error(), ) + return nil, fmt.Errorf("VM hot-reload failed after chain creation: %w", err) } chainInfos := make([]blockchainInfo, len(chainSpecs)) @@ -1133,22 +1169,22 @@ func (ln *localNetwork) waitForCustomChainsReady( ) } - // Quick health check with 30s timeout - don't block forever - // If network is healthy, chains should come up quickly - healthCtx, cancel := context.WithTimeout(ctx, 30*time.Second) + // FAIL FAST: 15s timeout for local chain health check + // If chain isn't healthy in 15s on localhost, something is wrong - return error immediately + healthCtx, cancel := context.WithTimeout(ctx, 15*time.Second) defer cancel() if err := ln.healthy(healthCtx); err != nil { - // Log warning but don't fail - chain is created, may just need more time - ln.logger.Warn("chain health check timed out, chain may still be starting", + // CRITICAL FIX: Return error instead of swallowing it + // This was causing CLI to wait forever while errors were logged but not returned + ln.logger.Error("chain health check failed - returning error immediately", "error", err.Error(), ) - ln.logger.Info("use 'lux network status' to check chain health") - } else { - fmt.Println() - ln.logger.Info(log.Green.Wrap("custom chains ready")) + return fmt.Errorf("custom chains not ready within 15s: %w", err) } + fmt.Println() + ln.logger.Info(log.Green.Wrap("custom chains ready")) return nil } @@ -1192,6 +1228,18 @@ func (ln *localNetwork) restartNodes( trackChainIDsSet.Add(s) } } + + // OPTIMIZATION: Nodes with track-chains=all auto-discover all chains. + // They don't need restart for new chain deployment - VM hot-reload is enough. + // This prevents race conditions where VMs are killed during initialization. + hasTrackAll := trackChainIDsSet.Contains("all") + if hasTrackAll { + ln.logger.Debug("node has track-chains=all, skipping restart", + "nodeName", nodeName, + ) + continue + } + needsRestart := false for _, validatorSpec := range validatorSpecs { if validatorSpec.NodeName == node.name { @@ -2272,7 +2320,8 @@ func (ln *localNetwork) reloadVMPlugins(ctx context.Context) error { // with retry logic to handle hot-loading delays func (ln *localNetwork) verifyVMsAvailable(ctx context.Context, vmIDs []ids.ID) error { const ( - maxRetries = 10 + // FAIL FAST: Reduced retries from 10 to 5 (2.5s max) + maxRetries = 5 retryInterval = 500 * time.Millisecond ) diff --git a/local/genesis_config.go b/local/genesis_config.go index 6737016c..063b2e21 100644 --- a/local/genesis_config.go +++ b/local/genesis_config.go @@ -4,13 +4,13 @@ package local import ( + "bytes" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "os" "path/filepath" - "strings" "time" "github.com/luxfi/const" @@ -31,6 +31,79 @@ import ( "github.com/luxfi/node/utils/formatting/address" ) +// patchGenesisPreservingRaw patches a top-level genesis JSON document while guaranteeing that +// selected keys are preserved byte-for-byte as raw JSON values (including quotes/escapes for strings). +// +// This is the correct approach for EVM genesis fields (C-Chain + any subnet EVM genesis) because +// parsing via interface{} will corrupt large numeric fields and/or change encoding. +// +// CRITICAL: Never use map[string]interface{} for genesis - it causes float64 precision loss! +func patchGenesisPreservingRaw( + in []byte, + preserveKeys []string, + mutate func(m map[string]json.RawMessage) error, +) ([]byte, error) { + var m map[string]json.RawMessage + if err := json.Unmarshal(in, &m); err != nil { + return nil, fmt.Errorf("unmarshal genesis envelope: %w", err) + } + + // Snapshot preserved raw values. + preserved := make(map[string]json.RawMessage, len(preserveKeys)) + for _, k := range preserveKeys { + if v, ok := m[k]; ok { + // deep copy + preserved[k] = append(json.RawMessage(nil), v...) + } + } + + // Apply edits. + if err := mutate(m); err != nil { + return nil, err + } + + // Restore preserved values (even if mutate touched them by accident). + for k, v := range preserved { + m[k] = v + } + + // Marshal output. + out, err := json.MarshalIndent(m, "", " ") + if err != nil { + return nil, fmt.Errorf("marshal genesis envelope: %w", err) + } + + // Sanity check: ensure preserved keys are still byte-identical. + var m2 map[string]json.RawMessage + if err := json.Unmarshal(out, &m2); err != nil { + return nil, fmt.Errorf("re-unmarshal genesis envelope: %w", err) + } + for k, v := range preserved { + if vv, ok := m2[k]; ok && !bytes.Equal(vv, v) { + return nil, fmt.Errorf("FATAL: preserved genesis key %q mutated (byte mismatch)", k) + } + } + + return out, nil +} + +// mustJSON is a helper for assigning scalars/structs back into RawMessage maps. +func mustJSON(v any) json.RawMessage { + b, err := json.Marshal(v) + if err != nil { + panic(err) + } + return b +} + +// evmGenesisKeys are the keys that MUST be preserved byte-for-byte in genesis. +// These correspond to EVM chain genesis configurations. +var evmGenesisKeys = []string{ + "cChainGenesis", + // Add subnet EVM genesis keys if embedded in main genesis: + // "hanzoGenesis", "spcGenesis", "zooGenesis", +} + // NewConfigForNetwork creates a network config for the specified network ID. // This uses the proper genesis configuration from github.com/luxfi/genesis/configs. // @@ -104,12 +177,9 @@ func NewConfigForNetwork(binaryPath string, numNodes uint32, networkID uint32) ( // - Use embedded validator keys from defaultNetworkConfig // - Keep initialStakers from genesis (already matches embedded keys) // - Generate P-chain allocations for the embedded validators - - // Parse genesis to modify it - var genesis map[string]interface{} - if err := json.Unmarshal(genesisJSON, &genesis); err != nil { - return network.Config{}, fmt.Errorf("failed to parse genesis: %w", err) - } + // + // CRITICAL: Use patchGenesisPreservingRaw to ensure cChainGenesis bytes are NEVER modified. + // Parsing via map[string]interface{} corrupts large numerics (float64 precision loss). hrp := constants.GetHRP(networkID) @@ -125,147 +195,133 @@ func NewConfigForNetwork(binaryPath string, numNodes uint32, networkID uint32) ( numEmbeddedToUse = numEmbedded } - // For P/X-chain allocations, we need to create them for keys the wallet can use. - // C-chain allocations are historic (embedded in genesis), but P/X can be set freely. - // REPLACE allocations with ones for the wallet's key (mnemonic or private key). - var newAllocations []interface{} + // Patch genesis using RawMessage to preserve cChainGenesis byte-exact + updatedGenesis, err := patchGenesisPreservingRaw(genesisJSON, evmGenesisKeys, func(m map[string]json.RawMessage) error { + // Build P/X-chain allocations for wallet keys + var newAllocations []map[string]interface{} - // If LUX_MNEMONIC is set, create allocations for mnemonic-derived key - // Need BOTH X-chain (for transfers) and P-chain (for chain creation/validators) - if mnemonic := os.Getenv("LUX_MNEMONIC"); mnemonic != "" { - validatorKeys, err := keys.DeriveValidatorsFromMnemonic(mnemonic, 1) - if err == nil && len(validatorKeys) > 0 { - vk := validatorKeys[0] - addr := vk.PChainAddr // Same underlying secp256k1 address - xLuxAddr, errX := address.Format("X", hrp, addr[:]) - pLuxAddr, errP := address.Format("P", hrp, addr[:]) - if errX == nil && errP == nil { - fmt.Printf("🔑 Setting X+P allocations for LUX_MNEMONIC: X=%s, P=%s (2B each)\n", xLuxAddr, pLuxAddr) - // X-chain allocation (for asset transfers) - newAllocations = append(newAllocations, map[string]interface{}{ - "ethAddr": vk.CChainAddrHex(), - "luxAddr": xLuxAddr, - "initialAmount": uint64(2000000000000000000), // 2B LUX - "unlockSchedule": []map[string]interface{}{}, - }) - // P-chain allocation (for chain creation, validators) - // IMPORTANT: Must have unlockSchedule entries for builder to create UTXOs - newAllocations = append(newAllocations, map[string]interface{}{ - "ethAddr": vk.CChainAddrHex(), - "luxAddr": pLuxAddr, - "initialAmount": uint64(0), // Not used for P-chain, unlockSchedule is used - "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(2000000000000000000), // 2B LUX - "locktime": uint64(0), // Immediately available - }, - }, - }) - } - } - } - - // If LUX_PRIVATE_KEY is set, also create X+P allocations for it - if privKeyHex := os.Getenv("LUX_PRIVATE_KEY"); privKeyHex != "" { - privKeyBytes, err := hex.DecodeString(privKeyHex) - if err == nil && len(privKeyBytes) == 32 { - luxPrivKey, err := luxcrypto.ToPrivateKey(privKeyBytes) - if err == nil { - pubKey := luxPrivKey.PublicKey() - addr := ids.ShortID(pubKey.Address()) + // If LUX_MNEMONIC is set, create allocations for mnemonic-derived key + if mnemonic := os.Getenv("LUX_MNEMONIC"); mnemonic != "" { + validatorKeys, err := keys.DeriveValidatorsFromMnemonic(mnemonic, 1) + if err == nil && len(validatorKeys) > 0 { + vk := validatorKeys[0] + addr := vk.PChainAddr xLuxAddr, errX := address.Format("X", hrp, addr[:]) pLuxAddr, errP := address.Format("P", hrp, addr[:]) if errX == nil && errP == nil { - fmt.Printf("🔑 Adding X+P allocations for LUX_PRIVATE_KEY: X=%s, P=%s (2B each)\n", xLuxAddr, pLuxAddr) - ethAddr := "0x" + hex.EncodeToString(addr[:]) + fmt.Printf("🔑 Setting X+P allocations for LUX_MNEMONIC: X=%s, P=%s (2B each)\n", xLuxAddr, pLuxAddr) // X-chain allocation newAllocations = append(newAllocations, map[string]interface{}{ - "ethAddr": ethAddr, + "ethAddr": vk.CChainAddrHex(), "luxAddr": xLuxAddr, - "initialAmount": uint64(2000000000000000000), // 2B LUX - "unlockSchedule": []map[string]interface{}{}, + "initialAmount": uint64(2000000000000000000), + "unlockSchedule": []interface{}{}, }) - // P-chain allocation - must use unlockSchedule for builder to create UTXOs + // P-chain allocation newAllocations = append(newAllocations, map[string]interface{}{ - "ethAddr": ethAddr, + "ethAddr": vk.CChainAddrHex(), "luxAddr": pLuxAddr, - "initialAmount": uint64(0), // Not used for P-chain + "initialAmount": uint64(0), "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(2000000000000000000), // 2B LUX - "locktime": uint64(0), // Immediately available - }, + {"amount": uint64(2000000000000000000), "locktime": uint64(0)}, }, }) } } } - } - // If we created new allocations, replace the genesis allocations - // Otherwise, keep the genesis package's allocations (for backward compatibility) - if len(newAllocations) > 0 { - genesis["allocations"] = newAllocations - } - - // Generate initialStakers from embedded validator keys if not provided in genesis - // This is needed because testnet/mainnet genesis may not have initialStakers defined - initialStakers, hasStakers := genesis["initialStakers"] - stakersSlice, isSlice := initialStakers.([]interface{}) - if !hasStakers || !isSlice || len(stakersSlice) == 0 { - // Generate initialStakers from embedded validator keys - var generatedStakers []map[string]interface{} - for i := uint32(0); i < numEmbeddedToUse; i++ { - embeddedConfig := defaultNetworkConfig.NodeConfigs[i] - - // Get NodeID from staking cert - nodeID, err := utils.ToNodeID([]byte(embeddedConfig.StakingKey), []byte(embeddedConfig.StakingCert)) - if err != nil { - return network.Config{}, fmt.Errorf("failed to get NodeID for node %d: %w", i, err) + // If LUX_PRIVATE_KEY is set, also create X+P allocations for it + if privKeyHex := os.Getenv("LUX_PRIVATE_KEY"); privKeyHex != "" { + privKeyBytes, err := hex.DecodeString(privKeyHex) + if err == nil && len(privKeyBytes) == 32 { + luxPrivKey, err := luxcrypto.ToPrivateKey(privKeyBytes) + if err == nil { + pubKey := luxPrivKey.PublicKey() + addr := ids.ShortID(pubKey.Address()) + xLuxAddr, errX := address.Format("X", hrp, addr[:]) + pLuxAddr, errP := address.Format("P", hrp, addr[:]) + if errX == nil && errP == nil { + fmt.Printf("🔑 Adding X+P allocations for LUX_PRIVATE_KEY: X=%s, P=%s (2B each)\n", xLuxAddr, pLuxAddr) + ethAddr := "0x" + hex.EncodeToString(addr[:]) + newAllocations = append(newAllocations, map[string]interface{}{ + "ethAddr": ethAddr, + "luxAddr": xLuxAddr, + "initialAmount": uint64(2000000000000000000), + "unlockSchedule": []interface{}{}, + }) + newAllocations = append(newAllocations, map[string]interface{}{ + "ethAddr": ethAddr, + "luxAddr": pLuxAddr, + "initialAmount": uint64(0), + "unlockSchedule": []map[string]interface{}{ + {"amount": uint64(2000000000000000000), "locktime": uint64(0)}, + }, + }) + } + } } - - // Get BLS key and compute ProofOfPossession - blsKeyBytes, err := base64.StdEncoding.DecodeString(embeddedConfig.StakingSigningKey) - if err != nil { - return network.Config{}, fmt.Errorf("failed to decode BLS key for node %d: %w", i, err) - } - blsSecretKey, err := bls.SecretKeyFromBytes(blsKeyBytes) - if err != nil { - return network.Config{}, fmt.Errorf("failed to parse BLS key for node %d: %w", i, err) - } - pop, err := signer.NewProofOfPossession(blsSecretKey) - if err != nil { - return network.Config{}, fmt.Errorf("failed to create ProofOfPossession for node %d: %w", i, err) - } - - // Create staker entry - use a reward address derived from the first key or a treasury address - // For simplicity, use the X-chain address from the first allocation or default - staker := map[string]interface{}{ - "nodeID": nodeID.String(), - "rewardAddress": "P-test1yljhuvjkmtu0y5ls6kf4exsdd8gea9mp7faxl2", // Default testnet treasury - "delegationFee": uint32(20000), // 2% - "signer": map[string]interface{}{ - "publicKey": fmt.Sprintf("0x%x", pop.PublicKey[:]), - "proofOfPossession": fmt.Sprintf("0x%x", pop.ProofOfPossession[:]), - }, - } - generatedStakers = append(generatedStakers, staker) } - genesis["initialStakers"] = generatedStakers - fmt.Printf("🔧 Generated %d initialStakers from embedded validator keys\n", len(generatedStakers)) - } - // Set initialStakedFunds to empty - allocations are for free balance, not staking - genesis["initialStakedFunds"] = []string{} + // Update allocations if we have new ones + if len(newAllocations) > 0 { + m["allocations"] = mustJSON(newAllocations) + } - // Update start time to now - now := time.Now().Unix() - genesis["startTime"] = uint64(now) + // Check if we need to generate initialStakers + var existingStakers []interface{} + if raw, ok := m["initialStakers"]; ok { + json.Unmarshal(raw, &existingStakers) + } + if len(existingStakers) == 0 { + // Generate initialStakers from embedded validator keys + var generatedStakers []map[string]interface{} + for i := uint32(0); i < numEmbeddedToUse; i++ { + embeddedConfig := defaultNetworkConfig.NodeConfigs[i] - // Re-serialize genesis - updatedGenesis, err := json.MarshalIndent(genesis, "", " ") + nodeID, err := utils.ToNodeID([]byte(embeddedConfig.StakingKey), []byte(embeddedConfig.StakingCert)) + if err != nil { + return fmt.Errorf("failed to get NodeID for node %d: %w", i, err) + } + + blsKeyBytes, err := base64.StdEncoding.DecodeString(embeddedConfig.StakingSigningKey) + if err != nil { + return fmt.Errorf("failed to decode BLS key for node %d: %w", i, err) + } + blsSecretKey, err := bls.SecretKeyFromBytes(blsKeyBytes) + if err != nil { + return fmt.Errorf("failed to parse BLS key for node %d: %w", i, err) + } + pop, err := signer.NewProofOfPossession(blsSecretKey) + if err != nil { + return fmt.Errorf("failed to create ProofOfPossession for node %d: %w", i, err) + } + + staker := map[string]interface{}{ + "nodeID": nodeID.String(), + "rewardAddress": "P-test1yljhuvjkmtu0y5ls6kf4exsdd8gea9mp7faxl2", + "delegationFee": uint32(20000), + "signer": map[string]interface{}{ + "publicKey": fmt.Sprintf("0x%x", pop.PublicKey[:]), + "proofOfPossession": fmt.Sprintf("0x%x", pop.ProofOfPossession[:]), + }, + } + generatedStakers = append(generatedStakers, staker) + } + m["initialStakers"] = mustJSON(generatedStakers) + fmt.Printf("🔧 Generated %d initialStakers from embedded validator keys\n", len(generatedStakers)) + } + + // Set initialStakedFunds to empty + m["initialStakedFunds"] = mustJSON([]string{}) + + // Update start time to now + now := time.Now().Unix() + m["startTime"] = mustJSON(uint64(now)) + + return nil + }) if err != nil { - return network.Config{}, fmt.Errorf("failed to serialize updated genesis: %w", err) + return network.Config{}, fmt.Errorf("failed to patch genesis: %w", err) } netConfig.Genesis = string(updatedGenesis) @@ -369,11 +425,24 @@ func NewCanonicalCustomConfig(binaryPath string, numNodes uint32) (network.Confi // and loads validator keys from ~/.lux/keys/node{0..n-1}/ func newCanonicalConfig(binaryPath string, numNodes uint32, networkID uint32, portBase int) (network.Config, error) { // Load CANONICAL genesis bytes - no parsing/re-serialization - genesisBytes, err := configs.GetCanonicalGenesisBytes(networkID) + originalGenesisBytes, err := configs.GetCanonicalGenesisBytes(networkID) if err != nil { return network.Config{}, fmt.Errorf("failed to load canonical genesis: %w", err) } + // For LOCAL TESTING: Update startTime to now so bootstrap starts immediately. + // CRITICAL: Use patchGenesisPreservingRaw to preserve cChainGenesis exact bytes. + now := time.Now().Unix() + fmt.Printf("📅 Updated genesis startTime to %d (now) for local testing\n", now) + + genesisBytes, err := patchGenesisPreservingRaw(originalGenesisBytes, evmGenesisKeys, func(m map[string]json.RawMessage) error { + m["startTime"] = mustJSON(uint64(now)) + return nil + }) + if err != nil { + return network.Config{}, fmt.Errorf("failed to patch genesis: %w", err) + } + // Start with default config netConfig := NewDefaultConfig(binaryPath) netConfig.Genesis = string(genesisBytes) @@ -506,16 +575,11 @@ func NewConfigWithPreExistingKeys(binaryPath string, networkID uint32, keysDir s // Start with the default config structure netConfig := NewDefaultConfig(binaryPath) - // Parse genesis to modify it - var genesis map[string]interface{} - if err := json.Unmarshal(genesisJSON, &genesis); err != nil { - return network.Config{}, fmt.Errorf("failed to parse genesis: %w", err) - } - - // Build initial stakers from loaded keys + // Build P/X chain data BEFORE patching genesis hrp := constants.GetHRP(networkID) numNodes := uint32(len(validatorKeys)) + // Build initial stakers from loaded keys initialStakers := make([]map[string]interface{}, numNodes) for i, vk := range validatorKeys { rewardAddr, err := address.Format("P", hrp, vk.PChainAddr[:]) @@ -526,11 +590,10 @@ func NewConfigWithPreExistingKeys(binaryPath string, networkID uint32, keysDir s staker := map[string]interface{}{ "nodeID": vk.NodeID.String(), "rewardAddress": rewardAddr, - "delegationFee": 20000, // 2% delegation fee - "weight": GigaLux, // 1,000,000,000 LUX (1B) per validator + "delegationFee": 20000, + "weight": GigaLux, } - // Add BLS signer if available if len(vk.BLSPublicKey) > 0 && len(vk.BLSPoP) > 0 { staker["signer"] = map[string]interface{}{ "publicKey": vk.BLSPublicKeyHex(), @@ -541,44 +604,32 @@ func NewConfigWithPreExistingKeys(binaryPath string, networkID uint32, keysDir s initialStakers[i] = staker } - // Update genesis with initial stakers (our validator NodeIDs) - genesis["initialStakers"] = initialStakers - - // Generate allocations from validator keys (rather than expecting pre-existing allocations) - // Each validator gets both X-chain and P-chain allocations - // X-chain: 1B LUX immediately available - // P-chain: 1B LUX with 1% unlock per year for 100 years starting Jan 1 2020 - allocations := make([]interface{}, 0, numNodes*2) - - // Constants for P-chain unlock schedule + // Build allocations const ( - oneGigaLux = uint64(1000000000000000000) // 1B LUX in nLUX - onePercentPerYear = oneGigaLux / 100 // 1% = 10M LUX - jan1_2020 = uint64(1577836800) // Unix timestamp - oneYear = uint64(31536000) // seconds + oneGigaLux = uint64(1000000000000000000) + onePercentPerYear = oneGigaLux / 100 + jan1_2020 = uint64(1577836800) + oneYear = uint64(31536000) ) + var allocations []map[string]interface{} for i, vk := range validatorKeys { - // Build P-chain address pChainAddr, err := address.Format("P", hrp, vk.PChainAddr[:]) if err != nil { return network.Config{}, fmt.Errorf("failed to format P-chain address for validator %d: %w", i, err) } - // Build X-chain address xChainAddr, err := address.Format("X", hrp, vk.PChainAddr[:]) if err != nil { return network.Config{}, fmt.Errorf("failed to format X-chain address for validator %d: %w", i, err) } - // X-chain allocation (1B LUX) - immediately available allocations = append(allocations, map[string]interface{}{ "ethAddr": vk.CChainAddrHex(), "luxAddr": xChainAddr, "initialAmount": oneGigaLux, - "unlockSchedule": []map[string]interface{}{}, + "unlockSchedule": []interface{}{}, }) - // P-chain allocation (1B LUX) - 1% per year for 100 years pchainUnlockSchedule := make([]map[string]interface{}, 100) for year := 0; year < 100; year++ { pchainUnlockSchedule[year] = map[string]interface{}{ @@ -595,94 +646,65 @@ func NewConfigWithPreExistingKeys(binaryPath string, networkID uint32, keysDir s fmt.Printf(" Validator %d: %s -> X:%s P:%s (1B each)\n", i+1, vk.NodeID.String(), xChainAddr, pChainAddr) } - genesis["allocations"] = allocations - // Set initialStakedFunds to EMPTY - we use explicit weight in initialStakers - genesis["initialStakedFunds"] = []string{} - - // Check for LUX_MNEMONIC and add mnemonic-derived allocation with FREE funds - // This enables subnet creation without needing the hardcoded treasury key - // IMPORTANT: Add this AFTER setting initialStakedFunds so mnemonic funds are NOT staked + // Add mnemonic allocation if set if mnemonic := os.Getenv("LUX_MNEMONIC"); mnemonic != "" { fmt.Printf("🔑 LUX_MNEMONIC is set, adding mnemonic allocation to genesis\n") - mnemonicAlloc := map[string]interface{}{ + allocations = append(allocations, map[string]interface{}{ "ethAddr": "0x0406d56943a38ad8398a738527f27e2cf01731a8", "luxAddr": "P-lux1qsrd262r5w9dswv2wwzj0un79ncpwvdgkpqzqu", "initialAmount": 0, "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(100000000000000), // 100,000 LUX - "locktime": uint64(0), - }, + {"amount": uint64(100000000000000), "locktime": uint64(0)}, }, - } - - // Append mnemonic allocation directly to our allocations slice - fmt.Printf(" Adding mnemonic allocation (NOT staked) to %d existing allocations\n", len(allocations)) - allocations = append(allocations, mnemonicAlloc) - genesis["allocations"] = allocations - } else { - fmt.Printf("⚠️ LUX_MNEMONIC not set, skipping mnemonic allocation\n") + }) } - // Check for LUX_PRIVATE_KEY and add allocations with correct HRP for this network - // This enables deploy operations when using a specific private key + // Add private key allocation if set + var initialStakedFunds []string if privKeyHex := os.Getenv("LUX_PRIVATE_KEY"); privKeyHex != "" { privKeyBytes, err := hex.DecodeString(privKeyHex) if err == nil && len(privKeyBytes) == 32 { - // Derive address from private key luxPrivKey, err := luxcrypto.ToPrivateKey(privKeyBytes) if err == nil { pubKey := luxPrivKey.PublicKey() pChainAddr := ids.ShortID(pubKey.Address()) - - // Format addresses with the correct HRP for this network xLuxAddr, errX := address.Format("X", hrp, pChainAddr[:]) pLuxAddr, errP := address.Format("P", hrp, pChainAddr[:]) if errX == nil && errP == nil { ethAddr := "0x" + hex.EncodeToString(pChainAddr[:]) fmt.Printf("🔑 Adding LUX_PRIVATE_KEY allocations: X=%s, P=%s (2B each)\n", xLuxAddr, pLuxAddr) - - // X-chain allocation (2B LUX) - immediately available allocations = append(allocations, map[string]interface{}{ "ethAddr": ethAddr, "luxAddr": xLuxAddr, - "initialAmount": uint64(2000000000000000000), // 2B LUX - "unlockSchedule": []map[string]interface{}{}, + "initialAmount": uint64(2000000000000000000), + "unlockSchedule": []interface{}{}, }) - - // P-chain allocation (2B LUX) - immediately available for subnet creation allocations = append(allocations, map[string]interface{}{ "ethAddr": ethAddr, "luxAddr": pLuxAddr, "initialAmount": uint64(0), "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(2000000000000000000), // 2B LUX - "locktime": uint64(0), // Immediately available - }, + {"amount": uint64(2000000000000000000), "locktime": uint64(0)}, }, }) - genesis["allocations"] = allocations - - // Add to initialStakedFunds for P-chain access - initialStakedFunds, _ := genesis["initialStakedFunds"].([]string) initialStakedFunds = append(initialStakedFunds, xLuxAddr) - genesis["initialStakedFunds"] = initialStakedFunds - fmt.Printf("🔑 Added %s to initialStakedFunds for P-chain access\n", xLuxAddr) } } } } - // Update start time to now + // Patch genesis using RawMessage to preserve cChainGenesis byte-exact now := time.Now().Unix() - genesis["startTime"] = uint64(now) - - // Re-serialize genesis - updatedGenesis, err := json.MarshalIndent(genesis, "", " ") + updatedGenesis, err := patchGenesisPreservingRaw(genesisJSON, evmGenesisKeys, func(m map[string]json.RawMessage) error { + m["initialStakers"] = mustJSON(initialStakers) + m["allocations"] = mustJSON(allocations) + m["initialStakedFunds"] = mustJSON(initialStakedFunds) + m["startTime"] = mustJSON(uint64(now)) + return nil + }) if err != nil { - return network.Config{}, fmt.Errorf("failed to serialize updated genesis: %w", err) + return network.Config{}, fmt.Errorf("failed to patch genesis: %w", err) } netConfig.Genesis = string(updatedGenesis) @@ -848,42 +870,27 @@ func NewConfigFromMnemonic(binaryPath string, networkID uint32, numNodes uint32) // Start with default config netConfig := NewDefaultConfig(binaryPath) - // Parse genesis to modify it - var genesis map[string]interface{} - if err := json.Unmarshal(genesisJSON, &genesis); err != nil { - return network.Config{}, fmt.Errorf("failed to parse genesis: %w", err) - } - hrp := constants.GetHRP(networkID) // Build initial stakers from derived keys initialStakers := make([]map[string]interface{}, numNodes) - // Each validator gets BOTH X-chain AND P-chain allocations (2 entries per validator) - allocations := make([]interface{}, 0, numNodes*2) + var allocations []map[string]interface{} for i, vk := range validatorKeys { - fmt.Printf("🔍 Validator %d: PChainAddr ShortID = %s\n", i, vk.PChainAddr.String()) - - // Build P-chain address for staker rewards and P-chain operations pChainAddr, err := address.Format("P", hrp, vk.PChainAddr[:]) if err != nil { return network.Config{}, fmt.Errorf("failed to format P-chain address for validator %d: %w", i, err) } - fmt.Printf("🔍 Validator %d: P-chain bech32 = %s\n", i, pChainAddr) - - // Build X-chain address for asset transfers xChainAddr, err := address.Format("X", hrp, vk.PChainAddr[:]) if err != nil { return network.Config{}, fmt.Errorf("failed to format X-chain address for validator %d: %w", i, err) } - fmt.Printf("🔍 Validator %d: X-chain bech32 = %s\n", i, xChainAddr) - // Initial staker entry staker := map[string]interface{}{ "nodeID": vk.NodeID.String(), - "rewardAddress": xChainAddr, // Rewards go to X-chain address - "delegationFee": 20000, // 2% delegation fee - "weight": GigaLux, // 1B LUX per validator + "rewardAddress": xChainAddr, + "delegationFee": 20000, + "weight": GigaLux, } if len(vk.BLSPublicKey) > 0 && len(vk.BLSPoP) > 0 { staker["signer"] = map[string]interface{}{ @@ -893,26 +900,18 @@ func NewConfigFromMnemonic(binaryPath string, networkID uint32, numNodes uint32) } initialStakers[i] = staker - // X-chain allocation (2B LUX) - for asset transfers allocations = append(allocations, map[string]interface{}{ "ethAddr": vk.CChainAddrHex(), "luxAddr": xChainAddr, - "initialAmount": uint64(2000000000000000000), // 2B LUX - "unlockSchedule": []map[string]interface{}{}, + "initialAmount": uint64(2000000000000000000), + "unlockSchedule": []interface{}{}, }) - - // P-chain allocation (2B LUX) - for chain creation, validators - // P-chain allocation - MUST use unlockSchedule for P-chain UTXOs - // The builder processes unlockSchedule for P-chain, initialAmount for X-chain allocations = append(allocations, map[string]interface{}{ "ethAddr": vk.CChainAddrHex(), "luxAddr": pChainAddr, "initialAmount": uint64(0), "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(2000000000000000000), // 2B LUX - "locktime": uint64(0), // locktime 0 = immediately unlocked - }, + {"amount": uint64(2000000000000000000), "locktime": uint64(0)}, }, }) @@ -921,43 +920,33 @@ func NewConfigFromMnemonic(binaryPath string, networkID uint32, numNodes uint32) // Add wallet key allocation if different from validators if walletNeedsAllocation { - // Build X-chain address for wallet walletXAddr, err := address.Format("X", hrp, walletKey.PChainAddr[:]) if err != nil { return network.Config{}, fmt.Errorf("failed to format wallet X-chain address: %w", err) } - // Build P-chain address for wallet walletPAddr, err := address.Format("P", hrp, walletKey.PChainAddr[:]) if err != nil { return network.Config{}, fmt.Errorf("failed to format wallet P-chain address: %w", err) } - // X-chain allocation for wallet (2B LUX) allocations = append(allocations, map[string]interface{}{ "ethAddr": walletKey.CChainAddrHex(), "luxAddr": walletXAddr, - "initialAmount": uint64(2000000000000000000), // 2B LUX - "unlockSchedule": []map[string]interface{}{}, + "initialAmount": uint64(2000000000000000000), + "unlockSchedule": []interface{}{}, }) - - // P-chain allocation for wallet (2B LUX) - MUST use unlockSchedule allocations = append(allocations, map[string]interface{}{ "ethAddr": walletKey.CChainAddrHex(), "luxAddr": walletPAddr, "initialAmount": uint64(0), "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(2000000000000000000), // 2B LUX - "locktime": uint64(0), // locktime 0 = immediately unlocked - }, + {"amount": uint64(2000000000000000000), "locktime": uint64(0)}, }, }) - fmt.Printf(" Wallet: %s -> X:%s P:%s (2B each)\n", walletKey.PChainAddr.String(), walletXAddr, walletPAddr) } - // Also add allocations for LUX_PRIVATE_KEY if set and different from wallet key - // This is needed when getDefaultKey() in blockchain.go uses LUX_PRIVATE_KEY + // Add LUX_PRIVATE_KEY allocations if set and different from wallet key if privKeyHex := os.Getenv("LUX_PRIVATE_KEY"); privKeyHex != "" { privKeyBytes, err := hex.DecodeString(privKeyHex) if err == nil && len(privKeyBytes) == 32 { @@ -966,92 +955,44 @@ func NewConfigFromMnemonic(binaryPath string, networkID uint32, numNodes uint32) pubKey := luxPrivKey.PublicKey() privKeyAddr := ids.ShortID(pubKey.Address()) - // Check if this is different from wallet key if privKeyAddr != walletKey.PChainAddr { privKeyXAddr, errX := address.Format("X", hrp, privKeyAddr[:]) privKeyPAddr, errP := address.Format("P", hrp, privKeyAddr[:]) if errX == nil && errP == nil { - fmt.Printf("🔑 Adding LUX_PRIVATE_KEY allocations (with %s HRP): X=%s P=%s (2B each)\n", hrp, privKeyXAddr, privKeyPAddr) + fmt.Printf("🔑 Adding LUX_PRIVATE_KEY allocations: X=%s P=%s (2B each)\n", privKeyXAddr, privKeyPAddr) ethAddr := "0x" + hex.EncodeToString(privKeyAddr[:]) - - // X-chain allocation allocations = append(allocations, map[string]interface{}{ "ethAddr": ethAddr, "luxAddr": privKeyXAddr, - "initialAmount": uint64(2000000000000000000), // 2B LUX - "unlockSchedule": []map[string]interface{}{}, + "initialAmount": uint64(2000000000000000000), + "unlockSchedule": []interface{}{}, }) - - // P-chain allocation - MUST use unlockSchedule allocations = append(allocations, map[string]interface{}{ "ethAddr": ethAddr, "luxAddr": privKeyPAddr, "initialAmount": uint64(0), "unlockSchedule": []map[string]interface{}{ - { - "amount": uint64(2000000000000000000), // 2B LUX - "locktime": uint64(0), // locktime 0 = immediately unlocked - }, + {"amount": uint64(2000000000000000000), "locktime": uint64(0)}, }, }) } - } else { - fmt.Printf("🔑 LUX_PRIVATE_KEY matches wallet key, no extra allocation needed\n") } } } } - genesis["initialStakers"] = initialStakers - genesis["allocations"] = allocations - - // CRITICAL: Also update xChainGenesis.allocations! - // The X-chain reads allocations from the embedded xChainGenesis JSON string, - // NOT from the top-level allocations array. We must update both. - if xChainGenesisStr, ok := genesis["xChainGenesis"].(string); ok { - var xChainGenesis map[string]interface{} - if err := json.Unmarshal([]byte(xChainGenesisStr), &xChainGenesis); err == nil { - // Build X-chain specific allocations (only X-chain addresses, use avaxAddr format) - xAllocations := make([]map[string]interface{}, 0) - for _, alloc := range allocations { - allocMap := alloc.(map[string]interface{}) - luxAddr, _ := allocMap["luxAddr"].(string) - // Only include X-chain allocations (start with "X-") - if strings.HasPrefix(luxAddr, "X-") { - initialAmount, _ := allocMap["initialAmount"].(uint64) - if initialAmount > 0 { - xAllocations = append(xAllocations, map[string]interface{}{ - "avaxAddr": luxAddr, // X-chain uses avaxAddr field name - "ethAddr": allocMap["ethAddr"], - "initialAmount": initialAmount, - "unlockSchedule": []interface{}{}, - }) - } - } - } - xChainGenesis["allocations"] = xAllocations - if updatedXChain, err := json.Marshal(xChainGenesis); err == nil { - genesis["xChainGenesis"] = string(updatedXChain) - fmt.Printf("✅ Updated xChainGenesis with %d allocations\n", len(xAllocations)) - } - } - } - - // IMPORTANT: Set initialStakedFunds to EMPTY so that P-chain allocations - // are NOT filtered by the builder. The builder filters allocations where - // the underlying ShortID matches initialStakedFunds, which would incorrectly - // filter P-chain allocations that share the same address as X-chain validators. - // We use explicit weight in initialStakers instead of deriving from stakes. - genesis["initialStakedFunds"] = []string{} - - // Update start time to now + // Patch genesis using RawMessage to preserve cChainGenesis byte-exact + // CRITICAL: Never use map[string]interface{} for genesis - it causes float64 precision loss! now := time.Now().Unix() - genesis["startTime"] = uint64(now) - - // Re-serialize genesis - updatedGenesis, err := json.MarshalIndent(genesis, "", " ") + updatedGenesis, err := patchGenesisPreservingRaw(genesisJSON, evmGenesisKeys, func(m map[string]json.RawMessage) error { + m["initialStakers"] = mustJSON(initialStakers) + m["allocations"] = mustJSON(allocations) + m["initialStakedFunds"] = mustJSON([]string{}) + m["startTime"] = mustJSON(uint64(now)) + return nil + }) if err != nil { - return network.Config{}, fmt.Errorf("failed to serialize genesis: %w", err) + return network.Config{}, fmt.Errorf("failed to patch genesis: %w", err) } netConfig.Genesis = string(updatedGenesis) diff --git a/main.go b/main.go index 343d27d1..9bfda1eb 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,4 @@ -// Copyright (C) 2025, Lux Industries Inc. All rights reserved. +// Copyright (C) 2021-2025, Lux Industries Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause package main diff --git a/server/network.go b/server/network.go index bd0ed218..def7d0d4 100644 --- a/server/network.go +++ b/server/network.go @@ -266,6 +266,14 @@ func (lc *localNetwork) createConfig() error { cfg.Flags[k] = v } + // Extract track-chains from global config if present + // This allows CLI to pass track-chains in globalNodeConfig JSON + if trackChainsVal, ok := globalConfig["track-chains"]; ok { + if trackChainsStr, ok := trackChainsVal.(string); ok { + lc.options.trackChains = trackChainsStr + } + } + if lc.pluginDir != "" { cfg.Flags[config.PluginDirKey] = lc.pluginDir } @@ -290,6 +298,12 @@ func (lc *localNetwork) createConfig() error { cfg.NodeConfigs[i].ChainConfigFiles = map[string]string{} } + // Propagate global config flags to each node config + // This ensures track-chains and other global settings apply to all nodes + for k, v := range globalConfig { + cfg.NodeConfigs[i].Flags[k] = v + } + for k, v := range lc.options.chainConfigs { cfg.NodeConfigs[i].ChainConfigFiles[k] = v } diff --git a/server/server.go b/server/server.go index 4afcc8ec..0fe0090e 100644 --- a/server/server.go +++ b/server/server.go @@ -53,9 +53,14 @@ const ( stopTimeout = 5 * time.Second defaultStartTimeout = 5 * time.Minute - // waitForHealthyTimeout increased from 3 to 10 minutes to allow proper - // bootstrapping of staking validators in mainnet configuration - waitForHealthyTimeout = 10 * time.Minute + // waitForHealthyTimeout - 60s for local 5-node network bootstrap + // First startup takes longer as nodes need to establish consensus + // Subsequent restarts are faster (<10s) but initial bootstrap needs time + waitForHealthyTimeout = 60 * time.Second + // chainDeployTimeout - 30s MAX for chain deploy operations + // FAIL FAST: If chain deploy takes longer than 30s, something is wrong + // Most P-chain API calls complete in <5s on localhost + chainDeployTimeout = 30 * time.Second TimeParseLayout = "2006-01-02 15:04:05" StakingMinimumLeadTime = 25 * time.Second @@ -619,10 +624,12 @@ func (s *server) CreateBlockchains( s.logger.Info("CreateBlockchains: starting chain creation", log.Int("numChains", len(chainSpecs)), - log.Duration("timeout", waitForHealthyTimeout), + log.Duration("timeout", chainDeployTimeout), ) - ctx, cancel := context.WithTimeout(context.Background(), waitForHealthyTimeout) + // FAIL FAST: Use shorter timeout for chain deploy operations + // 30s is plenty for local P-chain operations; if it takes longer, something is wrong + ctx, cancel := context.WithTimeout(context.Background(), chainDeployTimeout) defer cancel() chainIDs, err := s.network.CreateChains(ctx, chainSpecs) if err != nil {