diff --git a/go.mod b/go.mod index 338790d6..22743d49 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/ethereum/go-ethereum v1.14.3 github.com/gdamore/tcell/v2 v2.7.4 - github.com/nodeset-org/hyperdrive-daemon v0.5.0-b1 - github.com/nodeset-org/hyperdrive-stakewise v0.2.0 + github.com/nodeset-org/hyperdrive-daemon v1.0.0 + github.com/nodeset-org/hyperdrive-stakewise v1.0.1 github.com/rivo/tview v0.0.0-20230208211350-7dfff1ce7854 // DO NOT UPGRADE - github.com/rocket-pool/node-manager-core v0.4.0 + github.com/rocket-pool/node-manager-core v0.5.1-0.20240620041049-333f5150790e golang.org/x/sync v0.7.0 golang.org/x/term v0.19.0 gopkg.in/yaml.v2 v2.4.0 @@ -24,6 +24,7 @@ require ( github.com/alessio/shellescape v1.4.2 github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/cp v1.1.1 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect @@ -52,7 +53,6 @@ require ( github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/holiman/uint256 v1.2.4 // indirect - github.com/klauspost/compress v1.17.6 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -68,6 +68,7 @@ require ( github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rocket-pool/batch-query v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sethvargo/go-password v0.2.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -79,13 +80,16 @@ require ( github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.27.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.27.0 // indirect + go.opentelemetry.io/otel/sdk v1.27.0 // indirect + go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index a67cba9d..e8bf8459 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -119,8 +117,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -173,10 +171,10 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/nodeset-org/hyperdrive-daemon v0.5.0-b1 h1:WhAU40cQqKModEKyX5qnN4ZtPXDTIcw+t6HsJeyN9WQ= -github.com/nodeset-org/hyperdrive-daemon v0.5.0-b1/go.mod h1:4sJVNE2BZhtzdRAjQmw5A7aVenPFDJHrTgYHtajyRRg= -github.com/nodeset-org/hyperdrive-stakewise v0.2.0 h1:B9D2/LVdxUB54uh6gIGvClcObxNtlKObwK6Y+/Obaiw= -github.com/nodeset-org/hyperdrive-stakewise v0.2.0/go.mod h1:6LW0EQ+f1IzP7voVtwxG2ak6yDwM52oD//FR7ZF2gjo= +github.com/nodeset-org/hyperdrive-daemon v1.0.0 h1:gacaa2kP2wv1dBO4cpG03RGsdmCTiVRo2VvrhXb16zI= +github.com/nodeset-org/hyperdrive-daemon v1.0.0/go.mod h1:bkAacICyImNf7/nrHGiTuysDMCxtOq4wQ6dk1d2PbvI= +github.com/nodeset-org/hyperdrive-stakewise v1.0.1 h1:/o51y+O2MfHOQyzqLQepes9Afho+49pEaIgCi9hmRTI= +github.com/nodeset-org/hyperdrive-stakewise v1.0.1/go.mod h1:exRKj9kwdtHODX9woOllW/ZSarzmopTnVOvLEMyw+OU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -207,10 +205,10 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rocket-pool/batch-query v1.0.0 h1:5HejmT1n1fIdLIqUhTNwbkG2PGOPl3IVjCpFQcQZ4I4= github.com/rocket-pool/batch-query v1.0.0/go.mod h1:d1CmxShzk0fioJ4yX0eFGhz2an1odnW/LZ2cp3eDGIQ= -github.com/rocket-pool/node-manager-core v0.4.0 h1:oieATs51VwC9rJYPNnpF/oxUrRt5jLQIj5EBB5eKGik= -github.com/rocket-pool/node-manager-core v0.4.0/go.mod h1:Clii5aca9PvR4HoAlUs8dh2OsJbDDnJ4yL5EaQE1gSo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rocket-pool/node-manager-core v0.5.1-0.20240620041049-333f5150790e h1:Ml3pCctbeMQufM/cMHp4hIk46db2AypPnaMvcXPuu7w= +github.com/rocket-pool/node-manager-core v0.5.1-0.20240620041049-333f5150790e/go.mod h1:Clii5aca9PvR4HoAlUs8dh2OsJbDDnJ4yL5EaQE1gSo= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -229,8 +227,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= @@ -248,20 +246,20 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= +go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= +go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= +go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= +go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -304,8 +302,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -316,8 +314,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -330,14 +329,15 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240325203815-454cdb8f5daa h1:Jt1XW5PaLXF1/ePZrznsh/aAUvI7Adfc3LY1dAKlzRs= -google.golang.org/genproto/googleapis/api v0.0.0-20240325203815-454cdb8f5daa/go.mod h1:K4kfzHtI0kqWA79gecJarFtDn/Mls+GxQcg3Zox91Ac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa h1:RBgMaUMP+6soRkik4VoN8ojR2nex2TqZwjSSogic+eo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No= +google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/hyperdrive-cli/client/compose.go b/hyperdrive-cli/client/compose.go index 8741eacc..b6a694f8 100644 --- a/hyperdrive-cli/client/compose.go +++ b/hyperdrive-cli/client/compose.go @@ -28,7 +28,6 @@ func (c *HyperdriveClient) compose(composeFiles []string, args string) (string, if err != nil { return "", err } - if isNew { return "", fmt.Errorf("settings file not found. Please run `hyperdrive service config` to set up Hyperdrive before starting it") } @@ -43,6 +42,9 @@ func (c *HyperdriveClient) compose(composeFiles []string, args string) (string, return "", errors.New("no Beacon Node selected. Please run 'hyperdrive service config' before running this command") } + // Make sure the external IP is loaded + cfg.LoadExternalIP() + // Deploy the templates and run environment variable substitution on them deployedContainers, err := c.deployTemplates(cfg, expandedConfigPath) if err != nil { @@ -261,6 +263,7 @@ func (c *HyperdriveClient) composeModule(global *GlobalConfig, module hdconfig.I return []string{}, fmt.Errorf("error creating modules runtime folder (%s): %w", composePaths.RuntimePath, err) } + // Deploy the container templates for _, containerName := range toDeploy { containers, err := composePaths.File(string(containerName)).Write(global) if err != nil { @@ -269,5 +272,29 @@ func (c *HyperdriveClient) composeModule(global *GlobalConfig, module hdconfig.I deployedContainers = append(deployedContainers, containers...) } + // Check if the module has a Prometheus config + prometheusConfigFilename := modulePrometheusSd + template.TemplateSuffix + _, err = os.Stat(filepath.Join(composePaths.TemplatePath, prometheusConfigFilename)) + if os.IsNotExist(err) { + return deployedContainers, nil + } + + // Make the modules dir + modulesDir := filepath.Join(hyperdriveDir, metricsDir, hdconfig.ModulesName) + err = os.MkdirAll(modulesDir, metricsDirMode) + if err != nil { + return []string{}, fmt.Errorf("error creating metrics module directory [%s]: %w", modulesDir, err) + } + + // Deploy the Prometheus config + t := template.Template{ + Src: filepath.Join(composePaths.TemplatePath, prometheusConfigFilename), + Dst: filepath.Join(modulesDir, moduleName+template.ComposeFileSuffix), + } + err = t.Write(global) + if err != nil { + return []string{}, fmt.Errorf("could not write module [%s] Prometheus config: %w", moduleName, err) + } + return deployedContainers, nil } diff --git a/hyperdrive-cli/client/config.go b/hyperdrive-cli/client/config.go index a0b84464..2417e0c6 100644 --- a/hyperdrive-cli/client/config.go +++ b/hyperdrive-cli/client/config.go @@ -2,6 +2,7 @@ package client import ( "fmt" + "os" "path/filepath" "github.com/mitchellh/go-homedir" @@ -10,10 +11,11 @@ import ( ) const ( - prometheusConfigTemplate string = "prometheus-cfg.tmpl" - prometheusConfigTarget string = "prometheus.yml" - grafanaConfigTemplate string = "grafana-prometheus-datasource.tmpl" - grafanaConfigTarget string = "grafana-prometheus-datasource.yml" + metricsDirMode os.FileMode = 0755 + prometheusConfigTemplate string = "prometheus-cfg.tmpl" + prometheusConfigTarget string = "prometheus.yml" + grafanaConfigTemplate string = "grafana-prometheus-datasource.tmpl" + grafanaConfigTarget string = "grafana-prometheus-datasource.yml" ) // Load the config @@ -64,17 +66,31 @@ func (c *HyperdriveClient) SaveConfig(cfg *GlobalConfig) error { if err != nil { return err } - return SaveConfig(cfg, settingsFileDirectoryPath, SettingsFile) + err = SaveConfig(cfg, settingsFileDirectoryPath, SettingsFile) + if err != nil { + return fmt.Errorf("error saving config: %w", err) + } + + // Update the client's config cache + c.cfg = cfg + c.isNewCfg = false + return nil } // Load the Prometheus config template, do a template variable substitution, and save it func (c *HyperdriveClient) UpdatePrometheusConfiguration(config *GlobalConfig) error { + // Make sure the metrics path exists + metricsDirPath, err := createMetricsDir(c.Context.ConfigPath) + if err != nil { + return err + } + prometheusConfigTemplatePath, err := homedir.Expand(filepath.Join(templatesDir, prometheusConfigTemplate)) if err != nil { return fmt.Errorf("error expanding Prometheus config template path: %w", err) } - prometheusConfigTargetPath, err := homedir.Expand(filepath.Join(c.Context.ConfigPath, prometheusConfigTarget)) + prometheusConfigTargetPath, err := homedir.Expand(filepath.Join(metricsDirPath, prometheusConfigTarget)) if err != nil { return fmt.Errorf("error expanding Prometheus config target path: %w", err) } @@ -89,12 +105,18 @@ func (c *HyperdriveClient) UpdatePrometheusConfiguration(config *GlobalConfig) e // Load the Grafana config template, do a template variable substitution, and save it func (c *HyperdriveClient) UpdateGrafanaDatabaseConfiguration(config *GlobalConfig) error { + // Make sure the metrics path exists + metricsDirPath, err := createMetricsDir(c.Context.ConfigPath) + if err != nil { + return err + } + grafanaConfigTemplatePath, err := homedir.Expand(filepath.Join(templatesDir, grafanaConfigTemplate)) if err != nil { return fmt.Errorf("error expanding Grafana config template path: %w", err) } - grafanaConfigTargetPath, err := homedir.Expand(filepath.Join(c.Context.ConfigPath, grafanaConfigTarget)) + grafanaConfigTargetPath, err := homedir.Expand(filepath.Join(metricsDirPath, grafanaConfigTarget)) if err != nil { return fmt.Errorf("error expanding Grafana config target path: %w", err) } @@ -106,3 +128,13 @@ func (c *HyperdriveClient) UpdateGrafanaDatabaseConfiguration(config *GlobalConf return t.Write(config) } + +// Create the metrics directory +func createMetricsDir(cfgPath string) (string, error) { + metricsDirPath := filepath.Join(cfgPath, metricsDir) + err := os.MkdirAll(metricsDirPath, metricsDirMode) + if err != nil { + return "", fmt.Errorf("error creating metrics directory [%s]: %w", metricsDirPath, err) + } + return metricsDirPath, nil +} diff --git a/hyperdrive-cli/client/global-config.go b/hyperdrive-cli/client/global-config.go index 6614239d..fdb8b5a8 100644 --- a/hyperdrive-cli/client/global-config.go +++ b/hyperdrive-cli/client/global-config.go @@ -11,15 +11,16 @@ import ( // Wrapper for global configuration type GlobalConfig struct { + ExternalIP string Hyperdrive *hdconfig.HyperdriveConfig - Stakewise *swconfig.StakewiseConfig + Stakewise *swconfig.StakeWiseConfig } // Make a new global config func NewGlobalConfig(hdCfg *hdconfig.HyperdriveConfig) *GlobalConfig { cfg := &GlobalConfig{ Hyperdrive: hdCfg, - Stakewise: swconfig.NewStakewiseConfig(hdCfg), + Stakewise: swconfig.NewStakeWiseConfig(hdCfg), } for _, module := range cfg.GetAllModuleConfigs() { @@ -64,7 +65,7 @@ func (c *GlobalConfig) CreateCopy() *GlobalConfig { hdCopy := c.Hyperdrive.Clone() // Stakewise - swCopy := c.Stakewise.Clone().(*swconfig.StakewiseConfig) + swCopy := c.Stakewise.Clone().(*swconfig.StakeWiseConfig) return &GlobalConfig{ Hyperdrive: hdCopy, @@ -198,6 +199,27 @@ func (c *GlobalConfig) GetChanges(oldConfig *GlobalConfig) ([]*config.ChangedSec return sectionList, changedContainers, changeNetworks } +// Attempts to load the system's external IP address +func (c *GlobalConfig) LoadExternalIP() { + if c.ExternalIP != "" { + return + } + + // Get the external IP address + ip, err := config.GetExternalIP() + if err != nil { + fmt.Println("Warning: couldn't get external IP address; if you're using Nimbus, Besu, or Teku, it may have trouble finding peers:") + fmt.Println(err.Error()) + return + } + + if ip.To4() == nil { + fmt.Println("Warning: external IP address is v6; if you're using Nimbus, Besu, or Teku, it may have trouble finding peers.") + } + + c.ExternalIP = ip.String() +} + // Compare two config sections and see what's changed between them, generating a ChangedSection for the results. func getChanges( oldConfig config.IConfigSection, diff --git a/hyperdrive-cli/client/service.go b/hyperdrive-cli/client/service.go index f048d19f..e3d71d41 100644 --- a/hyperdrive-cli/client/service.go +++ b/hyperdrive-cli/client/service.go @@ -26,7 +26,9 @@ const ( overrideSourceDir string = "/usr/share/hyperdrive/override" overrideDir string = "override" runtimeDir string = "runtime" + metricsDir string = "metrics" extraScrapeJobsDir string = "extra-scrape-jobs" + modulePrometheusSd string = "prometheus-sd" ) // Install Hyperdrive @@ -269,8 +271,8 @@ func (c *HyperdriveClient) GetServiceVersion() (string, error) { return version.String(), nil } -// Deletes the data directory, including the node wallet and all validator keys, and restarts the Docker containers -func (c *HyperdriveClient) PurgeData(composeFiles []string) error { +// Deletes the data directory, including the node wallet and all validator keys, and restarts the Docker containers if requested +func (c *HyperdriveClient) PurgeData(composeFiles []string, restart bool) error { // Get the command to run with root privileges rootCmd, err := c.getEscalationCommand() if err != nil { @@ -302,11 +304,13 @@ func (c *HyperdriveClient) PurgeData(composeFiles []string) error { return fmt.Errorf("error deleting data: %w", err) } - // Start the containers - fmt.Println("Starting containers...") - err = c.StartService(composeFiles) - if err != nil { - return fmt.Errorf("error starting Docker containers: %w", err) + if restart { + // Start the containers + fmt.Println("Starting containers...") + err = c.StartService(composeFiles) + if err != nil { + return fmt.Errorf("error starting Docker containers: %w", err) + } } fmt.Println("Purge complete.") diff --git a/hyperdrive-cli/client/template/compose-file.go b/hyperdrive-cli/client/template/compose-file.go index ef7f35d0..bfdd1762 100644 --- a/hyperdrive-cli/client/template/compose-file.go +++ b/hyperdrive-cli/client/template/compose-file.go @@ -6,8 +6,8 @@ import ( ) const ( - templateSuffix string = ".tmpl" - composeFileSuffix string = ".yml" + TemplateSuffix string = ".tmpl" + ComposeFileSuffix string = ".yml" ) type ComposePaths struct { @@ -32,18 +32,18 @@ func (c *ComposePaths) File(name string) *ComposeFile { // from the TemplatePath, populate and save to the RuntimePath, and return a // slice of compose definitions pertaining to the container (including the override). func (c *ComposeFile) Write(data interface{}) ([]string, error) { - composePath := filepath.Join(c.paths.RuntimePath, c.name+composeFileSuffix) + composePath := filepath.Join(c.paths.RuntimePath, c.name+ComposeFileSuffix) tmpl := Template{ - Src: filepath.Join(c.paths.TemplatePath, c.name+templateSuffix), + Src: filepath.Join(c.paths.TemplatePath, c.name+TemplateSuffix), Dst: composePath, } err := tmpl.Write(data) if err != nil { - return nil, fmt.Errorf("Error writing %s compose definition: %w", c.name, err) + return nil, fmt.Errorf("error writing %s compose definition: %w", c.name, err) } return []string{ composePath, - filepath.Join(c.paths.OverridePath, c.name+composeFileSuffix), + filepath.Join(c.paths.OverridePath, c.name+ComposeFileSuffix), }, nil } diff --git a/hyperdrive-cli/commands/service/config.go b/hyperdrive-cli/commands/service/config.go index dd6e1a7e..9033f2a4 100644 --- a/hyperdrive-cli/commands/service/config.go +++ b/hyperdrive-cli/commands/service/config.go @@ -138,7 +138,7 @@ func configureService(c *cli.Context) error { for _, container := range md.ContainersToRestart { fullName := fmt.Sprintf("%s_%s", prefix, container) if !runningContainers[fullName] { - fmt.Printf("%s is not currently running.", fullName) + fmt.Printf("%s is not currently running.\n", fullName) } else { fmt.Printf("Stopping %s... ", fullName) err := hd.StopContainer(fullName) diff --git a/hyperdrive-cli/commands/service/config/review-page.go b/hyperdrive-cli/commands/service/config/review-page.go index 325cd5b5..8f9e47d2 100644 --- a/hyperdrive-cli/commands/service/config/review-page.go +++ b/hyperdrive-cli/commands/service/config/review-page.go @@ -6,6 +6,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/nodeset-org/hyperdrive-daemon/shared" + swconfig "github.com/nodeset-org/hyperdrive-stakewise/shared/config" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" "github.com/rivo/tview" "github.com/rocket-pool/node-manager-core/config" @@ -59,6 +60,13 @@ func NewReviewPage(md *mainDisplay, oldConfig *client.GlobalConfig, newConfig *c } } + // TEMP: Restart all of the module daemons if the HD daemon is being restarted + for container := range totalAffectedContainers { + if container == config.ContainerID_Daemon { + totalAffectedContainers[swconfig.ContainerID_StakewiseDaemon] = true + } + } + // Print the list of containers to restart if builder.String() == "" { builder.WriteString("") diff --git a/hyperdrive-cli/commands/service/config/settings-mev-boost.go b/hyperdrive-cli/commands/service/config/settings-mev-boost.go index 58db8714..f05dd1fa 100644 --- a/hyperdrive-cli/commands/service/config/settings-mev-boost.go +++ b/hyperdrive-cli/commands/service/config/settings-mev-boost.go @@ -18,15 +18,10 @@ type MevBoostConfigPage struct { selectionModeBox *parameterizedFormItem localItems []*parameterizedFormItem externalItems []*parameterizedFormItem - regulatedAllMevBox *parameterizedFormItem - unregulatedAllMevBox *parameterizedFormItem flashbotsBox *parameterizedFormItem bloxrouteMaxProfitBox *parameterizedFormItem bloxrouteRegulatedBox *parameterizedFormItem edenBox *parameterizedFormItem - ultrasoundBox *parameterizedFormItem - aestusBox *parameterizedFormItem - titanGlobalBox *parameterizedFormItem titanRegionalBox *parameterizedFormItem } @@ -67,6 +62,7 @@ func (configPage *MevBoostConfigPage) createContent() { configPage.selectionModeBox = createParameterizedDropDown(&configPage.masterConfig.Hyperdrive.MevBoost.SelectionMode, configPage.layout.descriptionBox) localParams := []config.IParameter{ + &configPage.masterConfig.Hyperdrive.MevBoost.CustomRelays, &configPage.masterConfig.Hyperdrive.MevBoost.Port, &configPage.masterConfig.Hyperdrive.MevBoost.OpenRpcPort, &configPage.masterConfig.Hyperdrive.MevBoost.ContainerTag, @@ -81,14 +77,11 @@ func (configPage *MevBoostConfigPage) createContent() { configPage.bloxrouteMaxProfitBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.BloxRouteMaxProfitRelay) configPage.bloxrouteRegulatedBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.BloxRouteRegulatedRelay) configPage.edenBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.EdenRelay) - configPage.ultrasoundBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.UltrasoundRelay) - configPage.aestusBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.AestusRelay) - configPage.titanGlobalBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.TitanGlobalRelay) configPage.titanRegionalBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.TitanRegionalRelay) // Map the parameters to the form items in the layout configPage.layout.mapParameterizedFormItems(configPage.enableBox, configPage.modeBox, configPage.selectionModeBox) - configPage.layout.mapParameterizedFormItems(configPage.flashbotsBox, configPage.bloxrouteMaxProfitBox, configPage.bloxrouteRegulatedBox, configPage.edenBox, configPage.ultrasoundBox, configPage.aestusBox, configPage.titanGlobalBox, configPage.titanRegionalBox) + configPage.layout.mapParameterizedFormItems(configPage.flashbotsBox, configPage.bloxrouteMaxProfitBox, configPage.bloxrouteRegulatedBox, configPage.edenBox, configPage.titanRegionalBox) configPage.layout.mapParameterizedFormItems(configPage.localItems...) configPage.layout.mapParameterizedFormItems(configPage.externalItems...) @@ -150,16 +143,7 @@ func (configPage *MevBoostConfigPage) handleSelectionModeChanged() { configPage.layout.form.AddFormItem(configPage.selectionModeBox.item) selectedMode := configPage.masterConfig.Hyperdrive.MevBoost.SelectionMode.Value switch selectedMode { - case hdconfig.MevSelectionMode_Profile: - regulatedAllMev, unregulatedAllMev := configPage.masterConfig.Hyperdrive.MevBoost.GetAvailableProfiles() - if unregulatedAllMev { - configPage.layout.form.AddFormItem(configPage.unregulatedAllMevBox.item) - } - if regulatedAllMev { - configPage.layout.form.AddFormItem(configPage.regulatedAllMevBox.item) - } - - case hdconfig.MevSelectionMode_Relay: + case hdconfig.MevSelectionMode_Manual: relays := configPage.masterConfig.Hyperdrive.MevBoost.GetAvailableRelays() for _, relay := range relays { switch relay.ID { @@ -171,12 +155,6 @@ func (configPage *MevBoostConfigPage) handleSelectionModeChanged() { configPage.layout.form.AddFormItem(configPage.bloxrouteRegulatedBox.item) case hdconfig.MevRelayID_Eden: configPage.layout.form.AddFormItem(configPage.edenBox.item) - case hdconfig.MevRelayID_Ultrasound: - configPage.layout.form.AddFormItem(configPage.ultrasoundBox.item) - case hdconfig.MevRelayID_Aestus: - configPage.layout.form.AddFormItem(configPage.aestusBox.item) - case hdconfig.MevRelayID_TitanGlobal: - configPage.layout.form.AddFormItem(configPage.titanGlobalBox.item) case hdconfig.MevRelayID_TitanRegional: configPage.layout.form.AddFormItem(configPage.titanRegionalBox.item) } @@ -188,11 +166,6 @@ func (configPage *MevBoostConfigPage) handleSelectionModeChanged() { // Handle a bulk redraw request func (configPage *MevBoostConfigPage) handleLayoutChanged() { - // Rebuild the profile boxes with the new descriptions - configPage.regulatedAllMevBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.EnableRegulatedAllMev) - configPage.unregulatedAllMevBox = createParameterizedCheckbox(&configPage.masterConfig.Hyperdrive.MevBoost.EnableUnregulatedAllMev) - configPage.layout.mapParameterizedFormItems(configPage.regulatedAllMevBox, configPage.unregulatedAllMevBox) - // Rebuild the parameter maps based on the selected network configPage.handleModeChanged() } diff --git a/hyperdrive-cli/commands/service/config/step-finished.go b/hyperdrive-cli/commands/service/config/step-finished.go index 0cfb0585..32b6e69e 100644 --- a/hyperdrive-cli/commands/service/config/step-finished.go +++ b/hyperdrive-cli/commands/service/config/step-finished.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + swconfig "github.com/nodeset-org/hyperdrive-stakewise/shared/config" "github.com/rivo/tview" "github.com/rocket-pool/node-manager-core/config" ) @@ -90,6 +91,12 @@ func processConfigAfterQuit(md *mainDisplay) { } var containersToRestart []config.ContainerID + // TEMP: Restart all of the module daemons if the HD daemon is being restarted + for container := range totalAffectedContainers { + if container == config.ContainerID_Daemon { + totalAffectedContainers[swconfig.ContainerID_StakewiseDaemon] = true + } + } for container := range totalAffectedContainers { containersToRestart = append(containersToRestart, container) } diff --git a/hyperdrive-cli/commands/service/config/step-local-mev.go b/hyperdrive-cli/commands/service/config/step-local-mev.go index 2a19fac5..48b104fc 100644 --- a/hyperdrive-cli/commands/service/config/step-local-mev.go +++ b/hyperdrive-cli/commands/service/config/step-local-mev.go @@ -1,21 +1,14 @@ package config import ( - "strings" - "github.com/nodeset-org/hyperdrive-daemon/shared/config" - nconfig "github.com/rocket-pool/node-manager-core/config" ) func createLocalMevStep(wiz *wizard, currentStep int, totalSteps int) *checkBoxWizardStep { - // Create the labels - regulatedAllLabel := strings.TrimPrefix(wiz.md.Config.Hyperdrive.MevBoost.EnableRegulatedAllMev.Name, "Enable ") - unregulatedAllLabel := strings.TrimPrefix(wiz.md.Config.Hyperdrive.MevBoost.EnableUnregulatedAllMev.Name, "Enable ") - - helperText := "Select the profiles you would like to enable below. Read the descriptions carefully! Leave all options unchecked if you wish to disable MEV-Boost.\n\n[lime]To learn more about MEV, please visit:\nhttps://docs.flashbots.net/new-to-mev\n" + helperText := "Select the relays you would like to enable below. Note that all of Hyperdrive's built-in relays support regional sanction lists (such as the US OFAC list) and are compliant with regulations. If you'd like to add your own custom relays, choose \"Review All Settings\" at the end of the wizard and go to the MEV-Boost section.\n\n[lime]To learn more about MEV, please visit:\nhttps://docs.flashbots.net/new-to-mev\n" show := func(modal *checkBoxModalLayout) { - labels, descriptions, selections := getMevChoices(wiz.md.Config.Hyperdrive.MevBoost, wiz.md.Config.Hyperdrive.Network.Value) + labels, descriptions, selections := getMevChoices(wiz.md.Config.Hyperdrive.MevBoost) modal.generateCheckboxes(labels, descriptions, selections) wiz.md.setPage(modal.page) @@ -23,19 +16,15 @@ func createLocalMevStep(wiz *wizard, currentStep int, totalSteps int) *checkBoxW } done := func(choices map[string]bool) { - wiz.md.Config.Hyperdrive.MevBoost.SelectionMode.Value = config.MevSelectionMode_Profile - wiz.md.Config.Hyperdrive.MevBoost.Enable.Value = false - atLeastOneEnabled := false - enabled, exists := choices[regulatedAllLabel] - if exists { - wiz.md.Config.Hyperdrive.MevBoost.EnableRegulatedAllMev.Value = enabled - atLeastOneEnabled = atLeastOneEnabled || enabled - } - enabled, exists = choices[unregulatedAllLabel] - if exists { - wiz.md.Config.Hyperdrive.MevBoost.EnableUnregulatedAllMev.Value = enabled - atLeastOneEnabled = atLeastOneEnabled || enabled + for label, enabled := range choices { + for _, param := range wiz.md.Config.Hyperdrive.MevBoost.GetParameters() { + if param.GetCommon().Name == "Enable "+label { + param.SetValue(enabled) + atLeastOneEnabled = atLeastOneEnabled || enabled + break + } + } } wiz.md.Config.Hyperdrive.MevBoost.Enable.Value = atLeastOneEnabled @@ -51,7 +40,7 @@ func createLocalMevStep(wiz *wizard, currentStep int, totalSteps int) *checkBoxW currentStep, totalSteps, helperText, - 90, + 80, "MEV-Boost", show, done, @@ -60,32 +49,24 @@ func createLocalMevStep(wiz *wizard, currentStep int, totalSteps int) *checkBoxW ) } -func getMevChoices(config *config.MevBoostConfig, network nconfig.Network) ([]string, []string, []bool) { +func getMevChoices(config *config.MevBoostConfig) ([]string, []string, []bool) { labels := []string{} descriptions := []string{} settings := []bool{} - regulatedAllMev, unregulatedAllMev := config.GetAvailableProfiles() - - if unregulatedAllMev { - label := strings.TrimPrefix(config.EnableUnregulatedAllMev.Name, "Enable ") + relays := config.GetAvailableRelays() + for _, relay := range relays { + label := relay.Name labels = append(labels, label) - description := config.EnableUnregulatedAllMev.DescriptionsByNetwork[network] - descriptions = append(descriptions, getDescriptionBody(description)) - settings = append(settings, config.EnableUnregulatedAllMev.Value) - } - if regulatedAllMev { - label := strings.TrimPrefix(config.EnableRegulatedAllMev.Name, "Enable ") - labels = append(labels, label) - description := config.EnableRegulatedAllMev.DescriptionsByNetwork[network] - descriptions = append(descriptions, getDescriptionBody(description)) - settings = append(settings, config.EnableRegulatedAllMev.Value) + description := relay.Description + descriptions = append(descriptions, description) + for _, parameter := range config.GetParameters() { + if parameter.GetCommon().Name == "Enable "+relay.Name { + settings = append(settings, parameter.GetValueAsAny().(bool)) + break + } + } } return labels, descriptions, settings } - -func getDescriptionBody(description string) string { - index := strings.Index(description, "Select this") - return description[index:] -} diff --git a/hyperdrive-cli/commands/service/config/step-mev-mode.go b/hyperdrive-cli/commands/service/config/step-mev-mode.go index a253caba..f59c144d 100644 --- a/hyperdrive-cli/commands/service/config/step-mev-mode.go +++ b/hyperdrive-cli/commands/service/config/step-mev-mode.go @@ -3,46 +3,70 @@ package config import ( "fmt" + hdconfig "github.com/nodeset-org/hyperdrive-daemon/shared/config" "github.com/rocket-pool/node-manager-core/config" ) func createMevModeStep(wiz *wizard, currentStep int, totalSteps int) *choiceWizardStep { // Create the button names and descriptions from the config - modes := wiz.md.Config.Hyperdrive.MevBoost.Mode.Options - modeNames := []string{} - modeDescriptions := []string{} - for _, mode := range modes { - modeNames = append(modeNames, mode.Name) - modeDescriptions = append(modeDescriptions, mode.Description) + modeNames := []string{ + "Use All Relays", + "Choose Relays", + "Externally Managed", + "Disable MEV-Boost", + } + modeDescriptions := []string{ + "Allow Hyperdrive to manage MEV-Boost for you, and subscribe to all of the built-in MEV relays. You can view the built-in relays during the manual configuration process once this wizard is finished, and add your own custom relays as well.", + "Allow Hyperdrive to manage MEV-Boost for you, but manually select which built-in relays to use. You can add your own custom relays as well.", + "Connect to an external MEV-Boost client that you manage yourself.", + "Disable MEV-Boost support. When your validators propose a block, they will use a block that your clients create by themselves.", } - helperText := "By default, Hyperdrive has MEV-Boost enabled. This allows you to capture extra profits from block proposals. Would you like Hyperdrive to manage MEV-Boost for you, or would you like to manage it yourself?\n\n[lime]To learn more about MEV, please visit:\nhttps://docs.flashbots.net/new-to-mev\n" + helperText := "Hyperdrive supports MEV-Boost, which allows you to capture extra profits from your validator's block proposals. If you'd like to use it, Hyperdrive can either manage MEV-Boost for you or connect to an instance you manage yourself. How would you like to use MEV-Boost?\n\n[lime]To learn more about MEV, please visit:\nhttps://docs.flashbots.net/new-to-mev\n" show := func(modal *choiceModalLayout) { wiz.md.setPage(modal.page) modal.focus(0) // Catch-all for safety - for i, option := range wiz.md.Config.Hyperdrive.MevBoost.Mode.Options { - if option.Value == wiz.md.Config.Hyperdrive.MevBoost.Mode.Value { - modal.focus(i) - break + if !wiz.md.Config.Hyperdrive.MevBoost.Enable.Value { + modal.focus(3) + return + } + + switch wiz.md.Config.Hyperdrive.MevBoost.Mode.Value { + case config.ClientMode_Local: + switch wiz.md.Config.Hyperdrive.MevBoost.SelectionMode.Value { + case hdconfig.MevSelectionMode_All: + modal.focus(0) + case hdconfig.MevSelectionMode_Manual: + modal.focus(1) } + case config.ClientMode_External: + modal.focus(2) } } done := func(buttonIndex int, buttonLabel string) { - wiz.md.Config.Hyperdrive.MevBoost.Mode.Value = modes[buttonIndex].Value - switch modes[buttonIndex].Value { - case config.ClientMode_Local: + switch buttonIndex { + case 0: + wiz.md.Config.Hyperdrive.MevBoost.Enable.Value = true + wiz.md.Config.Hyperdrive.MevBoost.Mode.Value = config.ClientMode_Local + wiz.md.Config.Hyperdrive.MevBoost.SelectionMode.Value = hdconfig.MevSelectionMode_All + wiz.finishedModal.show() + case 1: + wiz.md.Config.Hyperdrive.MevBoost.Enable.Value = true + wiz.md.Config.Hyperdrive.MevBoost.Mode.Value = config.ClientMode_Local + wiz.md.Config.Hyperdrive.MevBoost.SelectionMode.Value = hdconfig.MevSelectionMode_Manual wiz.localMevModal.show() - case config.ClientMode_External: - if wiz.md.Config.Hyperdrive.IsLocalMode() { - wiz.externalMevModal.show() - } else { - wiz.finishedModal.show() - } + case 2: + wiz.md.Config.Hyperdrive.MevBoost.Enable.Value = true + wiz.md.Config.Hyperdrive.MevBoost.Mode.Value = config.ClientMode_External + wiz.externalMevModal.show() + case 3: + wiz.md.Config.Hyperdrive.MevBoost.Enable.Value = false + wiz.finishedModal.show() default: - panic(fmt.Sprintf("Unknown MEV mode %s", modes[buttonIndex].Value)) + panic(fmt.Sprintf("Unhandled value %d", buttonIndex)) } } diff --git a/hyperdrive-cli/commands/service/install.go b/hyperdrive-cli/commands/service/install.go index bc0ffaed..95721d6a 100644 --- a/hyperdrive-cli/commands/service/install.go +++ b/hyperdrive-cli/commands/service/install.go @@ -102,6 +102,15 @@ func printPatchNotes() { fmt.Printf("%s=== Hyperdrive v%s ===%s\n\n", terminal.ColorGreen, shared.HyperdriveVersion, terminal.ColorReset) fmt.Printf("Changes you should be aware of before starting:\n\n") - fmt.Printf("%s=== Stakewise Module ===%s\n", terminal.ColorGreen, terminal.ColorReset) - fmt.Println("Stakewise functions now initialize the Stakewise wallet if it's missing instead of erroring out.") + fmt.Printf("%s=== Mainnet Support! ===%s\n", terminal.ColorGreen, terminal.ColorReset) + fmt.Println("This version of Hyperdrive supports the Ethereum Mainnet. You can now access the Gravita vault if you're a StakeWise module user and stake ETH on Gravita's behalf.") + fmt.Println() + + fmt.Printf("%s=== NodeSet Service ===%s\n", terminal.ColorGreen, terminal.ColorReset) + fmt.Println("Fixed a race condition that caused Hyperdrive to occasionally state your node wasn't registered when it was. The whole registration checking process should be greatly improved now.") + fmt.Println() + + fmt.Printf("%s=== MEV-Boost Overhaul ===%s\n", terminal.ColorGreen, terminal.ColorReset) + fmt.Println("The list of MEV-Boost built-in relays has been adjusted and only includes regulated relays due to liability concerns. Hyperdrive now includes a \"Custom Relays\" box that allows you to add your own relay URLs that MEV-Boost will use in addition to any built-in ones that you enable.") + fmt.Println() } diff --git a/hyperdrive-cli/commands/service/start.go b/hyperdrive-cli/commands/service/start.go index c38d1dd0..498c9576 100644 --- a/hyperdrive-cli/commands/service/start.go +++ b/hyperdrive-cli/commands/service/start.go @@ -70,7 +70,7 @@ func startService(c *cli.Context, ignoreConfigSuggestion bool) error { // Validate the config errors := cfg.Validate() if len(errors) > 0 { - fmt.Printf("%sYour configuration encountered errors. You must correct the following in order to start Hyperdrive:\n\n", terminal.ColorRed) + fmt.Printf("%sYour configuration encountered errors. You must correct the following by changing the settings with `hyperdrive service config` in order to start Hyperdrive:\n\n", terminal.ColorRed) for _, err := range errors { fmt.Printf("%s\n\n", err) } @@ -181,12 +181,16 @@ func startService(c *cli.Context, ignoreConfigSuggestion bool) error { return err } - // Get NodeSet registration status + // Get NodeSet registration status if this isn't a new wallet + isExistingWallet := status.Wallet.IsLoaded || status.Wallet.IsOnDisk + if !isExistingWallet { + return nil + } fmt.Println() fmt.Println("Checking node registration status...") retries = 5 for i := 0; i < retries; i++ { - err = nodeset.CheckRegistrationStatus(c, hd, sw) + _, err = nodeset.CheckRegistrationStatus(c, hd, sw) if err != nil { time.Sleep(time.Second) continue diff --git a/hyperdrive-cli/commands/service/utils.go b/hyperdrive-cli/commands/service/utils.go index 69c7f1aa..9b84d1eb 100644 --- a/hyperdrive-cli/commands/service/utils.go +++ b/hyperdrive-cli/commands/service/utils.go @@ -23,43 +23,31 @@ func getComposeFiles(c *cli.Context) []string { } // Handle a network change by terminating the service, deleting everything, and starting over -// TODO func changeNetworks(c *cli.Context, hd *client.HyperdriveClient) error { - return fmt.Errorf("NYI") - - /* - // Stop all of the containers - fmt.Print("Stopping containers... ") - err := hd.PauseService(getComposeFiles(c)) - if err != nil { - return fmt.Errorf("error stopping service: %w", err) - } - fmt.Println("done") - - // Delete the data folder - fmt.Print("Removing data folder... ") - _, err = hd.Api.Service.TerminateDataFolder() - if err != nil { - return err - } - fmt.Println("done") - - // Terminate the current setup - fmt.Print("Removing old installation... ") - err = hd.StopService(getComposeFiles(c)) - if err != nil { - return fmt.Errorf("error terminating old installation: %w", err) - } - fmt.Println("done") - - // Start the service - fmt.Print("Starting Hyperdrive... ") - err = hd.StartService(getComposeFiles(c)) - if err != nil { - return fmt.Errorf("error starting service: %w", err) - } - fmt.Println("done") - - return nil - */ + composeFiles := getComposeFiles(c) + + // Purge the data folder + fmt.Print("Purging data folder... ") + err := hd.PurgeData(composeFiles, false) + if err != nil { + return fmt.Errorf("error purging data folder: %w", err) + } + + // Terminate the current setup + fmt.Print("Removing old installation... ") + err = hd.StopService(composeFiles) + if err != nil { + return fmt.Errorf("error terminating old installation: %w", err) + } + fmt.Println("done") + + // Start the service + fmt.Print("Starting Hyperdrive... ") + err = hd.StartService(getComposeFiles(c)) + if err != nil { + return fmt.Errorf("error starting service: %w", err) + } + fmt.Println("done") + + return nil } diff --git a/hyperdrive-cli/commands/stakewise/nodeset/commands.go b/hyperdrive-cli/commands/stakewise/nodeset/commands.go index 38ec9c63..ffd07583 100644 --- a/hyperdrive-cli/commands/stakewise/nodeset/commands.go +++ b/hyperdrive-cli/commands/stakewise/nodeset/commands.go @@ -30,8 +30,10 @@ func RegisterCommands(cmd *cli.Command, name string, aliases []string) { { Name: "upload-deposit-data", Aliases: []string{"u"}, - Flags: []cli.Flag{}, - Usage: "Uploads the combined deposit data for all of your validator keys to NodeSet's Stakewise vault, so they can be assigned new deposits.", + Flags: []cli.Flag{ + utils.YesFlag, + }, + Usage: "Uploads the combined deposit data for all of your validator keys to NodeSet's Stakewise vault, so they can be assigned new deposits.", Action: func(c *cli.Context) error { // Validate args utils.ValidateArgCount(c, 0) @@ -55,6 +57,22 @@ func RegisterCommands(cmd *cli.Command, name string, aliases []string) { return registerNode(c) }, }, + { + Name: "generate-deposit-data", + Aliases: []string{"g"}, + Flags: []cli.Flag{ + generatePubkeyFlag, + generateIndentFlag, + }, + Usage: "Generates and prints the deposit data for your validators without uploading it to NodeSet. Useful for debugging.", + Action: func(c *cli.Context) error { + // Validate args + utils.ValidateArgCount(c, 0) + + // Run + return generateDepositData(c) + }, + }, }, }) } diff --git a/hyperdrive-cli/commands/stakewise/nodeset/generate-deposit-data.go b/hyperdrive-cli/commands/stakewise/nodeset/generate-deposit-data.go new file mode 100644 index 00000000..a70495f3 --- /dev/null +++ b/hyperdrive-cli/commands/stakewise/nodeset/generate-deposit-data.go @@ -0,0 +1,72 @@ +package nodeset + +import ( + "fmt" + + "github.com/goccy/go-json" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/rocket-pool/node-manager-core/beacon" + "github.com/urfave/cli/v2" +) + +var ( + generatePubkeyFlag *cli.StringSliceFlag = &cli.StringSliceFlag{ + Name: "pubkey", + Aliases: []string{"p"}, + Usage: "The pubkey of the validator to generate deposit data for. Can be specified multiple times for more than one pubkey. If not specified, deposit data for all validator keys will be generated.", + } + + generateIndentFlag *cli.BoolFlag = &cli.BoolFlag{ + Name: "indent", + Aliases: []string{"i"}, + Usage: "Specify this to indent (pretty-print) the deposit data output.", + } +) + +func generateDepositData(c *cli.Context) error { + // Get the client + hd, err := client.NewHyperdriveClientFromCtx(c) + if err != nil { + return err + } + sw, err := client.NewStakewiseClientFromCtx(c, hd) + if err != nil { + return err + } + + // Parse the pubkeys + pubkeyStrings := c.StringSlice(generatePubkeyFlag.Name) + pubkeys := make([]beacon.ValidatorPubkey, len(pubkeyStrings)) + for i, pubkeyString := range pubkeyStrings { + pubkey, err := beacon.HexToValidatorPubkey(pubkeyString) + if err != nil { + return fmt.Errorf("error parsing pubkey [%s]: %w", pubkeyString, err) + } + pubkeys[i] = pubkey + } + + // Generate the deposit data + fmt.Println("Generating deposit data...") + response, err := sw.Api.Nodeset.GenerateDepositData(pubkeys) + if err != nil { + return err + } + + // Serialize the deposit data + var bytes []byte + shouldIndent := c.Bool(generateIndentFlag.Name) + if shouldIndent { + bytes, err = json.MarshalIndent(response.Data.Deposits, "", " ") + } else { + bytes, err = json.Marshal(response.Data.Deposits) + } + if err != nil { + return fmt.Errorf("error serializing deposit data: %w", err) + } + + // Print the deposit data + fmt.Println("Deposit data:") + fmt.Println() + fmt.Println(string(bytes)) + return nil +} diff --git a/hyperdrive-cli/commands/stakewise/nodeset/register-node.go b/hyperdrive-cli/commands/stakewise/nodeset/register-node.go index 4cfea7c7..baafd787 100644 --- a/hyperdrive-cli/commands/stakewise/nodeset/register-node.go +++ b/hyperdrive-cli/commands/stakewise/nodeset/register-node.go @@ -24,12 +24,12 @@ func registerNode(c *cli.Context) error { return err } - // Check if it's already registered - shouldRegister, err := checkRegistrationStatusImpl(hd, sw) + // Check if doesn't have a wallet it's already registered + hasWallet, shouldRegister, err := checkRegistrationStatusImpl(hd, sw) if err != nil { return err } - if !shouldRegister { + if !hasWallet || !shouldRegister { return nil } diff --git a/hyperdrive-cli/commands/stakewise/nodeset/registration-status.go b/hyperdrive-cli/commands/stakewise/nodeset/registration-status.go index 8476626a..29643a41 100644 --- a/hyperdrive-cli/commands/stakewise/nodeset/registration-status.go +++ b/hyperdrive-cli/commands/stakewise/nodeset/registration-status.go @@ -16,5 +16,6 @@ func registrationStatus(c *cli.Context) error { return err } - return CheckRegistrationStatus(c, hd, sw) + _, err = CheckRegistrationStatus(c, hd, sw) + return err } diff --git a/hyperdrive-cli/commands/stakewise/nodeset/upload-deposit-data.go b/hyperdrive-cli/commands/stakewise/nodeset/upload-deposit-data.go index ee7d962b..9e0508d8 100644 --- a/hyperdrive-cli/commands/stakewise/nodeset/upload-deposit-data.go +++ b/hyperdrive-cli/commands/stakewise/nodeset/upload-deposit-data.go @@ -18,6 +18,6 @@ func uploadDepositData(c *cli.Context) error { } // Upload to the server - _, err = swcmdutils.UploadDepositData(sw) + _, err = swcmdutils.UploadDepositData(c, hd, sw) return err } diff --git a/hyperdrive-cli/commands/stakewise/nodeset/utils.go b/hyperdrive-cli/commands/stakewise/nodeset/utils.go index 41380799..0b33c897 100644 --- a/hyperdrive-cli/commands/stakewise/nodeset/utils.go +++ b/hyperdrive-cli/commands/stakewise/nodeset/utils.go @@ -4,56 +4,63 @@ import ( "fmt" "net/mail" + swapi "github.com/nodeset-org/hyperdrive-stakewise/shared/api" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/urfave/cli/v2" ) // CheckRegistrationStatus checks the registration status of the node with NodeSet and prompts the user to register if not already done -func CheckRegistrationStatus(c *cli.Context, hd *client.HyperdriveClient, sw *client.StakewiseClient) error { +// Returns whether or not the caller should continue with its operation after this check completes, or if it should exit +func CheckRegistrationStatus(c *cli.Context, hd *client.HyperdriveClient, sw *client.StakewiseClient) (bool, error) { // Check if the node is already registered - shouldRegister, err := checkRegistrationStatusImpl(hd, sw) + hasWallet, shouldRegister, err := checkRegistrationStatusImpl(hd, sw) if err != nil { - return err + return false, err } if !shouldRegister { - return nil + return hasWallet, nil } // Prompt for registration if !(c.Bool(utils.YesFlag.Name) || utils.Confirm("Would you like to register your node now?")) { fmt.Println("Cancelled.") - return nil + return false, nil } - return registerNodeImpl(c, sw) + return hasWallet, registerNodeImpl(c, sw) } // Returns true if the node should register because it hasn't yet and is able to -func checkRegistrationStatusImpl(hd *client.HyperdriveClient, sw *client.StakewiseClient) (bool, error) { - // Get wallet response - response, err := hd.Api.Wallet.Status() +func checkRegistrationStatusImpl(hd *client.HyperdriveClient, sw *client.StakewiseClient) (bool, bool, error) { + // Check wallet status + _, ready, err := utils.CheckIfWalletReady(hd) if err != nil { - return false, err + return false, false, err } - - // Make sure we have a wallet loaded - if !response.Data.WalletStatus.Wallet.IsLoaded { - fmt.Println("The node wallet has not been initialized yet. Please run `hyperdrive wallet status` to learn more.") - return false, nil + if !ready { + return false, false, nil } // Get the registration status resp, err := sw.Api.Nodeset.RegistrationStatus() if err != nil { - return false, err + return false, false, err } - if resp.Data.Registered { - fmt.Println("Your node is registered with NodeSet.") - } else { + switch resp.Data.Status { + case swapi.NodesetRegistrationStatus_Unknown: + fmt.Println("Hyperdrive couldn't check your node's registration status:") + fmt.Println(resp.Data.ErrorMessage) + fmt.Println("Please try again later.") + case swapi.NodesetRegistrationStatus_NoWallet: + fmt.Println("Your node can't be registered until you have a node wallet initialized. Please run `hyperdrive wallet init` or `hyperdrive wallet recover` first.") + case swapi.NodesetRegistrationStatus_Unregistered: fmt.Println("Your node is not currently registered with NodeSet.") + return true, true, nil + case swapi.NodesetRegistrationStatus_Registered: + fmt.Println("Your node is registered with NodeSet.") } - return !resp.Data.Registered, nil + return true, false, nil } // Registers the node with NodeSet diff --git a/hyperdrive-cli/commands/stakewise/status/get-node-status.go b/hyperdrive-cli/commands/stakewise/status/get-node-status.go index 1bf8e9ce..219d62d4 100644 --- a/hyperdrive-cli/commands/stakewise/status/get-node-status.go +++ b/hyperdrive-cli/commands/stakewise/status/get-node-status.go @@ -5,6 +5,7 @@ import ( swtypes "github.com/nodeset-org/hyperdrive-stakewise/shared/types" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/commands/stakewise/nodeset" "github.com/rocket-pool/node-manager-core/beacon" "github.com/urfave/cli/v2" ) @@ -20,6 +21,16 @@ func getNodeStatus(c *cli.Context) error { return err } + // Check the registration status first + shouldContinue, err := nodeset.CheckRegistrationStatus(c, hd, sw) + if err != nil { + return fmt.Errorf("error checking registration status: %w", err) + } + if !shouldContinue { + return nil + } + + // Get the validator statuses response, err := sw.Api.Status.GetValidatorStatuses() if err != nil { fmt.Printf("error fetching validator statuses: %v\n", err) diff --git a/hyperdrive-cli/commands/stakewise/utils/utils.go b/hyperdrive-cli/commands/stakewise/utils/utils.go index 86c80c53..e6453d19 100644 --- a/hyperdrive-cli/commands/stakewise/utils/utils.go +++ b/hyperdrive-cli/commands/stakewise/utils/utils.go @@ -4,7 +4,9 @@ import ( "fmt" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" + "github.com/urfave/cli/v2" ) func printUploadError(err error) { @@ -15,7 +17,26 @@ func printUploadError(err error) { } // Upload deposit data to the server -func UploadDepositData(sw *client.StakewiseClient) (bool, error) { +func UploadDepositData(c *cli.Context, hd *client.HyperdriveClient, sw *client.StakewiseClient) (bool, error) { + // Check wallet status + _, ready, err := utils.CheckIfWalletReady(hd) + if err != nil { + return false, err + } + if !ready { + return false, nil + } + + // Warn user prior to uploading deposit data + fmt.Println("NOTE: There is currently no way to remove a validator's deposit data from the NodeSet service once you've uploaded it. The key will be eligible for activation at any time, so this node must remain online at all times to handle activation and validation duties.") + fmt.Printf("%sIf you turn the node off, you may be removed from NodeSet for negligence of duty!%s\n", terminal.ColorYellow, terminal.ColorReset) + fmt.Println() + + if !(c.Bool(utils.YesFlag.Name) || utils.Confirm("Do you want to continue uploading your deposit data?")) { + fmt.Println("Cancelled.") + return false, nil + } + // Initial attempt to upload all deposit data fmt.Println("Uploading deposit data to the NodeSet server...") response, err := sw.Api.Nodeset.UploadDepositData() @@ -33,6 +54,15 @@ func UploadDepositData(sw *client.StakewiseClient) (bool, error) { newKeyCount := len(data.NewPubkeys) remainingKeyCount := len(data.RemainingPubkeys) + if data.InvalidWithdrawalCredentials { + fmt.Printf("%sWARNING: Your deposit data contained withdrawal credentials that do not correspond to a valid StakeWise vault. Please contact the Hyperdrive developers and report this issue.%s\n", terminal.ColorYellow, terminal.ColorReset) + return false, nil + } + if data.NotAuthorizedForMainnet { + fmt.Printf("%sWARNING: Your deposit data was rejected because you are not currently authorized to access the Mainnet vault. You will need to run on the Holesky testnet first before being given access to Mainnet.%s\n", terminal.ColorYellow, terminal.ColorReset) + return false, nil + } + if data.SufficientBalance { if newKeyCount == 0 { fmt.Printf("All of your validator keys are already registered (%s%d%s in total).\n", terminal.ColorGreen, data.TotalCount, terminal.ColorReset) @@ -45,7 +75,7 @@ func UploadDepositData(sw *client.StakewiseClient) (bool, error) { fmt.Println(key.HexWithPrefix()) } } else { - fmt.Println("Not all keys were uploaded due to insufficient balance.") + fmt.Printf("%sWarning: not all keys were uploaded due to insufficient balance.%s\n", terminal.ColorYellow, terminal.ColorReset) fmt.Printf("Current wallet balance: %s%f%s\n", terminal.ColorGreen, data.Balance, terminal.ColorReset) fmt.Printf("Remaining unregistered keys: %s%d%s\n", terminal.ColorGreen, remainingKeyCount, terminal.ColorReset) fmt.Printf("You need %s%f%s more ETH to register your remaining keys.\n", terminal.ColorGreen, data.RemainingEthRequired, terminal.ColorReset) @@ -66,5 +96,5 @@ func UploadDepositData(sw *client.StakewiseClient) (bool, error) { fmt.Printf("%s%d%s are registered and pending activation.\n", terminal.ColorGreen, data.PendingCount, terminal.ColorReset) fmt.Printf("%s%d%s are registered and have been activated already.\n", terminal.ColorGreen, data.ActiveCount, terminal.ColorReset) - return true, nil + return newKeyCount != 0, nil } diff --git a/hyperdrive-cli/commands/stakewise/validator/exit.go b/hyperdrive-cli/commands/stakewise/validator/exit.go index aa197cb5..b259f21e 100644 --- a/hyperdrive-cli/commands/stakewise/validator/exit.go +++ b/hyperdrive-cli/commands/stakewise/validator/exit.go @@ -41,6 +41,15 @@ func exit(c *cli.Context) error { return err } + // Check wallet status + _, ready, err := utils.CheckIfWalletReady(hd) + if err != nil { + return err + } + if !ready { + return nil + } + // Get all active validators activeValidatorResponse, err := sw.Api.Status.GetValidatorStatuses() if err != nil { diff --git a/hyperdrive-cli/commands/stakewise/wallet/claim-rewards.go b/hyperdrive-cli/commands/stakewise/wallet/claim-rewards.go index 98c11793..4bbe81eb 100644 --- a/hyperdrive-cli/commands/stakewise/wallet/claim-rewards.go +++ b/hyperdrive-cli/commands/stakewise/wallet/claim-rewards.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/tx" "github.com/rocket-pool/node-manager-core/eth" "github.com/urfave/cli/v2" @@ -22,6 +23,15 @@ func claimRewards(c *cli.Context) error { return err } + // Check if there's a node address ready + _, ready, err := utils.CheckIfAddressReady(hd) + if err != nil { + return err + } + if !ready { + return nil + } + // Get the list of rewards available resp, err := sw.Api.Wallet.ClaimRewards() if err != nil { @@ -29,14 +39,14 @@ func claimRewards(c *cli.Context) error { } fmt.Println("Your withdrawable rewards:") fmt.Printf("%.4f %s (%s)\n", eth.WeiToEth(resp.Data.WithdrawableToken), resp.Data.TokenSymbol, resp.Data.TokenName) - fmt.Printf("%.4f ETH\n", eth.WeiToEth(resp.Data.WithdrawableEth)) + fmt.Printf("%.4f ETH\n", eth.WeiToEth(resp.Data.WithdrawableNativeToken)) fmt.Println() - fmt.Println("NOTE: this list only shows rewards that Stakewise has already returned to NodeSet. Your share may include more rewards, but Stakewise hasn't returned yet.") + fmt.Println("NOTE: this list only shows rewards that StakeWise has already returned to NodeSet. Your share may include more rewards, but StakeWise hasn't returned yet.") fmt.Println() // Check if both balances are zero sum := big.NewInt(0) - sum.Add(sum, resp.Data.WithdrawableEth) + sum.Add(sum, resp.Data.WithdrawableNativeToken) sum.Add(sum, resp.Data.WithdrawableToken) if sum.Cmp(common.Big0) == 0 { fmt.Println("You don't have any rewards to claim.") diff --git a/hyperdrive-cli/commands/stakewise/wallet/commands.go b/hyperdrive-cli/commands/stakewise/wallet/commands.go index d706c889..2e268c69 100644 --- a/hyperdrive-cli/commands/stakewise/wallet/commands.go +++ b/hyperdrive-cli/commands/stakewise/wallet/commands.go @@ -29,6 +29,7 @@ func RegisterCommands(cmd *cli.Command, name string, aliases []string) { Aliases: []string{"g"}, Usage: "Generate new validator keys derived from your node wallet.", Flags: []cli.Flag{ + utils.YesFlag, generateKeysCountFlag, generateKeysNoRestartFlag, }, diff --git a/hyperdrive-cli/commands/stakewise/wallet/generate-keys.go b/hyperdrive-cli/commands/stakewise/wallet/generate-keys.go index 6698fdd6..afd25dcc 100644 --- a/hyperdrive-cli/commands/stakewise/wallet/generate-keys.go +++ b/hyperdrive-cli/commands/stakewise/wallet/generate-keys.go @@ -7,6 +7,7 @@ import ( swconfig "github.com/nodeset-org/hyperdrive-stakewise/shared/config" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" swcmdutils "github.com/nodeset-org/hyperdrive/hyperdrive-cli/commands/stakewise/utils" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" cliutils "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/rocket-pool/node-manager-core/utils/input" @@ -37,21 +38,12 @@ func generateKeys(c *cli.Context) error { } noRestart := c.Bool(generateKeysNoRestartFlag.Name) - // Make sure there's a wallet loaded - response, err := hd.Api.Wallet.Status() + // Check wallet status + _, ready, err := utils.CheckIfWalletReady(hd) if err != nil { - return fmt.Errorf("error checking wallet status: %w", err) + return err } - status := response.Data.WalletStatus - if !status.Wallet.IsLoaded { - if !status.Wallet.IsOnDisk { - fmt.Println("Your node wallet has not been initialized yet. Please run `hyperdrive wallet init` first to create it, then run this again.") - return nil - } - if !status.Password.IsPasswordSaved { - fmt.Println("Your node wallet has been initialized, but Hyperdrive doesn't have a password loaded for it so it cannot be used. Please run `hyperdrive wallet set-password` to enter it, then run this command again.") - return nil - } + if !ready { return nil } @@ -121,7 +113,7 @@ func generateKeys(c *cli.Context) error { fmt.Println() // Upload to the server - newKeysUploaded, err := swcmdutils.UploadDepositData(sw) + newKeysUploaded, err := swcmdutils.UploadDepositData(c, hd, sw) if err != nil { return err } diff --git a/hyperdrive-cli/commands/stakewise/wallet/initialize.go b/hyperdrive-cli/commands/stakewise/wallet/initialize.go index dafbab7e..24834bba 100644 --- a/hyperdrive-cli/commands/stakewise/wallet/initialize.go +++ b/hyperdrive-cli/commands/stakewise/wallet/initialize.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/urfave/cli/v2" ) @@ -19,21 +20,12 @@ func initialize(c *cli.Context) error { return err } - // Make sure there's a wallet loaded - response, err := hd.Api.Wallet.Status() + // Check wallet status + _, ready, err := utils.CheckIfWalletReady(hd) if err != nil { - return fmt.Errorf("error checking wallet status: %w", err) + return err } - status := response.Data.WalletStatus - if !status.Wallet.IsLoaded { - if !status.Wallet.IsOnDisk { - fmt.Println("Your node wallet has not been initialized yet. Please run `hyperdrive wallet init` first to create it, then run this again.") - return nil - } - if !status.Password.IsPasswordSaved { - fmt.Println("Your node wallet has been initialized, but Hyperdrive doesn't have a password loaded for it so it cannot be used. Please run `hyperdrive wallet set-password` to enter it, then run this command again.") - return nil - } + if !ready { return nil } diff --git a/hyperdrive-cli/commands/wallet/commands.go b/hyperdrive-cli/commands/wallet/commands.go index 9dc6fc47..6cfeac17 100644 --- a/hyperdrive-cli/commands/wallet/commands.go +++ b/hyperdrive-cli/commands/wallet/commands.go @@ -63,7 +63,6 @@ func RegisterCommands(app *cli.App, name string, aliases []string) { initConfirmMnemonicFlag, derivationPathFlag, walletIndexFlag, - RegisterEmailFlag, }, Action: func(c *cli.Context) error { // Validate args diff --git a/hyperdrive-cli/commands/wallet/export-eth-key.go b/hyperdrive-cli/commands/wallet/export-eth-key.go index 723cf579..e517844b 100644 --- a/hyperdrive-cli/commands/wallet/export-eth-key.go +++ b/hyperdrive-cli/commands/wallet/export-eth-key.go @@ -2,8 +2,10 @@ package wallet import ( "fmt" + "os" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/rocket-pool/node-manager-core/wallet" "github.com/urfave/cli/v2" ) @@ -29,6 +31,21 @@ func exportEthKey(c *cli.Context) error { return nil } + if !hd.Context.SecureSession { + // Check if stdout is interactive + stat, err := os.Stdout.Stat() + if err != nil { + fmt.Fprintf(os.Stderr, "An error occured while determining whether or not the output is a tty: %s\n"+ + "Use 'hyperdrive --secure-session wallet export-eth-key' to bypass.\n", err.Error()) + os.Exit(1) + } + + if (stat.Mode()&os.ModeCharDevice) == os.ModeCharDevice && + !utils.ConfirmSecureSession("Exporting a wallet will print sensitive information to your screen.") { + return nil + } + } + // Get the wallet in ETH key format ethKey, err := hd.Api.Wallet.ExportEthKey() if err != nil { @@ -37,6 +54,15 @@ func exportEthKey(c *cli.Context) error { // Print wallet & return fmt.Println("Wallet in ETH Key Format:") + fmt.Println("============") + fmt.Println() fmt.Println(string(ethKey.Data.EthKeyJson)) + fmt.Println() + fmt.Println("============") + fmt.Println() + fmt.Println("Wallet password:") + fmt.Println() + fmt.Println(ethKey.Data.Password) + fmt.Println() return nil } diff --git a/hyperdrive-cli/commands/wallet/export.go b/hyperdrive-cli/commands/wallet/export.go index 4cfbb591..74bbf3b4 100644 --- a/hyperdrive-cli/commands/wallet/export.go +++ b/hyperdrive-cli/commands/wallet/export.go @@ -17,13 +17,12 @@ func exportWallet(c *cli.Context) error { return err } - // Get & check wallet status - status, err := hd.Api.Wallet.Status() + // Check wallet status + _, ready, err := utils.CheckIfWalletReady(hd) if err != nil { return err } - if !status.Data.WalletStatus.Wallet.IsLoaded { - fmt.Println("The node wallet is not loaded and ready for usage. Please run `hyperdrive wallet status` for more details.") + if !ready { return nil } @@ -32,7 +31,7 @@ func exportWallet(c *cli.Context) error { stat, err := os.Stdout.Stat() if err != nil { fmt.Fprintf(os.Stderr, "An error occured while determining whether or not the output is a tty: %s\n"+ - "Use \"hyperdrive --secure-session wallet export\" to bypass.\n", err.Error()) + "Use 'hyperdrive --secure-session wallet export' to bypass.\n", err.Error()) os.Exit(1) } @@ -50,18 +49,23 @@ func exportWallet(c *cli.Context) error { // Print wallet & return fmt.Println("Node account private key:") - fmt.Println("") + fmt.Println() fmt.Println(nutils.EncodeHexWithPrefix(export.Data.AccountPrivateKey)) - fmt.Println("") - fmt.Println("Wallet password:") - fmt.Println("") - fmt.Println(export.Data.Password) - fmt.Println("") + fmt.Println() fmt.Println("Wallet file:") fmt.Println("============") - fmt.Println("") + fmt.Println() fmt.Println(export.Data.Wallet) - fmt.Println("") + fmt.Println() fmt.Println("============") + fmt.Println() + fmt.Println("Wallet password:") + fmt.Println() + if export.Data.Password == "" { + fmt.Println("") + } else { + fmt.Println(export.Data.Password) + } + fmt.Println() return nil } diff --git a/hyperdrive-cli/commands/wallet/init.go b/hyperdrive-cli/commands/wallet/init.go index 4f2b84e0..081ac9cf 100644 --- a/hyperdrive-cli/commands/wallet/init.go +++ b/hyperdrive-cli/commands/wallet/init.go @@ -2,6 +2,7 @@ package wallet import ( "fmt" + "log/slog" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" @@ -50,6 +51,16 @@ func InitWallet(c *cli.Context, hd *client.HyperdriveClient) error { return fmt.Errorf("error getting Hyperdrive configuration: %w", err) } + // Print a debug log warning + if cfg.Hyperdrive.Logging.Level.Value == slog.LevelDebug { + fmt.Printf("%sWARNING: You have debug logging enabled. Your node's wallet password will be saved to the log file if you run this command.%s\n\n", terminal.ColorRed, terminal.ColorReset) + if !utils.Confirm("Are you sure you want to continue?") { + fmt.Println("Cancelled.") + return nil + } + fmt.Println() + } + // Prompt for user confirmation before printing sensitive information if !(hd.Context.SecureSession || utils.ConfirmSecureSession("Creating a wallet will print sensitive information to your screen.")) { @@ -121,7 +132,7 @@ func InitWallet(c *cli.Context, hd *client.HyperdriveClient) error { fmt.Println("The node wallet was successfully initialized.") fmt.Printf("Node account: %s%s%s\n", terminal.ColorBlue, response.Data.AccountAddress.Hex(), terminal.ColorReset) - // Initialize the Stakewise wallet if it's enabled + // Initialize the StakeWise wallet if it's enabled if cfg.Stakewise.Enabled.Value { fmt.Println() fmt.Println("You have the Stakewise module enabled. Initializing it with your new wallet...") @@ -134,22 +145,8 @@ func InitWallet(c *cli.Context, hd *client.HyperdriveClient) error { return fmt.Errorf("error initializing Stakewise wallet: %w", err) } fmt.Println("Stakewise wallet initialized.") - - registrationStatusResp, err := sw.Api.Nodeset.RegistrationStatus() - if err != nil { - return err - } - if !registrationStatusResp.Data.Registered && utils.Confirm("Would you like to upload your validator keys to NodeSet?") { - if c.String(RegisterEmailFlag.Name) == "" { - fmt.Printf("Please provide an email address with the %s flag.\n", RegisterEmailFlag.Name) - fmt.Printf("You can register your validator with `hyperdrive stakewise nodeset register-node`.\n") - return nil - } - _, err := sw.Api.Nodeset.RegisterNode(c.String(RegisterEmailFlag.Name)) - if err != nil { - return err - } - } + fmt.Println() + fmt.Println("Please whitelist your node on your `nodeset.io` dashboard, then register it with `hyperdrive sw ns register`.") } return nil } diff --git a/hyperdrive-cli/commands/wallet/masquerade.go b/hyperdrive-cli/commands/wallet/masquerade.go index 276776b0..4e8ed1be 100644 --- a/hyperdrive-cli/commands/wallet/masquerade.go +++ b/hyperdrive-cli/commands/wallet/masquerade.go @@ -25,7 +25,7 @@ func masquerade(c *cli.Context) error { return err } - fmt.Printf("Masquerading allows you to set your node address to any address you want. Your daemon will \"pretend\" to be that node, and all commands will act as though your node wallet is for that address. Since you don't have the private key for that address, you can't submit transactions or sign messages though; your node will be in %sread-only mode%s until you end the masquerade with `hyperdrive wallet restore-address`.\n\n", terminal.ColorYellow, terminal.ColorReset) + fmt.Printf("Masquerading allows you to set your node address to any address you want. Your node will \"pretend\" to have that address, and most commands will act as though your node wallet is for that address. Since you don't have the private key for that address, you can't submit transactions or sign messages though; your node will be in %sread-only mode%s until you end the masquerade with `hyperdrive wallet restore-address`.\n\n", terminal.ColorYellow, terminal.ColorReset) // Get the address addressString := c.String(masqueradeAddressFlag.Name) diff --git a/hyperdrive-cli/commands/wallet/purge.go b/hyperdrive-cli/commands/wallet/purge.go index 2751c96c..37c15f59 100644 --- a/hyperdrive-cli/commands/wallet/purge.go +++ b/hyperdrive-cli/commands/wallet/purge.go @@ -23,7 +23,7 @@ func purge(c *cli.Context) error { // Purge composeFiles := c.StringSlice(utils.ComposeFileFlag.Name) - err = hd.PurgeData(composeFiles) + err = hd.PurgeData(composeFiles, true) if err != nil { return fmt.Errorf("%w\n%sTHERE WAS AN ERROR DELETING YOUR KEYS. They most likely have not been deleted. Proceed with caution.%s", err, terminal.ColorRed, terminal.ColorReset) } diff --git a/hyperdrive-cli/commands/wallet/recover.go b/hyperdrive-cli/commands/wallet/recover.go index b9422646..2ffe4f61 100644 --- a/hyperdrive-cli/commands/wallet/recover.go +++ b/hyperdrive-cli/commands/wallet/recover.go @@ -2,9 +2,11 @@ package wallet import ( "fmt" + "log/slog" "strings" "github.com/ethereum/go-ethereum/common" + swapi "github.com/nodeset-org/hyperdrive-stakewise/shared/api" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" @@ -18,6 +20,12 @@ func recoverWallet(c *cli.Context) error { return err } + // Get the config + cfg, _, err := hd.LoadConfig() + if err != nil { + return fmt.Errorf("error getting Hyperdrive configuration: %w", err) + } + // Get & check wallet status statusResponse, err := hd.Api.Wallet.Status() if err != nil { @@ -29,6 +37,16 @@ func recoverWallet(c *cli.Context) error { return nil } + // Print a debug log warning + if cfg.Hyperdrive.Logging.Level.Value == slog.LevelDebug { + fmt.Printf("%sWARNING: You have debug logging enabled. Your mnemonic and node wallet password will be saved to the log file if you run this command.%s\n\n", terminal.ColorRed, terminal.ColorReset) + if !utils.Confirm("Are you sure you want to continue?") { + fmt.Println("Cancelled.") + return nil + } + fmt.Println() + } + // Prompt a notice about test recovery fmt.Printf("%sNOTE:\nThis command will restore your node wallet's private key.\nIf you just want to test recovery to ensure it works without actually regenerating the files, please use `hyperdrive wallet test-recovery` instead.%s\n\n", terminal.ColorYellow, terminal.ColorReset) @@ -102,5 +120,42 @@ func recoverWallet(c *cli.Context) error { fmt.Printf("Node account: %s\n", response.Data.AccountAddress.Hex()) } + // Initialize the StakeWise wallet if it's enabled + if cfg.Stakewise.Enabled.Value { + fmt.Println() + fmt.Println("You have the Stakewise module enabled. Initializing it with your new wallet...") + sw, err := client.NewStakewiseClientFromCtx(c, hd) + if err != nil { + return err + } + _, err = sw.Api.Wallet.Initialize() + if err != nil { + return fmt.Errorf("error initializing Stakewise wallet: %w", err) + } + fmt.Println("Stakewise wallet initialized.") + fmt.Println() + + // Check if the wallet is registered with NodeSet + regResponse, err := sw.Api.Nodeset.RegistrationStatus() + if err != nil { + fmt.Println("Hyperdrive couldn't check your node's registration status:") + fmt.Println(err.Error()) + fmt.Println("If your node isn't registered yet, you'll have to register it later.") + return nil + } + switch regResponse.Data.Status { + case swapi.NodesetRegistrationStatus_Registered: + fmt.Println("Your node is already registered with NodeSet.") + + case swapi.NodesetRegistrationStatus_Unregistered: + fmt.Println("Please whitelist your node on your `nodeset.io` dashboard, then register it with `hyperdrive sw ns register`.") + + case swapi.NodesetRegistrationStatus_Unknown: + fmt.Println("Hyperdrive couldn't check your node's registration status:") + fmt.Println(regResponse.Data.ErrorMessage) + fmt.Println("If your node isn't registered yet, you'll have to register it later.") + } + + } return nil } diff --git a/hyperdrive-cli/commands/wallet/send-message.go b/hyperdrive-cli/commands/wallet/send-message.go index a3aeda37..d899e1ff 100644 --- a/hyperdrive-cli/commands/wallet/send-message.go +++ b/hyperdrive-cli/commands/wallet/send-message.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/tx" "github.com/rocket-pool/node-manager-core/utils/input" "github.com/urfave/cli/v2" @@ -18,6 +19,15 @@ func sendMessage(c *cli.Context, toAddressOrEns string, message []byte) error { return err } + // Check if there's a node address ready + _, ready, err := utils.CheckIfAddressReady(hd) + if err != nil { + return err + } + if !ready { + return nil + } + // Get the address var toAddress common.Address var toAddressString string diff --git a/hyperdrive-cli/commands/wallet/send.go b/hyperdrive-cli/commands/wallet/send.go index f0e674f2..27586c7d 100644 --- a/hyperdrive-cli/commands/wallet/send.go +++ b/hyperdrive-cli/commands/wallet/send.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/tx" "github.com/rocket-pool/node-manager-core/eth" @@ -22,6 +23,15 @@ func nodeSend(c *cli.Context, amount float64, token string, toAddressOrEns strin return err } + // Check if there's a node address ready + _, ready, err := utils.CheckIfAddressReady(hd) + if err != nil { + return err + } + if !ready { + return nil + } + // Get amount in wei amountWei := eth.EthToWei(amount) diff --git a/hyperdrive-cli/commands/wallet/set-ens-name.go b/hyperdrive-cli/commands/wallet/set-ens-name.go index 9a7871e4..d0c3ba5d 100644 --- a/hyperdrive-cli/commands/wallet/set-ens-name.go +++ b/hyperdrive-cli/commands/wallet/set-ens-name.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/tx" "github.com/urfave/cli/v2" @@ -16,6 +17,15 @@ func setEnsName(c *cli.Context, name string) error { return err } + // Check if there's a node address ready + _, ready, err := utils.CheckIfAddressReady(hd) + if err != nil { + return err + } + if !ready { + return nil + } + fmt.Printf("This will confirm the node's ENS name as '%s'.\n\n%sNOTE: to confirm your name, you must first register it with the ENS application at https://app.ens.domains.\nWe recommend using a hardware wallet as the base domain, and registering your node as a subdomain of it.%s\n\n", name, terminal.ColorYellow, terminal.ColorReset) // Build the TX diff --git a/hyperdrive-cli/commands/wallet/set-password.go b/hyperdrive-cli/commands/wallet/set-password.go index d32fac9e..ba657c65 100644 --- a/hyperdrive-cli/commands/wallet/set-password.go +++ b/hyperdrive-cli/commands/wallet/set-password.go @@ -2,9 +2,11 @@ package wallet import ( "fmt" + "log/slog" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/rocket-pool/node-manager-core/utils/input" "github.com/urfave/cli/v2" ) @@ -16,6 +18,12 @@ func setPassword(c *cli.Context) error { return err } + // Get the config + cfg, _, err := hd.LoadConfig() + if err != nil { + return fmt.Errorf("error getting Hyperdrive configuration: %w", err) + } + // Get & check wallet status statusResponse, err := hd.Api.Wallet.Status() if err != nil { @@ -31,6 +39,20 @@ func setPassword(c *cli.Context) error { } fmt.Println("The node wallet is loaded, but the password is not saved to disk.") } + if !status.Wallet.IsOnDisk { + fmt.Println("The node wallet has not been initialized yet. Please run `hyperdrive wallet init` or `hyperdrive wallet recover` first, then run this again.") + return nil + } + + // Print a debug log warning + if cfg.Hyperdrive.Logging.Level.Value == slog.LevelDebug { + fmt.Printf("%sWARNING: You have debug logging enabled. Your node's wallet password will be saved to the log file if you run this command.%s\n\n", terminal.ColorRed, terminal.ColorReset) + if !utils.Confirm("Are you sure you want to continue?") { + fmt.Println("Cancelled.") + return nil + } + fmt.Println() + } // Get the password passwordString := c.String(PasswordFlag.Name) diff --git a/hyperdrive-cli/commands/wallet/sign-message.go b/hyperdrive-cli/commands/wallet/sign-message.go index f2dbb267..22a85669 100644 --- a/hyperdrive-cli/commands/wallet/sign-message.go +++ b/hyperdrive-cli/commands/wallet/sign-message.go @@ -6,9 +6,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/goccy/go-json" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" cliutils "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" - "github.com/rocket-pool/node-manager-core/utils" - "github.com/rocket-pool/node-manager-core/wallet" + nutils "github.com/rocket-pool/node-manager-core/utils" "github.com/urfave/cli/v2" ) @@ -38,13 +38,12 @@ func signMessage(c *cli.Context) error { return err } - // Get & check wallet status - status, err := hd.Api.Wallet.Status() + // Check wallet status + status, ready, err := utils.CheckIfWalletReady(hd) if err != nil { return err } - if !wallet.IsWalletReady(status.Data.WalletStatus) { - fmt.Println("The node wallet is not loaded or your node is in read-only mode. Please run `hyperdrive wallet status` for more details.") + if !ready { return nil } @@ -62,9 +61,9 @@ func signMessage(c *cli.Context) error { // Print the signature formattedSignature := PersonalSignature{ - Address: status.Data.WalletStatus.Wallet.WalletAddress, + Address: status.Wallet.WalletAddress, Message: message, - Signature: utils.EncodeHexWithPrefix(response.Data.SignedMessage), + Signature: nutils.EncodeHexWithPrefix(response.Data.SignedMessage), Version: fmt.Sprint(signatureVersion), } bytes, err := json.MarshalIndent(formattedSignature, "", " ") diff --git a/hyperdrive-cli/commands/wallet/status.go b/hyperdrive-cli/commands/wallet/status.go index 4b4879b8..1998ba44 100644 --- a/hyperdrive-cli/commands/wallet/status.go +++ b/hyperdrive-cli/commands/wallet/status.go @@ -20,7 +20,7 @@ func getStatus(c *cli.Context) error { // Get the config cfg, isNew, err := hd.LoadConfig() if err != nil { - return fmt.Errorf("Error loading configuration: %w", err) + return fmt.Errorf("error loading configuration: %w", err) } // Print what network we're on @@ -49,7 +49,7 @@ func getStatus(c *cli.Context) error { return nil } if !status.Password.IsPasswordSaved { - fmt.Println("The node wallet has been initialized, but Hyperdrive doesn't have a password loaded for your node wallet so it cannot be used.") + fmt.Println("The node wallet has been initialized, but Hyperdrive doesn't have a password loaded for your node wallet so it cannot be used. Please run `hyperdrive wallet set-password` to load it.") fmt.Printf("Your node is currently running as %s%s%s in %s'read-only' mode%s.\n", terminal.ColorBlue, status.Address.NodeAddress.Hex(), terminal.ColorReset, terminal.ColorYellow, terminal.ColorReset) return nil } diff --git a/hyperdrive-cli/commands/wallet/test-recovery.go b/hyperdrive-cli/commands/wallet/test-recovery.go index 1cfc23f4..fb963f6d 100644 --- a/hyperdrive-cli/commands/wallet/test-recovery.go +++ b/hyperdrive-cli/commands/wallet/test-recovery.go @@ -2,10 +2,12 @@ package wallet import ( "fmt" + "log/slog" "strings" "github.com/ethereum/go-ethereum/common" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/client" + "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils" "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/urfave/cli/v2" ) @@ -20,6 +22,22 @@ func testRecovery(c *cli.Context) error { // Prompt a notice about test recovery fmt.Printf("%sNOTE:\nThis command will test the recovery of your node wallet's private key, but will not actually write any files; it's simply a \"dry run\" of recovery.\nUse `hyperdrive wallet recover` to actually recover the wallet.%s\n\n", terminal.ColorYellow, terminal.ColorReset) + // Get the config + cfg, _, err := hd.LoadConfig() + if err != nil { + return fmt.Errorf("error getting Hyperdrive configuration: %w", err) + } + + // Print a debug log warning + if cfg.Hyperdrive.Logging.Level.Value == slog.LevelDebug { + fmt.Printf("%sWARNING: You have debug logging enabled. Your mnemonic and node wallet password will be saved to the log file if you run this command.%s\n\n", terminal.ColorRed, terminal.ColorReset) + if !utils.Confirm("Are you sure you want to continue?") { + fmt.Println("Cancelled.") + return nil + } + fmt.Println() + } + // Prompt for mnemonic var mnemonic string if c.String(mnemonicFlag.Name) != "" { diff --git a/hyperdrive-cli/utils/utils.go b/hyperdrive-cli/utils/utils.go index 857b3b28..16c62ffe 100644 --- a/hyperdrive-cli/utils/utils.go +++ b/hyperdrive-cli/utils/utils.go @@ -15,9 +15,60 @@ import ( "github.com/rocket-pool/node-manager-core/config" "github.com/rocket-pool/node-manager-core/eth" "github.com/rocket-pool/node-manager-core/utils/input" + "github.com/rocket-pool/node-manager-core/wallet" "github.com/urfave/cli/v2" ) +// Verifies the daemon has a node address ready and loaded (allows for masquerade mode support). +func CheckIfAddressReady(hd *client.HyperdriveClient) (wallet.WalletStatus, bool, error) { + // Get & check wallet status + statusResponse, err := hd.Api.Wallet.Status() + if err != nil { + return wallet.WalletStatus{}, false, err + } + status := statusResponse.Data.WalletStatus + + // There's an address ready + if status.Address.HasAddress { + if status.Address.NodeAddress != status.Wallet.WalletAddress { + fmt.Printf("%sReminder: You are currently masquerading as %s%s%s.\nYou can create transactions but cannot sign or submit them.%s\n", terminal.ColorGreen, terminal.ColorBlue, status.Address.NodeAddress, terminal.ColorGreen, terminal.ColorReset) + fmt.Println() + } + return status, true, nil + } + + // If the address isn't ready, check if the wallet's ready + if !status.Wallet.IsLoaded { + if !status.Wallet.IsOnDisk { + fmt.Println("The node wallet has not been initialized yet. Please run `hyperdrive wallet init` or `hyperdrive wallet recover` first, then run this again.") + return status, false, nil + } + fmt.Println("The daemon requires your node wallet's password to unlock it. Please run `hyperdrive wallet set-password` first, then run this again.") + return status, false, nil + } + + // The address isn't ready but the wallet is so have the user run restore-address to fix it + fmt.Printf("The node wallet is %s%s%s but the node address is not set. Please restore it with `hyperdrive wallet restore-address` or `hyperdrive wallet masquerade` first, then run this again.", terminal.ColorBlue, status.Wallet.WalletAddress, terminal.ColorReset) + return status, false, nil +} + +// Verifies the daemon has a node wallet ready and loaded. +func CheckIfWalletReady(hd *client.HyperdriveClient) (wallet.WalletStatus, bool, error) { + // Get & check wallet status + statusResponse, err := hd.Api.Wallet.Status() + if err != nil { + return wallet.WalletStatus{}, false, err + } + status := statusResponse.Data.WalletStatus + + // Check if it's already set properly and the wallet has been loaded + if !wallet.IsWalletReady(status) { + fmt.Println("The node wallet is not loaded or your node is in read-only mode. Please run `hyperdrive wallet status` for more details.") + return status, false, nil + } + return status, true, nil +} + // Print a TX's details to the console. func PrintTransactionHash(hd *client.HyperdriveClient, hash common.Hash) { finalMessage := "Waiting for the transaction to be included in a block... you may wait here for it, or press CTRL+C to exit and return to the terminal.\n\n" diff --git a/install/deploy/scripts/start-bn.sh b/install/deploy/scripts/start-bn.sh index 2ee07c3d..0f889e2a 100755 --- a/install/deploy/scripts/start-bn.sh +++ b/install/deploy/scripts/start-bn.sh @@ -63,7 +63,6 @@ if [ "$CLIENT" = "lighthouse" ]; then --eth1-blocks-per-log-query 150 \ --disable-upnp \ --staking \ - --http-allow-sync-stalled \ --execution-jwt=/secrets/jwtsecret \ --quic-port ${BN_P2P_QUIC_PORT:-8001} \ --historic-state-cache-size 2 \ @@ -292,6 +291,10 @@ if [ "$CLIENT" = "teku" ]; then CMD="$CMD --metrics-enabled=true --metrics-interface=0.0.0.0 --metrics-port=$BN_METRICS_PORT --metrics-host-allowlist=*" fi + if [ ! -z "$EXTERNAL_IP" ]; then + CMD="$CMD --p2p-advertised-ip=$EXTERNAL_IP" + fi + if [ ! -z "$CHECKPOINT_SYNC_URL" ]; then CMD="$CMD --checkpoint-sync-url=$CHECKPOINT_SYNC_URL" fi diff --git a/install/deploy/scripts/start-ec.sh b/install/deploy/scripts/start-ec.sh index b547a8a0..f25084ce 100755 --- a/install/deploy/scripts/start-ec.sh +++ b/install/deploy/scripts/start-ec.sh @@ -262,7 +262,7 @@ if [ "$CLIENT" = "besu" ]; then if [ "$BESU_ARCHIVE_MODE" = "true" ]; then CMD="$CMD --sync-mode=FULL --data-storage-format=FOREST" else - CMD="$CMD --sync-mode=SNAP --data-storage-format=BONSAI --Xbonsai-limit-trie-logs-enabled=true" + CMD="$CMD --sync-mode=SNAP --data-storage-format=BONSAI" fi if [ ! -z "$EC_MAX_PEERS" ]; then diff --git a/install/deploy/scripts/start-vc.sh b/install/deploy/scripts/start-vc.sh index a87a2501..6a1c24e7 100755 --- a/install/deploy/scripts/start-vc.sh +++ b/install/deploy/scripts/start-vc.sh @@ -46,7 +46,7 @@ if [ "$CLIENT" = "lighthouse" ]; then fi if [ "$ENABLE_MEV_BOOST" = "true" ]; then - CMD="$CMD --builder-proposals --prefer_builder_proposals" + CMD="$CMD --builder-proposals --prefer-builder-proposals" fi if [ "$ENABLE_METRICS" = "true" ]; then diff --git a/install/deploy/templates/bn.tmpl b/install/deploy/templates/bn.tmpl index f907c27f..f87a8bff 100644 --- a/install/deploy/templates/bn.tmpl +++ b/install/deploy/templates/bn.tmpl @@ -43,7 +43,7 @@ services: - BN_MAX_PEERS={{.Hyperdrive.GetBnMaxPeers}} - ENABLE_METRICS={{.Hyperdrive.Metrics.EnableMetrics}} - BN_METRICS_PORT={{.Hyperdrive.Metrics.BnMetricsPort}} - - EXTERNAL_IP={{.Hyperdrive.GetExternalIP}} + - EXTERNAL_IP={{.ExternalIP}} - CHECKPOINT_SYNC_URL={{.Hyperdrive.LocalBeaconClient.CheckpointSyncProvider}} - BN_ADDITIONAL_FLAGS={{.Hyperdrive.GetBnAdditionalFlags}} - ENABLE_BITFLY_NODE_METRICS={{.Hyperdrive.Metrics.EnableBitflyNodeMetrics}} diff --git a/install/deploy/templates/ec.tmpl b/install/deploy/templates/ec.tmpl index 7f22562f..57b98a1b 100644 --- a/install/deploy/templates/ec.tmpl +++ b/install/deploy/templates/ec.tmpl @@ -32,7 +32,7 @@ services: - EC_HTTP_PORT={{.Hyperdrive.LocalExecutionClient.HttpPort}} - EC_WS_PORT={{.Hyperdrive.LocalExecutionClient.WebsocketPort}} - EC_ENGINE_PORT={{.Hyperdrive.LocalExecutionClient.EnginePort}} - - EXTERNAL_IP={{.Hyperdrive.GetExternalIP}} + - EXTERNAL_IP={{.ExternalIP}} - ENABLE_METRICS={{.Hyperdrive.Metrics.EnableMetrics}} - EC_METRICS_PORT={{.Hyperdrive.Metrics.EcMetricsPort}} {{- /* Client-specific values */}} diff --git a/install/deploy/templates/grafana.tmpl b/install/deploy/templates/grafana.tmpl index df10b5b3..bba713b7 100644 --- a/install/deploy/templates/grafana.tmpl +++ b/install/deploy/templates/grafana.tmpl @@ -16,7 +16,7 @@ services: ports: - "{{$port}}:{{$port}}/tcp" volumes: - - "{{.Hyperdrive.GetUserDirectory}}/grafana-prometheus-datasource.yml:/etc/grafana/provisioning/datasources/prometheus.yml" + - "{{.Hyperdrive.GetUserDirectory}}/metrics/grafana-prometheus-datasource.yml:/etc/grafana/provisioning/datasources/prometheus.yml" - "grafana-storage:/var/lib/grafana" networks: - net diff --git a/install/deploy/templates/modules/stakewise/prometheus-sd.tmpl b/install/deploy/templates/modules/stakewise/prometheus-sd.tmpl new file mode 100644 index 00000000..d5655db0 --- /dev/null +++ b/install/deploy/templates/modules/stakewise/prometheus-sd.tmpl @@ -0,0 +1,5 @@ +# Target for the StakeWise VC +- labels: + job: "sw_vc" + targets: + - 'sw_vc:{{.Stakewise.VcCommon.MetricsPort}}' diff --git a/install/deploy/templates/modules/stakewise/sw_operator.tmpl b/install/deploy/templates/modules/stakewise/sw_operator.tmpl index 1c43d881..95b1c605 100644 --- a/install/deploy/templates/modules/stakewise/sw_operator.tmpl +++ b/install/deploy/templates/modules/stakewise/sw_operator.tmpl @@ -37,6 +37,8 @@ services: {{- range $network := .Hyperdrive.GetAdditionalDockerNetworks}} - {{$network}} {{- end}} + environment: + - DISABLE_DEPOSIT_DATA_WARNINGS=true cap_drop: - all cap_add: diff --git a/install/deploy/templates/prometheus-cfg.tmpl b/install/deploy/templates/prometheus-cfg.tmpl index b15717b8..20fbca37 100644 --- a/install/deploy/templates/prometheus-cfg.tmpl +++ b/install/deploy/templates/prometheus-cfg.tmpl @@ -33,6 +33,11 @@ scrape_configs: static_configs: - targets: ['{{.Hyperdrive.DaemonContainerName}}:{{or .Hyperdrive.Metrics.DaemonMetricsPort.Value "9102"}}'] + - job_name: 'modules' + file_sd_configs: + - files: + - /modules/*.yml + - job_name: 'custom_jobs' # Mandatory field, but will be ignored. file_sd_configs: - files: diff --git a/install/deploy/templates/prometheus.tmpl b/install/deploy/templates/prometheus.tmpl index 026c77a7..07cb44c3 100644 --- a/install/deploy/templates/prometheus.tmpl +++ b/install/deploy/templates/prometheus.tmpl @@ -18,7 +18,8 @@ services: {{- end}} ports: [{{.Hyperdrive.GetPrometheusOpenPorts}}] volumes: - - "{{.Hyperdrive.GetUserDirectory}}/prometheus.yml:/etc/prometheus/prometheus.yml" + - "{{.Hyperdrive.GetUserDirectory}}/metrics/prometheus.yml:/etc/prometheus/prometheus.yml" + - "{{.Hyperdrive.GetUserDirectory}}/metrics/modules:/modules" - "{{.Hyperdrive.GetUserDirectory}}/extra-scrape-jobs:/extra-scrape-jobs" - "prometheus-data:/prometheus" networks: diff --git a/install/packages/debian/debian/changelog b/install/packages/debian/debian/changelog index f60fa6af..ebfbc562 100644 --- a/install/packages/debian/debian/changelog +++ b/install/packages/debian/debian/changelog @@ -1,3 +1,20 @@ +hyperdrive (1.0.0) unstable; urgency=medium + + * Updated Besu, Geth, Reth, Lighthouse, Lodestar, and Teku. + * Added support for Mainnet. + * Fixed a race condition that caused `service start` to incorrectly state your node wasn't registered with your NodeSet account if the service was stopped before running the command. + * The MEV-Boost relay selection mode has been adjusted in preparation for Mainnet. + * Added support for Prometheus scrape targets provided by modules. + * Fixed a bug that prevented Lighthouse's VC from working with MEV-Boost enabled. + * Improved the node registration check to handle NodeSet service connection failures and race conditions. + * New command: `stakewise nodeset generate-deposit-data` can be used to print the deposit data for your validators directly instead of uploading it to the NodeSet servers, just in case you need to access it for any reason. + * Updated the StakeWise v3 Operator container. This version no longer spams the logs with warning about empty deposit data or missing validator keys, which were not applicable to NodeSet operators. + * Added support for 0xSplits v2.0, which is now used for StakeWise rewards on Holesky and will be used on Mainnet. + * The StakeWise daemon's task loop now waits for your node to be registered before trying to perform any actions that require registration. + * Uploading deposit data to NodeSet now requires both your Execution Client and Beacon Node to be synced. + + -- NodeSet LLC Thu, 20 Jun 2024 19:54:59 +0000 + hyperdrive (0.5.0~b1) unstable; urgency=medium * Updated Besu, Nimbus, Grafana, Prometheus, and Node Exporter.