diff --git a/.mockery.yaml b/.mockery.yaml index f1d971730b..9dd8273ece 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -23,6 +23,13 @@ packages: dir: ./test/mocks pkgname: mocks filename: p2p.go + github.com/evstack/ev-node/pkg/raft: + interfaces: + sourceNode: + config: + dir: ./pkg/raft + pkgname: raft + filename: node_mock.go github.com/evstack/ev-node/pkg/store: interfaces: Store: diff --git a/RELEASE.md b/RELEASE.md index fd11b700ca..e269b6680f 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -97,8 +97,8 @@ Packages must be released in the following order: These packages only depend on `core` and can be released in parallel after `core`: -2. **github.com/evstack/ev-node** - Path: `./` (root) -3. **github.com/evstack/ev-node/execution/evm** - Path: `./execution/evm` +1. **github.com/evstack/ev-node** - Path: `./` (root) +2. **github.com/evstack/ev-node/execution/evm** - Path: `./execution/evm` #### Phase 3: Application Packages diff --git a/apps/evm/cmd/run.go b/apps/evm/cmd/run.go index 08dcd8109c..38a9cfe6ea 100644 --- a/apps/evm/cmd/run.go +++ b/apps/evm/cmd/run.go @@ -25,7 +25,6 @@ import ( da "github.com/evstack/ev-node/pkg/da/types" "github.com/evstack/ev-node/pkg/genesis" genesispkg "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" "github.com/evstack/ev-node/pkg/p2p/key" "github.com/evstack/ev-node/pkg/sequencers/based" "github.com/evstack/ev-node/pkg/sequencers/single" @@ -99,11 +98,6 @@ var RunCmd = &cobra.Command{ return err } - p2pClient, err := p2p.NewClient(nodeConfig.P2P, nodeKey.PrivKey, datastore, genesis.ChainID, logger, nil) - if err != nil { - return err - } - // Start force inclusion API server if address is provided forceInclusionAddr, err := cmd.Flags().GetString(flagForceInclusionServer) if err != nil { @@ -142,7 +136,7 @@ var RunCmd = &cobra.Command{ }() } - return rollcmd.StartNode(logger, cmd, executor, sequencer, p2pClient, datastore, nodeConfig, genesis, node.NodeOptions{}) + return rollcmd.StartNode(logger, cmd, executor, sequencer, nodeKey, datastore, nodeConfig, genesis, node.NodeOptions{}) }, } diff --git a/apps/evm/go.mod b/apps/evm/go.mod index 395b5708ba..e9875a7c09 100644 --- a/apps/evm/go.mod +++ b/apps/evm/go.mod @@ -28,9 +28,11 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect github.com/StackExchange/wmi v1.2.1 // indirect + github.com/armon/go-metrics v0.4.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/boltdb/bolt v1.3.1 // indirect github.com/celestiaorg/go-libp2p-messenger v0.2.2 // indirect github.com/celestiaorg/go-square/merkle v0.0.0-20240627094109-7d01436067a3 // indirect github.com/celestiaorg/go-square/v3 v3.0.2 // indirect @@ -50,6 +52,7 @@ require ( github.com/emicklei/dot v1.6.2 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/ferranbt/fastssz v0.1.4 // indirect github.com/filecoin-project/go-clock v0.1.0 // indirect github.com/filecoin-project/go-jsonrpc v0.9.0 // indirect @@ -72,8 +75,15 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/raft v1.7.3 // indirect + github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/apps/evm/go.sum b/apps/evm/go.sum index 6e01b17c83..04e300d112 100644 --- a/apps/evm/go.sum +++ b/apps/evm/go.sum @@ -234,6 +234,8 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= @@ -242,6 +244,7 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= @@ -257,16 +260,27 @@ github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhk github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/thrift v0.17.0/go.mod h1:OLxhMRJxomX+1I/KUw03qoV3mMz16BwaKI+d4fPBx7Q= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/celestiaorg/go-libp2p-messenger v0.2.2 h1:osoUfqjss7vWTIZrrDSy953RjQz+ps/vBFE7bychLEc= @@ -295,6 +309,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -339,6 +355,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= @@ -353,6 +370,7 @@ github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56 github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= +github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -392,6 +410,8 @@ github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzF github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= @@ -418,10 +438,16 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -439,6 +465,7 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -450,6 +477,7 @@ github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= @@ -598,12 +626,31 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnV github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= 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-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/raft v1.7.3 h1:DxpEqZJysHN0wK+fviai5mFcSYsCkNpFUl1xpAW8Rbo= +github.com/hashicorp/raft v1.7.3/go.mod h1:DfvCGFxpAUPE0L4Uc8JLlTPtc3GzSbdH0MTJCLgnmJQ= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 h1:tjaIHlfKX22DCCPTx2mK+6N/kTP9DV7B3bxEUyQtjKA= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148/go.mod h1:sgCxzMuvQ3huVxgmeDdj73YIMmezWZ40HQu2IPmjJWk= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= @@ -641,6 +688,12 @@ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7Bd github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -648,6 +701,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienrbrt/go-header v0.0.0-20251008134330-747c8c192fa8 h1:F+gOiipBxG43s+Ho+ri9T8IwumjWjp1XUon4DLWjxfQ= github.com/julienrbrt/go-header v0.0.0-20251008134330-747c8c192fa8/go.mod h1:eX9iTSPthVEAlEDLux40ZT/olXPGhpxHd+mEzJeDhd0= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -662,9 +717,12 @@ github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -712,12 +770,14 @@ github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuz github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -732,6 +792,7 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= @@ -751,6 +812,9 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -779,12 +843,17 @@ github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOo github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -834,6 +903,7 @@ github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7ITo github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -844,16 +914,33 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= @@ -888,6 +975,9 @@ github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeH github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= @@ -913,6 +1003,7 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -924,8 +1015,10 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -943,10 +1036,12 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= @@ -1031,6 +1126,7 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1127,12 +1223,14 @@ golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1177,6 +1275,7 @@ golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -1254,9 +1353,12 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1266,6 +1368,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1280,6 +1383,8 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1287,6 +1392,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1298,6 +1404,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1306,6 +1413,7 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1456,6 +1564,7 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= @@ -1641,15 +1750,23 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/apps/grpc/cmd/run.go b/apps/grpc/cmd/run.go index 021a3bb8fe..9fea78d9c3 100644 --- a/apps/grpc/cmd/run.go +++ b/apps/grpc/cmd/run.go @@ -20,7 +20,6 @@ import ( da "github.com/evstack/ev-node/pkg/da/types" "github.com/evstack/ev-node/pkg/genesis" rollgenesis "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" "github.com/evstack/ev-node/pkg/p2p/key" "github.com/evstack/ev-node/pkg/sequencers/based" "github.com/evstack/ev-node/pkg/sequencers/single" @@ -87,14 +86,8 @@ The execution client must implement the Evolve execution gRPC interface.`, return err } - // Create P2P client - p2pClient, err := p2p.NewClient(nodeConfig.P2P, nodeKey.PrivKey, datastore, genesis.ChainID, logger, nil) - if err != nil { - return err - } - // Start the node - return rollcmd.StartNode(logger, cmd, executor, sequencer, p2pClient, datastore, nodeConfig, genesis, node.NodeOptions{}) + return rollcmd.StartNode(logger, cmd, executor, sequencer, nodeKey, datastore, nodeConfig, genesis, node.NodeOptions{}) }, } diff --git a/apps/grpc/go.mod b/apps/grpc/go.mod index 8e1081e02c..a92a8beb51 100644 --- a/apps/grpc/go.mod +++ b/apps/grpc/go.mod @@ -22,8 +22,10 @@ require ( require ( connectrpc.com/connect v1.19.1 // indirect connectrpc.com/grpcreflect v1.3.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/boltdb/bolt v1.3.1 // indirect github.com/celestiaorg/go-header v0.7.4 // indirect github.com/celestiaorg/go-libp2p-messenger v0.2.2 // indirect github.com/celestiaorg/go-square/merkle v0.0.0-20240627094109-7d01436067a3 // indirect @@ -37,6 +39,7 @@ require ( github.com/dgraph-io/badger/v4 v4.5.1 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/filecoin-project/go-clock v0.1.0 // indirect github.com/filecoin-project/go-jsonrpc v0.9.0 // indirect github.com/flynn/noise v1.1.0 // indirect @@ -53,8 +56,15 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/raft v1.7.3 // indirect + github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/boxo v0.35.2 // indirect diff --git a/apps/grpc/go.sum b/apps/grpc/go.sum index 02b4e7867f..5533f0be63 100644 --- a/apps/grpc/go.sum +++ b/apps/grpc/go.sum @@ -234,8 +234,11 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= @@ -247,14 +250,25 @@ github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhk github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/thrift v0.17.0/go.mod h1:OLxhMRJxomX+1I/KUw03qoV3mMz16BwaKI+d4fPBx7Q= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/celestiaorg/go-libp2p-messenger v0.2.2 h1:osoUfqjss7vWTIZrrDSy953RjQz+ps/vBFE7bychLEc= @@ -283,6 +297,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -308,8 +324,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= @@ -318,6 +336,7 @@ github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56 github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= +github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -346,6 +365,7 @@ github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87K github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU= @@ -369,10 +389,16 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -387,6 +413,7 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -396,6 +423,7 @@ github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFT github.com/goccy/go-yaml v1.19.0 h1:EmkZ9RIsX+Uq4DYFowegAuJo8+xdX3T/2dwNPXbxEYE= github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -536,12 +564,31 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4Zs github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/raft v1.7.3 h1:DxpEqZJysHN0wK+fviai5mFcSYsCkNpFUl1xpAW8Rbo= +github.com/hashicorp/raft v1.7.3/go.mod h1:DfvCGFxpAUPE0L4Uc8JLlTPtc3GzSbdH0MTJCLgnmJQ= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 h1:tjaIHlfKX22DCCPTx2mK+6N/kTP9DV7B3bxEUyQtjKA= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148/go.mod h1:sgCxzMuvQ3huVxgmeDdj73YIMmezWZ40HQu2IPmjJWk= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -573,6 +620,12 @@ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7Bd github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -580,6 +633,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienrbrt/go-header v0.0.0-20251008134330-747c8c192fa8 h1:F+gOiipBxG43s+Ho+ri9T8IwumjWjp1XUon4DLWjxfQ= github.com/julienrbrt/go-header v0.0.0-20251008134330-747c8c192fa8/go.mod h1:eX9iTSPthVEAlEDLux40ZT/olXPGhpxHd+mEzJeDhd0= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -594,9 +649,12 @@ github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -642,12 +700,14 @@ github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuz github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -659,6 +719,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= @@ -676,6 +737,9 @@ github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -704,10 +768,15 @@ github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOo github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -755,6 +824,7 @@ github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7ITo github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -765,16 +835,33 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= @@ -800,6 +887,9 @@ github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZ github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= @@ -825,6 +915,7 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -836,8 +927,10 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -851,6 +944,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -930,6 +1025,7 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1026,12 +1122,14 @@ golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1076,6 +1174,7 @@ golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -1153,9 +1252,12 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1164,6 +1266,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1178,6 +1281,8 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1185,6 +1290,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1196,6 +1302,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1204,6 +1311,7 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1354,6 +1462,7 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= @@ -1539,13 +1648,21 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/apps/testapp/cmd/run.go b/apps/testapp/cmd/run.go index 122ca92794..6fe2843bb7 100644 --- a/apps/testapp/cmd/run.go +++ b/apps/testapp/cmd/run.go @@ -18,7 +18,6 @@ import ( blobrpc "github.com/evstack/ev-node/pkg/da/jsonrpc" da "github.com/evstack/ev-node/pkg/da/types" "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" "github.com/evstack/ev-node/pkg/p2p/key" "github.com/evstack/ev-node/pkg/sequencers/based" "github.com/evstack/ev-node/pkg/sequencers/single" @@ -96,12 +95,7 @@ var RunCmd = &cobra.Command{ return err } - p2pClient, err := p2p.NewClient(nodeConfig.P2P, nodeKey.PrivKey, datastore, genesis.ChainID, logger, p2p.NopMetrics()) - if err != nil { - return err - } - - return cmd.StartNode(logger, command, executor, sequencer, p2pClient, datastore, nodeConfig, genesis, node.NodeOptions{}) + return cmd.StartNode(logger, command, executor, sequencer, nodeKey, datastore, nodeConfig, genesis, node.NodeOptions{}) }, } diff --git a/apps/testapp/go.mod b/apps/testapp/go.mod index 50691b3eea..7612018cc1 100644 --- a/apps/testapp/go.mod +++ b/apps/testapp/go.mod @@ -22,8 +22,10 @@ require ( require ( connectrpc.com/connect v1.19.1 // indirect connectrpc.com/grpcreflect v1.3.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/boltdb/bolt v1.3.1 // indirect github.com/celestiaorg/go-libp2p-messenger v0.2.2 // indirect github.com/celestiaorg/go-square/merkle v0.0.0-20240627094109-7d01436067a3 // indirect github.com/celestiaorg/go-square/v3 v3.0.2 // indirect @@ -36,6 +38,7 @@ require ( github.com/dgraph-io/badger/v4 v4.5.1 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/filecoin-project/go-clock v0.1.0 // indirect github.com/filecoin-project/go-jsonrpc v0.9.0 // indirect github.com/flynn/noise v1.1.0 // indirect @@ -52,8 +55,15 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/raft v1.7.3 // indirect + github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/boxo v0.35.2 // indirect diff --git a/apps/testapp/go.sum b/apps/testapp/go.sum index 02b4e7867f..5533f0be63 100644 --- a/apps/testapp/go.sum +++ b/apps/testapp/go.sum @@ -234,8 +234,11 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= @@ -247,14 +250,25 @@ github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhk github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/thrift v0.17.0/go.mod h1:OLxhMRJxomX+1I/KUw03qoV3mMz16BwaKI+d4fPBx7Q= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/celestiaorg/go-libp2p-messenger v0.2.2 h1:osoUfqjss7vWTIZrrDSy953RjQz+ps/vBFE7bychLEc= @@ -283,6 +297,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -308,8 +324,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= @@ -318,6 +336,7 @@ github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56 github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= +github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -346,6 +365,7 @@ github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87K github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU= @@ -369,10 +389,16 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -387,6 +413,7 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -396,6 +423,7 @@ github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFT github.com/goccy/go-yaml v1.19.0 h1:EmkZ9RIsX+Uq4DYFowegAuJo8+xdX3T/2dwNPXbxEYE= github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -536,12 +564,31 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4Zs github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/raft v1.7.3 h1:DxpEqZJysHN0wK+fviai5mFcSYsCkNpFUl1xpAW8Rbo= +github.com/hashicorp/raft v1.7.3/go.mod h1:DfvCGFxpAUPE0L4Uc8JLlTPtc3GzSbdH0MTJCLgnmJQ= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 h1:tjaIHlfKX22DCCPTx2mK+6N/kTP9DV7B3bxEUyQtjKA= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148/go.mod h1:sgCxzMuvQ3huVxgmeDdj73YIMmezWZ40HQu2IPmjJWk= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -573,6 +620,12 @@ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7Bd github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -580,6 +633,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienrbrt/go-header v0.0.0-20251008134330-747c8c192fa8 h1:F+gOiipBxG43s+Ho+ri9T8IwumjWjp1XUon4DLWjxfQ= github.com/julienrbrt/go-header v0.0.0-20251008134330-747c8c192fa8/go.mod h1:eX9iTSPthVEAlEDLux40ZT/olXPGhpxHd+mEzJeDhd0= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -594,9 +649,12 @@ github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -642,12 +700,14 @@ github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuz github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -659,6 +719,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= @@ -676,6 +737,9 @@ github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -704,10 +768,15 @@ github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOo github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -755,6 +824,7 @@ github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7ITo github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -765,16 +835,33 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= @@ -800,6 +887,9 @@ github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZ github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= @@ -825,6 +915,7 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -836,8 +927,10 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -851,6 +944,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -930,6 +1025,7 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1026,12 +1122,14 @@ golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1076,6 +1174,7 @@ golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -1153,9 +1252,12 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1164,6 +1266,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1178,6 +1281,8 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1185,6 +1290,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1196,6 +1302,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1204,6 +1311,7 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1354,6 +1462,7 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= @@ -1539,13 +1648,21 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/block/components.go b/block/components.go index eea7691a0b..5b6911015d 100644 --- a/block/components.go +++ b/block/components.go @@ -35,6 +35,17 @@ type Components struct { errorCh chan error } +// GetLastState returns the current blockchain state +func (bc *Components) GetLastState() types.State { + if bc.Executor != nil { + return bc.Executor.GetLastState() + } + if bc.Syncer != nil { + return bc.Syncer.GetLastState() + } + return types.State{} +} + // Start starts all components and monitors for critical errors. // It is blocking and returns when the context is cancelled or an error occurs func (bc *Components) Start(ctx context.Context) error { @@ -108,6 +119,11 @@ func (bc *Components) Stop() error { errs = errors.Join(errs, fmt.Errorf("failed to stop submitter: %w", err)) } } + if bc.Cache != nil { + if err := bc.Cache.SaveToDisk(); err != nil { + errs = errors.Join(errs, fmt.Errorf("failed to save caches: %w", err)) + } + } return errs } @@ -126,8 +142,8 @@ func NewSyncComponents( logger zerolog.Logger, metrics *Metrics, blockOpts BlockOptions, + raftNode common.RaftNode, ) (*Components, error) { - logger.Info().Msg("Starting in sync-mode") cacheManager, err := cache.NewManager(config, store, logger) if err != nil { return nil, fmt.Errorf("failed to create cache manager: %w", err) @@ -149,6 +165,7 @@ func NewSyncComponents( logger, blockOpts, errorCh, + raftNode, ) // Create submitter for sync nodes (no signer, only DA inclusion processing) @@ -191,8 +208,8 @@ func NewAggregatorComponents( logger zerolog.Logger, metrics *Metrics, blockOpts BlockOptions, + raftNode common.RaftNode, ) (*Components, error) { - logger.Info().Msg("Starting in aggregator-mode") cacheManager, err := cache.NewManager(config, store, logger) if err != nil { return nil, fmt.Errorf("failed to create cache manager: %w", err) @@ -215,6 +232,7 @@ func NewAggregatorComponents( logger, blockOpts, errorCh, + raftNode, ) if err != nil { return nil, fmt.Errorf("failed to create executor: %w", err) diff --git a/block/components_test.go b/block/components_test.go index d2ecfa5cf1..497f2290e7 100644 --- a/block/components_test.go +++ b/block/components_test.go @@ -99,6 +99,7 @@ func TestNewSyncComponents_Creation(t *testing.T) { zerolog.Nop(), NopMetrics(), DefaultBlockOptions(), + nil, ) require.NoError(t, err) @@ -154,6 +155,7 @@ func TestNewAggregatorComponents_Creation(t *testing.T) { zerolog.Nop(), NopMetrics(), DefaultBlockOptions(), + nil, ) require.NoError(t, err) @@ -236,6 +238,7 @@ func TestExecutor_RealExecutionClientFailure_StopsNode(t *testing.T) { zerolog.Nop(), NopMetrics(), DefaultBlockOptions(), + nil, ) require.NoError(t, err) diff --git a/block/internal/cache/manager.go b/block/internal/cache/manager.go index db022fc470..3b7698fabd 100644 --- a/block/internal/cache/manager.go +++ b/block/internal/cache/manager.go @@ -81,7 +81,9 @@ type PendingManager interface { GetPendingHeaders(ctx context.Context) ([]*types.SignedHeader, error) GetPendingData(ctx context.Context) ([]*types.SignedData, error) SetLastSubmittedHeaderHeight(ctx context.Context, height uint64) + GetLastSubmittedHeaderHeight() uint64 SetLastSubmittedDataHeight(ctx context.Context, height uint64) + GetLastSubmittedDataHeight() uint64 NumPendingHeaders() uint64 NumPendingData() uint64 } @@ -347,10 +349,18 @@ func (m *implementation) GetPendingData(ctx context.Context) ([]*types.SignedDat return signedDataList, nil } +func (m *implementation) GetLastSubmittedHeaderHeight() uint64 { + return m.pendingHeaders.GetLastSubmittedHeaderHeight() +} + func (m *implementation) SetLastSubmittedHeaderHeight(ctx context.Context, height uint64) { m.pendingHeaders.SetLastSubmittedHeaderHeight(ctx, height) } +func (m *implementation) GetLastSubmittedDataHeight() uint64 { + return m.pendingData.GetLastSubmittedDataHeight() +} + func (m *implementation) SetLastSubmittedDataHeight(ctx context.Context, height uint64) { m.pendingData.SetLastSubmittedDataHeight(ctx, height) } diff --git a/block/internal/cache/pending_base.go b/block/internal/cache/pending_base.go index ca36e999f4..f4cc4ad41a 100644 --- a/block/internal/cache/pending_base.go +++ b/block/internal/cache/pending_base.go @@ -71,6 +71,10 @@ func (pb *pendingBase[T]) numPending() uint64 { return height - pb.lastHeight.Load() } +func (pb *pendingBase[T]) getLastSubmittedHeight() uint64 { + return pb.lastHeight.Load() +} + func (pb *pendingBase[T]) setLastSubmittedHeight(ctx context.Context, newLastSubmittedHeight uint64) { lsh := pb.lastHeight.Load() if newLastSubmittedHeight > lsh && pb.lastHeight.CompareAndSwap(lsh, newLastSubmittedHeight) { diff --git a/block/internal/cache/pending_data.go b/block/internal/cache/pending_data.go index 6f75eb54aa..d7f3bbfeec 100644 --- a/block/internal/cache/pending_data.go +++ b/block/internal/cache/pending_data.go @@ -2,6 +2,7 @@ package cache import ( "context" + "errors" "github.com/rs/zerolog" @@ -28,8 +29,17 @@ type PendingData struct { base *pendingBase[*types.Data] } +var errInFlightData = errors.New("inflight data") + func fetchData(ctx context.Context, store store.Store, height uint64) (*types.Data, error) { _, data, err := store.GetBlockData(ctx, height) + if err != nil { + return nil, err + } + // in the executor, WIP data is temporary stored. skip them until the process is completed + if data.Height() == 0 { + return nil, errInFlightData + } return data, err } @@ -58,3 +68,6 @@ func (pd *PendingData) NumPendingData() uint64 { func (pd *PendingData) SetLastSubmittedDataHeight(ctx context.Context, newLastSubmittedDataHeight uint64) { pd.base.setLastSubmittedHeight(ctx, newLastSubmittedDataHeight) } +func (pd *PendingData) GetLastSubmittedDataHeight() uint64 { + return pd.base.getLastSubmittedHeight() +} diff --git a/block/internal/cache/pending_headers.go b/block/internal/cache/pending_headers.go index ab8453ec1b..b3ad795979 100644 --- a/block/internal/cache/pending_headers.go +++ b/block/internal/cache/pending_headers.go @@ -2,6 +2,7 @@ package cache import ( "context" + "errors" "github.com/rs/zerolog" @@ -25,8 +26,17 @@ type PendingHeaders struct { base *pendingBase[*types.SignedHeader] } +var errInFlightHeader = errors.New("inflight header") + func fetchSignedHeader(ctx context.Context, store storepkg.Store, height uint64) (*types.SignedHeader, error) { header, err := store.GetHeader(ctx, height) + if err != nil { + return nil, err + } + // in the executor, WIP headers are temporary stored. skip them until the process is completed + if header.Height() == 0 { + return nil, errInFlightHeader + } return header, err } @@ -55,3 +65,7 @@ func (ph *PendingHeaders) SetLastSubmittedHeaderHeight(ctx context.Context, newL func (ph *PendingHeaders) init() error { return ph.base.init() } + +func (ph *PendingHeaders) GetLastSubmittedHeaderHeight() uint64 { + return ph.base.getLastSubmittedHeight() +} diff --git a/block/internal/common/broadcaster_mock.go b/block/internal/common/broadcaster_mock.go index 2983478078..b638e6b491 100644 --- a/block/internal/common/broadcaster_mock.go +++ b/block/internal/common/broadcaster_mock.go @@ -39,6 +39,50 @@ func (_m *MockBroadcaster[H]) EXPECT() *MockBroadcaster_Expecter[H] { return &MockBroadcaster_Expecter[H]{mock: &_m.Mock} } +// Height provides a mock function for the type MockBroadcaster +func (_mock *MockBroadcaster[H]) Height() uint64 { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for Height") + } + + var r0 uint64 + if returnFunc, ok := ret.Get(0).(func() uint64); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(uint64) + } + return r0 +} + +// MockBroadcaster_Height_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Height' +type MockBroadcaster_Height_Call[H header.Header[H]] struct { + *mock.Call +} + +// Height is a helper method to define mock.On call +func (_e *MockBroadcaster_Expecter[H]) Height() *MockBroadcaster_Height_Call[H] { + return &MockBroadcaster_Height_Call[H]{Call: _e.mock.On("Height")} +} + +func (_c *MockBroadcaster_Height_Call[H]) Run(run func()) *MockBroadcaster_Height_Call[H] { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBroadcaster_Height_Call[H]) Return(v uint64) *MockBroadcaster_Height_Call[H] { + _c.Call.Return(v) + return _c +} + +func (_c *MockBroadcaster_Height_Call[H]) RunAndReturn(run func() uint64) *MockBroadcaster_Height_Call[H] { + _c.Call.Return(run) + return _c +} + // Store provides a mock function for the type MockBroadcaster func (_mock *MockBroadcaster[H]) Store() header.Store[H] { ret := _mock.Called() diff --git a/block/internal/common/expected_interfaces.go b/block/internal/common/expected_interfaces.go index 8f36af6240..e4bc7e472b 100644 --- a/block/internal/common/expected_interfaces.go +++ b/block/internal/common/expected_interfaces.go @@ -8,8 +8,9 @@ import ( "github.com/celestiaorg/go-header" ) -// broadcaster interface for P2P broadcasting +// Broadcaster interface for P2P broadcasting type Broadcaster[H header.Header[H]] interface { WriteToStoreAndBroadcast(ctx context.Context, payload H, opts ...pubsub.PubOpt) error Store() header.Store[H] + Height() uint64 } diff --git a/block/internal/common/raft.go b/block/internal/common/raft.go new file mode 100644 index 0000000000..28dd9c58c0 --- /dev/null +++ b/block/internal/common/raft.go @@ -0,0 +1,17 @@ +package common + +import ( + "context" + + "github.com/evstack/ev-node/pkg/raft" +) + +// RaftNode interface for raft consensus integration +type RaftNode interface { + IsLeader() bool + GetState() *raft.RaftBlockState + + Broadcast(ctx context.Context, state *raft.RaftBlockState) error + + SetApplyCallback(ch chan<- raft.RaftApplyMsg) +} diff --git a/block/internal/executing/executor.go b/block/internal/executing/executor.go index 845e18727e..1cbc527e46 100644 --- a/block/internal/executing/executor.go +++ b/block/internal/executing/executor.go @@ -5,10 +5,12 @@ import ( "context" "errors" "fmt" + "reflect" "sync" "sync/atomic" "time" + "github.com/evstack/ev-node/pkg/raft" "github.com/ipfs/go-datastore" "github.com/libp2p/go-libp2p/core/crypto" "github.com/rs/zerolog" @@ -46,6 +48,9 @@ type Executor struct { genesis genesis.Genesis options common.BlockOptions + // Raft consensus + raftNode common.RaftNode + // State management lastState *atomic.Pointer[types.State] @@ -84,6 +89,7 @@ func NewExecutor( logger zerolog.Logger, options common.BlockOptions, errorCh chan<- error, + raftNode common.RaftNode, ) (*Executor, error) { // For based sequencer, signer is optional as blocks are not signed if !config.Node.BasedSequencer { @@ -100,6 +106,9 @@ func NewExecutor( return nil, common.ErrNotProposer } } + if raftNode != nil && reflect.ValueOf(raftNode).IsNil() { + raftNode = nil + } return &Executor{ store: store, @@ -114,6 +123,7 @@ func NewExecutor( dataBroadcaster: dataBroadcaster, options: options, lastState: &atomic.Pointer[types.State]{}, + raftNode: raftNode, txNotifyCh: make(chan struct{}, 1), errorCh: errorCh, logger: logger.With().Str("component", "executor").Logger(), @@ -151,6 +161,13 @@ func (e *Executor) Stop() error { return nil } +// GetLastState returns the current state. +func (e *Executor) GetLastState() types.State { + state := e.getLastState() + state.AppHash = bytes.Clone(state.AppHash) + return state +} + // getLastState returns the current state. // getLastState should never directly mutate. func (e *Executor) getLastState() types.State { @@ -202,6 +219,12 @@ func (e *Executor) initializeState() error { } } + if e.raftNode != nil { + // ensure node is fully synced before producing any blocks + if raftState := e.raftNode.GetState(); raftState.Height != 0 && raftState.Height != state.LastBlockHeight { + return fmt.Errorf("invalid state: node is not synced with the chain: raft %d != %d state", raftState.Height, state.LastBlockHeight) + } + } e.setLastState(state) e.sequencer.SetDAHeight(state.DAHeight) @@ -310,6 +333,11 @@ func (e *Executor) produceBlock() error { } }() + // Check raft leadership if raft is enabled + if e.raftNode != nil && !e.raftNode.IsLeader() { + return errors.New("not raft leader") + } + currentState := e.getLastState() newHeight := currentState.LastBlockHeight + 1 @@ -423,6 +451,31 @@ func (e *Executor) produceBlock() error { return fmt.Errorf("failed to update state: %w", err) } + // Propose block to raft to share state in the cluster + if e.raftNode != nil { + headerBytes, err := header.MarshalBinary() + if err != nil { + return fmt.Errorf("failed to marshal header: %w", err) + } + dataBytes, err := data.MarshalBinary() + if err != nil { + return fmt.Errorf("failed to marshal data: %w", err) + } + + raftState := &raft.RaftBlockState{ + Height: newHeight, + Hash: header.Hash(), + Timestamp: header.BaseHeader.Time, + Header: headerBytes, + Data: dataBytes, + LastSubmittedDaHeaderHeight: e.cache.GetLastSubmittedHeaderHeight(), + LastSubmittedDaDataHeight: e.cache.GetLastSubmittedDataHeight(), + } + if err := e.raftNode.Broadcast(e.ctx, raftState); err != nil { + return fmt.Errorf("failed to propose block to raft: %w", err) + } + e.logger.Debug().Uint64("height", newHeight).Msg("proposed block to raft") + } if err := batch.Commit(); err != nil { return fmt.Errorf("failed to commit batch: %w", err) } @@ -568,7 +621,7 @@ func (e *Executor) createBlock(ctx context.Context, height uint64, batchData *Ba } for i, tx := range batchData.Transactions { - data.Txs[i] = types.Tx(tx) + data.Txs[i] = tx } // Set data hash @@ -693,6 +746,15 @@ func (e *Executor) recordBlockMetrics(newState types.State, data *types.Data) { e.metrics.CommittedHeight.Set(float64(data.Metadata.Height)) } +// IsSynced checks if the last block height in the stored state matches the expected height and returns true if they are equal. +func (e *Executor) IsSynced(expHeight uint64) bool { + state, err := e.store.GetState(e.ctx) + if err != nil { + return false + } + return state.LastBlockHeight == expHeight +} + // BatchData represents batch data from sequencer type BatchData struct { *coresequencer.Batch diff --git a/block/internal/executing/executor_lazy_test.go b/block/internal/executing/executor_lazy_test.go index a11cf6a1c2..f542aa9f95 100644 --- a/block/internal/executing/executor_lazy_test.go +++ b/block/internal/executing/executor_lazy_test.go @@ -66,6 +66,7 @@ func TestLazyMode_ProduceBlockLogic(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) @@ -181,6 +182,7 @@ func TestRegularMode_ProduceBlockLogic(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) diff --git a/block/internal/executing/executor_logic_test.go b/block/internal/executing/executor_logic_test.go index 6029186e86..5ed6df015e 100644 --- a/block/internal/executing/executor_logic_test.go +++ b/block/internal/executing/executor_logic_test.go @@ -88,6 +88,7 @@ func TestProduceBlock_EmptyBatch_SetsEmptyDataHash(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) @@ -178,6 +179,7 @@ func TestPendingLimit_SkipsProduction(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) diff --git a/block/internal/executing/executor_restart_test.go b/block/internal/executing/executor_restart_test.go index 14daccddcc..d4a7137426 100644 --- a/block/internal/executing/executor_restart_test.go +++ b/block/internal/executing/executor_restart_test.go @@ -2,6 +2,7 @@ package executing import ( "context" + "fmt" "testing" "time" @@ -66,6 +67,7 @@ func TestExecutor_RestartUsesPendingHeader(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) @@ -188,6 +190,7 @@ func TestExecutor_RestartUsesPendingHeader(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) @@ -260,6 +263,8 @@ func TestExecutor_RestartNoPendingHeader(t *testing.T) { cfg.Node.BlockTime = config.DurationWrapper{Duration: 10 * time.Millisecond} cfg.Node.MaxPendingHeadersAndData = 1000 + const numBlocks = 5 + gen := genesis.Genesis{ ChainID: "test-chain", InitialHeight: 1, @@ -289,6 +294,7 @@ func TestExecutor_RestartNoPendingHeader(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) @@ -298,26 +304,31 @@ func TestExecutor_RestartNoPendingHeader(t *testing.T) { mockSeq1.EXPECT().SetDAHeight(uint64(0)).Return().Once() require.NoError(t, exec1.initializeState()) - exec1.ctx, exec1.cancel = context.WithCancel(context.Background()) + exec1.ctx, exec1.cancel = context.WithCancel(t.Context()) - // Produce first block + // Produce n blocks mockSeq1.EXPECT().GetNextBatch(mock.Anything, mock.AnythingOfType("sequencer.GetNextBatchRequest")). RunAndReturn(func(ctx context.Context, req coreseq.GetNextBatchRequest) (*coreseq.GetNextBatchResponse, error) { return &coreseq.GetNextBatchResponse{ Batch: &coreseq.Batch{ - Transactions: [][]byte{[]byte("tx1")}, + Transactions: [][]byte{[]byte("any_tx")}, }, Timestamp: time.Now(), }, nil - }).Once() + }).Times(numBlocks) - mockExec1.EXPECT().ExecuteTxs(mock.Anything, mock.Anything, uint64(1), mock.AnythingOfType("time.Time"), initStateRoot). - Return([]byte("new_root_1"), uint64(1024), nil).Once() + mockSeq1.EXPECT().GetDAHeight().Return(uint64(0)).Times(numBlocks) - mockSeq1.EXPECT().GetDAHeight().Return(uint64(0)).Once() + lastStateRoot := initStateRoot + for i := range numBlocks { + newStateRoot := []byte(fmt.Sprintf("new_root_%d", i+1)) + mockExec1.EXPECT().ExecuteTxs(mock.Anything, mock.Anything, gen.InitialHeight+uint64(i), mock.AnythingOfType("time.Time"), lastStateRoot). + Return(newStateRoot, uint64(1024), nil).Once() + lastStateRoot = newStateRoot - err = exec1.produceBlock() - require.NoError(t, err) + require.NoError(t, exec1.produceBlock()) + } + require.Equal(t, uint64(numBlocks), exec1.getLastState().LastBlockHeight) // Stop first executor exec1.cancel() @@ -344,17 +355,18 @@ func TestExecutor_RestartNoPendingHeader(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) mockSeq2.EXPECT().SetDAHeight(uint64(0)).Return().Once() require.NoError(t, exec2.initializeState()) - exec2.ctx, exec2.cancel = context.WithCancel(context.Background()) + exec2.ctx, exec2.cancel = context.WithCancel(t.Context()) defer exec2.cancel() // Verify state loaded correctly state := exec2.getLastState() - assert.Equal(t, uint64(1), state.LastBlockHeight) + require.Equal(t, uint64(numBlocks), state.LastBlockHeight) // Now produce next block - should go through normal sequencer flow since no pending block mockSeq2.EXPECT().GetNextBatch(mock.Anything, mock.AnythingOfType("sequencer.GetNextBatchRequest")). @@ -367,8 +379,8 @@ func TestExecutor_RestartNoPendingHeader(t *testing.T) { }, nil }).Once() - mockExec2.EXPECT().ExecuteTxs(mock.Anything, mock.Anything, uint64(2), mock.AnythingOfType("time.Time"), []byte("new_root_1")). - Return([]byte("new_root_2"), uint64(1024), nil).Once() + mockExec2.EXPECT().ExecuteTxs(mock.Anything, mock.Anything, uint64(numBlocks+1), mock.AnythingOfType("time.Time"), lastStateRoot). + Return([]byte("new_root_after_restart"), uint64(1024), nil).Once() mockSeq2.EXPECT().GetDAHeight().Return(uint64(0)).Once() @@ -378,7 +390,7 @@ func TestExecutor_RestartNoPendingHeader(t *testing.T) { // Verify normal operation h, err := memStore.Height(context.Background()) require.NoError(t, err) - assert.Equal(t, uint64(2), h) + assert.Equal(t, uint64(numBlocks+1), h) // Verify sequencer was called (normal flow) mockSeq2.AssertCalled(t, "GetNextBatch", mock.Anything, mock.AnythingOfType("sequencer.GetNextBatchRequest")) diff --git a/block/internal/executing/executor_test.go b/block/internal/executing/executor_test.go index e310c6d40d..26cf249854 100644 --- a/block/internal/executing/executor_test.go +++ b/block/internal/executing/executor_test.go @@ -58,6 +58,7 @@ func TestExecutor_BroadcasterIntegration(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) @@ -108,6 +109,7 @@ func TestExecutor_NilBroadcasters(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, err) diff --git a/block/internal/reaping/reaper_test.go b/block/internal/reaping/reaper_test.go index fac03bdd5d..bd710669e2 100644 --- a/block/internal/reaping/reaper_test.go +++ b/block/internal/reaping/reaper_test.go @@ -58,6 +58,7 @@ func newTestExecutor(t *testing.T) *executing.Executor { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), // error channel + nil, ) require.NoError(t, err) diff --git a/block/internal/submitting/submitter.go b/block/internal/submitting/submitter.go index 6aeb7a2d5b..3b1962e8aa 100644 --- a/block/internal/submitting/submitter.go +++ b/block/internal/submitting/submitter.go @@ -108,6 +108,7 @@ func (s *Submitter) Start(ctx context.Context) error { // Start DA submission loop if signer is available (aggregator nodes only) if s.signer != nil { + s.logger.Info().Msg("starting DA submission loop") s.wg.Add(1) go func() { defer s.wg.Done() diff --git a/block/internal/syncing/assert.go b/block/internal/syncing/assert.go new file mode 100644 index 0000000000..02cf4040a0 --- /dev/null +++ b/block/internal/syncing/assert.go @@ -0,0 +1,43 @@ +package syncing + +import ( + "errors" + "fmt" + + "github.com/evstack/ev-node/pkg/genesis" + "github.com/evstack/ev-node/types" +) + +func assertExpectedProposer(genesis genesis.Genesis, proposerAddr []byte) error { + if string(proposerAddr) != string(genesis.ProposerAddress) { + return fmt.Errorf("unexpected proposer: got %x, expected %x", + proposerAddr, genesis.ProposerAddress) + } + return nil +} + +func assertValidSignedData(signedData *types.SignedData, genesis genesis.Genesis) error { + if signedData == nil || signedData.Txs == nil { + return errors.New("empty signed data") + } + + if err := assertExpectedProposer(genesis, signedData.Signer.Address); err != nil { + return err + } + + dataBytes, err := signedData.Data.MarshalBinary() + if err != nil { + return fmt.Errorf("failed to get signed data payload: %w", err) + } + + valid, err := signedData.Signer.PubKey.Verify(dataBytes, signedData.Signature) + if err != nil { + return fmt.Errorf("failed to verify signature: %w", err) + } + + if !valid { + return fmt.Errorf("invalid signature") + } + + return nil +} diff --git a/block/internal/syncing/da_retriever.go b/block/internal/syncing/da_retriever.go index 1307b39681..506840f5c3 100644 --- a/block/internal/syncing/da_retriever.go +++ b/block/internal/syncing/da_retriever.go @@ -346,38 +346,12 @@ func (r *daRetriever) tryDecodeData(bz []byte, daHeight uint64) *types.Data { // assertExpectedProposer validates the proposer address func (r *daRetriever) assertExpectedProposer(proposerAddr []byte) error { - if string(proposerAddr) != string(r.genesis.ProposerAddress) { - return fmt.Errorf("unexpected proposer: got %x, expected %x", - proposerAddr, r.genesis.ProposerAddress) - } - return nil + return assertExpectedProposer(r.genesis, proposerAddr) } // assertValidSignedData validates signed data using the configured signature provider func (r *daRetriever) assertValidSignedData(signedData *types.SignedData) error { - if signedData == nil || signedData.Txs == nil { - return errors.New("empty signed data") - } - - if err := r.assertExpectedProposer(signedData.Signer.Address); err != nil { - return err - } - - dataBytes, err := signedData.Data.MarshalBinary() - if err != nil { - return fmt.Errorf("failed to get signed data payload: %w", err) - } - - valid, err := signedData.Signer.PubKey.Verify(dataBytes, signedData.Signature) - if err != nil { - return fmt.Errorf("failed to verify signature: %w", err) - } - - if !valid { - return fmt.Errorf("invalid signature") - } - - return nil + return assertValidSignedData(signedData, r.genesis) } // isEmptyDataExpected checks if empty data is expected for a header diff --git a/block/internal/syncing/raft_retriever.go b/block/internal/syncing/raft_retriever.go new file mode 100644 index 0000000000..e71e97c7f4 --- /dev/null +++ b/block/internal/syncing/raft_retriever.go @@ -0,0 +1,140 @@ +package syncing + +import ( + "context" + "errors" + "fmt" + "sync" + + "github.com/evstack/ev-node/block/internal/common" + "github.com/evstack/ev-node/pkg/genesis" + "github.com/evstack/ev-node/pkg/raft" + "github.com/evstack/ev-node/types" + "github.com/rs/zerolog" +) + +type eventProcessor interface { + handle(ctx context.Context, event common.DAHeightEvent) error +} +type eventProcessorFn func(ctx context.Context, event common.DAHeightEvent) error + +func (e eventProcessorFn) handle(ctx context.Context, event common.DAHeightEvent) error { + return e(ctx, event) +} + +type raftStatePreProcessor func(ctx context.Context, state *raft.RaftBlockState) error +type raftRetriever struct { + raftNode common.RaftNode + wg sync.WaitGroup + logger zerolog.Logger + genesis genesis.Genesis + eventProcessor eventProcessor + raftBlockPreProcessor raftStatePreProcessor + + mtx sync.Mutex + cancel context.CancelFunc +} + +func newRaftRetriever( + raftNode common.RaftNode, + genesis genesis.Genesis, + logger zerolog.Logger, + eventProcessor eventProcessor, + raftBlockPostProcessor raftStatePreProcessor, +) *raftRetriever { + return &raftRetriever{ + raftNode: raftNode, + genesis: genesis, + logger: logger, + eventProcessor: eventProcessor, + raftBlockPreProcessor: raftBlockPostProcessor, + } +} + +// Start begins the syncing component +func (r *raftRetriever) Start(ctx context.Context) error { + r.mtx.Lock() + defer r.mtx.Unlock() + if r.cancel != nil { + return errors.New("syncer already started") + } + ctx, r.cancel = context.WithCancel(ctx) + applyCh := make(chan raft.RaftApplyMsg, 1) + r.raftNode.SetApplyCallback(applyCh) + + r.wg.Add(1) + go func() { + defer r.wg.Done() + r.raftApplyLoop(ctx, applyCh) + }() + return nil +} + +// Stop gracefully shuts down the raft retriever +func (r *raftRetriever) Stop() { + r.mtx.Lock() + if r.cancel != nil { + r.cancel() + r.cancel = nil + } + r.mtx.Unlock() + + r.wg.Wait() +} + +// raftApplyLoop processes blocks received from raft +func (r *raftRetriever) raftApplyLoop(ctx context.Context, applyCh <-chan raft.RaftApplyMsg) { + r.logger.Info().Msg("starting raft apply loop") + defer r.logger.Info().Msg("raft apply loop stopped") + + for { + select { + case <-ctx.Done(): + return + case msg := <-applyCh: + if err := r.consumeRaftBlock(ctx, msg.State); err != nil { + r.logger.Error().Err(err).Uint64("height", msg.State.Height).Msg("failed to apply raft block") + } + } + } +} + +// consumeRaftBlock applies a block received from raft consensus +func (r *raftRetriever) consumeRaftBlock(ctx context.Context, state *raft.RaftBlockState) error { + r.logger.Debug().Uint64("height", state.Height).Msg("applying raft block") + if err := r.raftBlockPreProcessor(ctx, state); err != nil { + return err + } + + // Unmarshal header and data + var header types.SignedHeader + if err := header.UnmarshalBinary(state.Header); err != nil { + return fmt.Errorf("unmarshal header: %w", err) + } + + if err := header.Header.ValidateBasic(); err != nil { + r.logger.Debug().Err(err).Msg("invalid header structure") + return nil + } + if err := assertExpectedProposer(r.genesis, header.ProposerAddress); err != nil { + r.logger.Debug().Err(err).Msg("unexpected proposer") + return nil + } + + var data types.Data + if err := data.UnmarshalBinary(state.Data); err != nil { + return fmt.Errorf("unmarshal data: %w", err) + } + + event := common.DAHeightEvent{ + Header: &header, + Data: &data, + DaHeight: 0, // raft events don't have DA height context, yet as DA submission is asynchronous + } + return r.eventProcessor.handle(ctx, event) +} + +// Height returns the current height of the raft node's state. +func (r *raftRetriever) Height() uint64 { + return r.raftNode.GetState().Height +} diff --git a/block/internal/syncing/syncer.go b/block/internal/syncing/syncer.go index 266bc55e40..9153b60339 100644 --- a/block/internal/syncing/syncer.go +++ b/block/internal/syncing/syncer.go @@ -9,11 +9,14 @@ import ( "errors" "fmt" "math" + "reflect" "sync" "sync/atomic" "time" coreexecutor "github.com/evstack/ev-node/core/execution" + datypes "github.com/evstack/ev-node/pkg/da/types" + "github.com/evstack/ev-node/pkg/raft" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/rs/zerolog" "golang.org/x/sync/errgroup" @@ -22,7 +25,6 @@ import ( "github.com/evstack/ev-node/block/internal/common" "github.com/evstack/ev-node/block/internal/da" "github.com/evstack/ev-node/pkg/config" - datypes "github.com/evstack/ev-node/pkg/da/types" "github.com/evstack/ev-node/pkg/genesis" "github.com/evstack/ev-node/pkg/store" "github.com/evstack/ev-node/types" @@ -101,9 +103,10 @@ type Syncer struct { errorCh chan<- error // Channel to report critical execution client failures // Handlers - daRetriever DARetriever - fiRetriever *da.ForcedInclusionRetriever - p2pHandler p2pHandler + daRetriever DARetriever + p2pHandler p2pHandler + raftRetriever *raftRetriever + fiRetriever *da.ForcedInclusionRetriever // Forced inclusion tracking pendingForcedInclusionTxs sync.Map // map[string]pendingForcedInclusionTx @@ -133,7 +136,7 @@ func NewSyncer( store store.Store, exec coreexecutor.Executor, daClient da.Client, - cache cache.CacheManager, + cache cache.Manager, metrics *common.Metrics, config config.Config, genesis genesis.Genesis, @@ -142,6 +145,7 @@ func NewSyncer( logger zerolog.Logger, options common.BlockOptions, errorCh chan<- error, + raftNode common.RaftNode, ) *Syncer { daRetrieverHeight := &atomic.Uint64{} daRetrieverHeight.Store(genesis.DAStartHeight) @@ -155,7 +159,7 @@ func NewSyncer( blockFullnessEMA := &atomic.Pointer[float64]{} blockFullnessEMA.Store(&initialFullness) - return &Syncer{ + s := &Syncer{ store: store, exec: exec, cache: cache, @@ -168,13 +172,22 @@ func NewSyncer( daRetrieverHeight: daRetrieverHeight, headerStore: headerStore, dataStore: dataStore, - heightInCh: make(chan common.DAHeightEvent, 100), + heightInCh: make(chan common.DAHeightEvent, 1_000), errorCh: errorCh, logger: logger.With().Str("component", "syncer").Logger(), gracePeriodMultiplier: gracePeriodMultiplier, blockFullnessEMA: blockFullnessEMA, gracePeriodConfig: newForcedInclusionGracePeriodConfig(), } + if raftNode != nil && !reflect.ValueOf(raftNode).IsNil() { + s.raftRetriever = newRaftRetriever(raftNode, genesis, logger, eventProcessorFn(s.pipeEvent), func(ctx context.Context, state *raft.RaftBlockState) error { + s.logger.Debug().Uint64("header_height", state.LastSubmittedDaHeaderHeight).Uint64("data_height", state.LastSubmittedDaDataHeight).Msg("received raft block state") + cache.SetLastSubmittedHeaderHeight(ctx, state.LastSubmittedDaHeaderHeight) + cache.SetLastSubmittedDataHeight(ctx, state.LastSubmittedDaDataHeight) + return nil + }) + } + return s } // Start begins the syncing component @@ -195,6 +208,12 @@ func (s *Syncer) Start(ctx context.Context) error { s.p2pHandler.SetProcessedHeight(currentHeight) } + if s.raftRetriever != nil { + if err := s.raftRetriever.Start(s.ctx); err != nil { + return fmt.Errorf("start raft retriever: %w", err) + } + } + if !s.waitForGenesis() { return nil } @@ -215,15 +234,39 @@ func (s *Syncer) Start(ctx context.Context) error { // Stop shuts down the syncing component func (s *Syncer) Stop() error { - if s.cancel != nil { - s.cancel() + if s.cancel == nil { + return nil } + s.cancel() s.cancelP2PWait(0) s.wg.Wait() s.logger.Info().Msg("syncer stopped") + close(s.heightInCh) + s.cancel = nil return nil } +// isCatchingUpState returns true if the syncer has pending events or is behind the current raft height +func (s *Syncer) isCatchingUpState() bool { + return len(s.heightInCh) != 0 || func() bool { + currentHeight, err := s.store.Height(s.ctx) + if err != nil { + s.logger.Error().Err(err).Msg("failed to get current height") + return false + } + return s.headerStore.Store().Height() > currentHeight || + s.dataStore.Store().Height() > currentHeight || + s.raftRetriever != nil && s.raftRetriever.Height() > currentHeight + }() +} + +// GetLastState returns the current state. +func (e *Syncer) GetLastState() types.State { + state := e.getLastState() + state.AppHash = bytes.Clone(state.AppHash) + return state +} + // getLastState returns the current state func (s *Syncer) getLastState() types.State { state := s.lastState.Load() @@ -298,8 +341,10 @@ func (s *Syncer) processLoop() { select { case <-s.ctx.Done(): return - case heightEvent := <-s.heightInCh: - s.processHeightEvent(&heightEvent) + case heightEvent, ok := <-s.heightInCh: + if ok { + s.processHeightEvent(&heightEvent) + } } } } @@ -372,10 +417,8 @@ func (s *Syncer) fetchDAUntilCaughtUp() error { // Process DA events for _, event := range events { - select { - case s.heightInCh <- event: - default: - s.cache.SetPendingEvent(event.Header.Height(), &event) + if err := s.pipeEvent(s.ctx, event); err != nil { + return err } } @@ -470,6 +513,19 @@ func (s *Syncer) waitForGenesis() bool { return true } +func (s *Syncer) pipeEvent(ctx context.Context, event common.DAHeightEvent) error { + select { + case s.heightInCh <- event: + return nil + case <-ctx.Done(): + s.cache.SetPendingEvent(event.Header.Height(), &event) + return ctx.Err() + default: + s.cache.SetPendingEvent(event.Header.Height(), &event) + } + return nil +} + func (s *Syncer) processHeightEvent(event *common.DAHeightEvent) { height := event.Header.Height() headerHash := event.Header.Hash().String() @@ -516,8 +572,11 @@ func (s *Syncer) processHeightEvent(event *common.DAHeightEvent) { // Try to sync the next block if err := s.trySyncNextBlock(event); err != nil { - s.logger.Error().Err(err).Msg("failed to sync next block") - // If the error is not due to an validation error, re-store the event as pending + s.logger.Error().Err(err). + Uint64("event-height", event.Header.Height()). + Uint64("state-height", s.getLastState().LastBlockHeight). + Msg("failed to sync next block") + // If the error is not due to a validation error, re-store the event as pending switch { case errors.Is(err, errInvalidBlock): // do not reschedule @@ -1095,3 +1154,12 @@ func (s *Syncer) cancelP2PWait(height uint64) { state.cancel() } } + +// IsSynced checks if the last block height in the stored state matches the expected height and returns true if they are equal. +func (s *Syncer) IsSynced(expHeight uint64) bool { + state, err := s.store.GetState(s.ctx) + if err != nil { + return false + } + return state.LastBlockHeight == expHeight && !s.isCatchingUpState() +} diff --git a/block/internal/syncing/syncer_backoff_test.go b/block/internal/syncing/syncer_backoff_test.go index 6df2e577a0..de99be6dac 100644 --- a/block/internal/syncing/syncer_backoff_test.go +++ b/block/internal/syncing/syncer_backoff_test.go @@ -326,7 +326,7 @@ func setupTestSyncer(t *testing.T, daBlockTime time.Duration) *Syncer { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, _, _ := buildSyncTestSigner(t) @@ -355,6 +355,7 @@ func setupTestSyncer(t *testing.T, daBlockTime time.Duration) *Syncer { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, syncer.initializeState()) diff --git a/block/internal/syncing/syncer_benchmark_test.go b/block/internal/syncing/syncer_benchmark_test.go index e2b6f6e51f..3cc42ff567 100644 --- a/block/internal/syncing/syncer_benchmark_test.go +++ b/block/internal/syncing/syncer_benchmark_test.go @@ -81,7 +81,7 @@ func newBenchFixture(b *testing.B, totalHeights uint64, shuffledTx bool, daDelay ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(b, err) addr, pub, signer := buildSyncTestSigner(b) @@ -114,6 +114,7 @@ func newBenchFixture(b *testing.B, totalHeights uint64, shuffledTx bool, daDelay zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(b, s.initializeState()) s.ctx, s.cancel = ctx, cancel diff --git a/block/internal/syncing/syncer_forced_inclusion_test.go b/block/internal/syncing/syncer_forced_inclusion_test.go index 8b0622a42d..cd2036d38b 100644 --- a/block/internal/syncing/syncer_forced_inclusion_test.go +++ b/block/internal/syncing/syncer_forced_inclusion_test.go @@ -344,7 +344,7 @@ func TestVerifyForcedInclusionTxs_AllTransactionsIncluded(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -385,6 +385,7 @@ func TestVerifyForcedInclusionTxs_AllTransactionsIncluded(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -417,7 +418,7 @@ func TestVerifyForcedInclusionTxs_MissingTransactions(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -458,6 +459,7 @@ func TestVerifyForcedInclusionTxs_MissingTransactions(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -520,7 +522,7 @@ func TestVerifyForcedInclusionTxs_PartiallyIncluded(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -561,6 +563,7 @@ func TestVerifyForcedInclusionTxs_PartiallyIncluded(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -627,7 +630,7 @@ func TestVerifyForcedInclusionTxs_NoForcedTransactions(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, _, _ := buildSyncTestSigner(t) @@ -668,6 +671,7 @@ func TestVerifyForcedInclusionTxs_NoForcedTransactions(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -695,7 +699,7 @@ func TestVerifyForcedInclusionTxs_NamespaceNotConfigured(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, _, _ := buildSyncTestSigner(t) @@ -734,6 +738,7 @@ func TestVerifyForcedInclusionTxs_NamespaceNotConfigured(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -758,7 +763,7 @@ func TestVerifyForcedInclusionTxs_DeferralWithinEpoch(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -799,6 +804,7 @@ func TestVerifyForcedInclusionTxs_DeferralWithinEpoch(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -881,7 +887,7 @@ func TestVerifyForcedInclusionTxs_MaliciousAfterEpochEnd(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -922,6 +928,7 @@ func TestVerifyForcedInclusionTxs_MaliciousAfterEpochEnd(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever @@ -969,7 +976,7 @@ func TestVerifyForcedInclusionTxs_SmoothingExceedsEpoch(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -1011,6 +1018,7 @@ func TestVerifyForcedInclusionTxs_SmoothingExceedsEpoch(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) s.daRetriever = daRetriever s.fiRetriever = fiRetriever diff --git a/block/internal/syncing/syncer_test.go b/block/internal/syncing/syncer_test.go index 21b012cf21..efb7ed82c3 100644 --- a/block/internal/syncing/syncer_test.go +++ b/block/internal/syncing/syncer_test.go @@ -105,7 +105,7 @@ func TestSyncer_validateBlock_DataHashMismatch(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -128,6 +128,7 @@ func TestSyncer_validateBlock_DataHashMismatch(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, s.initializeState()) // Create header and data with correct hash @@ -154,7 +155,7 @@ func TestProcessHeightEvent_SyncsAndUpdatesState(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -179,6 +180,7 @@ func TestProcessHeightEvent_SyncsAndUpdatesState(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), errChan, + nil, ) require.NoError(t, s.initializeState()) @@ -209,7 +211,7 @@ func TestSequentialBlockSync(t *testing.T) { ds := dssync.MutexWrap(datastore.NewMapDatastore()) st := store.New(ds) - cm, err := cache.NewCacheManager(config.DefaultConfig(), zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) addr, pub, signer := buildSyncTestSigner(t) @@ -233,6 +235,7 @@ func TestSequentialBlockSync(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), errChan, + nil, ) require.NoError(t, s.initializeState()) s.ctx = context.Background() @@ -328,7 +331,7 @@ func TestSyncLoopPersistState(t *testing.T) { cfg.RootDir = t.TempDir() cfg.ClearCache = true - cacheMgr, err := cache.NewCacheManager(cfg, zerolog.Nop()) + cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) const myDAHeightOffset = uint64(1) @@ -357,7 +360,7 @@ func TestSyncLoopPersistState(t *testing.T) { st, dummyExec, nil, - cacheMgr, + cm, common.NopMetrics(), cfg, gen, @@ -366,6 +369,7 @@ func TestSyncLoopPersistState(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), errorCh, + nil, ) require.NoError(t, syncerInst1.initializeState()) @@ -423,7 +427,7 @@ func TestSyncLoopPersistState(t *testing.T) { require.Equal(t, myFutureDAHeight, syncerInst1.daRetrieverHeight.Load()) // wait for all events consumed - require.NoError(t, cacheMgr.SaveToDisk()) + require.NoError(t, cm.SaveToDisk()) t.Log("processLoop on instance1 completed") // then @@ -438,15 +442,15 @@ func TestSyncLoopPersistState(t *testing.T) { require.Nil(t, event, "event at height %d should have been removed", blockHeight) } // and when new instance is up on restart - cacheMgr, err = cache.NewCacheManager(cfg, zerolog.Nop()) + cm, err = cache.NewManager(config.DefaultConfig(), st, zerolog.Nop()) require.NoError(t, err) - require.NoError(t, cacheMgr.LoadFromDisk()) + require.NoError(t, cm.LoadFromDisk()) syncerInst2 := NewSyncer( st, dummyExec, nil, - cacheMgr, + cm, common.NopMetrics(), cfg, gen, @@ -455,6 +459,7 @@ func TestSyncLoopPersistState(t *testing.T) { zerolog.Nop(), common.DefaultBlockOptions(), make(chan error, 1), + nil, ) require.NoError(t, syncerInst2.initializeState()) diff --git a/block/public.go b/block/public.go index 61a1e068a4..df33995b05 100644 --- a/block/public.go +++ b/block/public.go @@ -78,3 +78,6 @@ func NewForcedInclusionRetriever( ) ForcedInclusionRetriever { return da.NewForcedInclusionRetriever(client, logger, daStartHeight, daEpochSize) } + +// Expose Raft types for consensus integration +type RaftNode = common.RaftNode diff --git a/docs/guides/migrating-to-ev-abci.md b/docs/guides/migrating-to-ev-abci.md index f49ba6df6f..eb6abcd9e0 100644 --- a/docs/guides/migrating-to-ev-abci.md +++ b/docs/guides/migrating-to-ev-abci.md @@ -41,9 +41,9 @@ import ( ) ``` -2. Add the migration manager keeper to your app struct -3. Register the module in your module manager -4. Configure the migration manager in your app initialization +1. Add the migration manager keeper to your app struct +2. Register the module in your module manager +3. Configure the migration manager in your app initialization ### Step 2: Replace Staking Module with Wrapper diff --git a/execution/evm/test/go.mod b/execution/evm/test/go.mod index f037ba4cb5..02a31afa1f 100644 --- a/execution/evm/test/go.mod +++ b/execution/evm/test/go.mod @@ -101,7 +101,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-metrics v0.5.3 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/uint256 v1.3.2 // indirect diff --git a/execution/evm/test/go.sum b/execution/evm/test/go.sum index 8a0b4c8956..9a45657c95 100644 --- a/execution/evm/test/go.sum +++ b/execution/evm/test/go.sum @@ -49,7 +49,9 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -224,10 +226,12 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -295,6 +299,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -328,13 +333,13 @@ github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NM 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-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-metrics v0.5.3 h1:M5uADWMOGCTUNU1YuC4hfknOeHNaX54LDm4oYSucoNE= -github.com/hashicorp/go-metrics v0.5.3/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= @@ -388,9 +393,13 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= @@ -398,6 +407,7 @@ github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYW github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -520,6 +530,7 @@ github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJh github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -609,6 +620,8 @@ github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -619,11 +632,15 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= @@ -658,6 +675,7 @@ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= @@ -790,6 +808,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -799,6 +818,7 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -807,6 +827,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -821,12 +842,17 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -846,6 +872,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/go.mod b/go.mod index 921fab5f22..1afe31a7c5 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,8 @@ require ( github.com/filecoin-project/go-jsonrpc v0.9.0 github.com/go-kit/kit v0.13.0 github.com/goccy/go-yaml v1.19.0 + github.com/hashicorp/raft v1.7.3 + github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 github.com/ipfs/go-datastore v0.9.0 github.com/ipfs/go-ds-badger4 v0.1.8 github.com/libp2p/go-libp2p v0.46.0 @@ -41,8 +43,10 @@ require ( ) require ( + github.com/armon/go-metrics v0.4.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/boltdb/bolt v1.3.1 // indirect github.com/celestiaorg/go-libp2p-messenger v0.2.2 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -52,6 +56,7 @@ require ( github.com/dgraph-io/badger/v4 v4.5.1 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/filecoin-project/go-clock v0.1.0 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect @@ -67,6 +72,11 @@ require ( github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/huin/goupnp v1.3.0 // indirect diff --git a/go.sum b/go.sum index 1329c1c51b..7ddda65611 100644 --- a/go.sum +++ b/go.sum @@ -234,8 +234,11 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= @@ -247,14 +250,25 @@ github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhk github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/thrift v0.17.0/go.mod h1:OLxhMRJxomX+1I/KUw03qoV3mMz16BwaKI+d4fPBx7Q= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/celestiaorg/go-header v0.7.4 h1:kQx3bVvKV+H2etxRi4IUuby5VQydBONx3giHFXDcZ/o= @@ -285,6 +299,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -310,8 +326,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= @@ -320,6 +338,7 @@ github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56 github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= +github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -348,6 +367,7 @@ github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87K github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU= @@ -371,10 +391,16 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -389,6 +415,7 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -398,6 +425,7 @@ github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFT github.com/goccy/go-yaml v1.19.0 h1:EmkZ9RIsX+Uq4DYFowegAuJo8+xdX3T/2dwNPXbxEYE= github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -538,12 +566,31 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4Zs github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/raft v1.7.3 h1:DxpEqZJysHN0wK+fviai5mFcSYsCkNpFUl1xpAW8Rbo= +github.com/hashicorp/raft v1.7.3/go.mod h1:DfvCGFxpAUPE0L4Uc8JLlTPtc3GzSbdH0MTJCLgnmJQ= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148 h1:tjaIHlfKX22DCCPTx2mK+6N/kTP9DV7B3bxEUyQtjKA= +github.com/hashicorp/raft-boltdb v0.0.0-20251103221153-05f9dd7a5148/go.mod h1:sgCxzMuvQ3huVxgmeDdj73YIMmezWZ40HQu2IPmjJWk= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -575,11 +622,19 @@ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7Bd github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -594,9 +649,12 @@ github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -642,12 +700,14 @@ github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuz github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -659,6 +719,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= @@ -676,6 +737,9 @@ github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -704,10 +768,15 @@ github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOo github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -755,6 +824,7 @@ github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7ITo github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -765,16 +835,33 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= @@ -800,6 +887,9 @@ github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZ github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= @@ -825,6 +915,7 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -836,8 +927,10 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -851,6 +944,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -930,6 +1025,7 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1026,12 +1122,14 @@ golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1076,6 +1174,7 @@ golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -1153,9 +1252,12 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1164,6 +1266,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1178,6 +1281,8 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1185,6 +1290,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1196,6 +1302,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1204,6 +1311,7 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1354,6 +1462,7 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= @@ -1539,13 +1648,21 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/node/execution_test.go b/node/execution_test.go deleted file mode 100644 index ea4e67cce6..0000000000 --- a/node/execution_test.go +++ /dev/null @@ -1,123 +0,0 @@ -//go:build !integration - -package node - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - coreexecutor "github.com/evstack/ev-node/core/execution" - testmocks "github.com/evstack/ev-node/test/mocks" - "github.com/evstack/ev-node/types" -) - -func TestBasicExecutionFlow(t *testing.T) { - require := require.New(t) - - node, cleanup := createNodeWithCleanup(t, getTestConfig(t, 1)) - defer cleanup() - - // Wait for node initialization - err := waitForNodeInitialization(node) - require.NoError(err) - - // Get the original executor to retrieve transactions - originalExecutor := getExecutorFromNode(t, node) - txs := getTransactions(t, originalExecutor, t.Context()) - - // Use the generated mock executor for testing execution steps - mockExec := testmocks.NewMockExecutor(t) - - // Define expected state and parameters - expectedInitialStateRoot := []byte("initial state root") - expectedMaxBytes := uint64(1024) - expectedNewStateRoot := []byte("new state root") - blockHeight := uint64(1) - chainID := "test-chain" - - // Set expectations on the mock executor - mockExec.On("InitChain", mock.Anything, mock.AnythingOfType("time.Time"), blockHeight, chainID). - Return(expectedInitialStateRoot, expectedMaxBytes, nil).Once() - mockExec.On("ExecuteTxs", mock.Anything, txs, blockHeight, mock.AnythingOfType("time.Time"), expectedInitialStateRoot). - Return(expectedNewStateRoot, expectedMaxBytes, nil).Once() - mockExec.On("SetFinal", mock.Anything, blockHeight). - Return(nil).Once() - - // Call helper functions with the mock executor - stateRoot, maxBytes := initializeChain(t, mockExec, t.Context()) - require.Equal(expectedInitialStateRoot, stateRoot) - require.Equal(expectedMaxBytes, maxBytes) - - newStateRoot, newMaxBytes := executeTransactions(t, mockExec, t.Context(), txs, stateRoot, maxBytes) - require.Equal(expectedNewStateRoot, newStateRoot) - require.Equal(expectedMaxBytes, newMaxBytes) - - finalizeExecution(t, mockExec, t.Context()) - - require.NotEmpty(newStateRoot) -} - -func waitForNodeInitialization(node *FullNode) error { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - ticker := time.NewTicker(100 * time.Millisecond) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - if node.IsRunning() && node.blockComponents != nil { - return nil - } - case <-ctx.Done(): - return errors.New("timeout waiting for node initialization") - } - } -} - -func getExecutorFromNode(t *testing.T, node *FullNode) coreexecutor.Executor { - if node.blockComponents != nil && node.blockComponents.Executor != nil { - // Return the underlying core executor from the block executor - // This is a test-only access pattern - t.Skip("Direct executor access not available through block components") - return nil - } - t.Skip("getExecutorFromNode needs block components with executor") - return nil -} - -func getTransactions(t *testing.T, executor coreexecutor.Executor, ctx context.Context) [][]byte { - txs, err := executor.GetTxs(ctx) - require.NoError(t, err) - return txs -} - -func initializeChain(t *testing.T, executor coreexecutor.Executor, ctx context.Context) ([]byte, uint64) { - genesisTime := time.Now() - initialHeight := uint64(1) - chainID := "test-chain" - stateRoot, maxBytes, err := executor.InitChain(ctx, genesisTime, initialHeight, chainID) - require.NoError(t, err) - require.Greater(t, maxBytes, uint64(0)) - return stateRoot, maxBytes -} - -func executeTransactions(t *testing.T, executor coreexecutor.Executor, ctx context.Context, txs [][]byte, stateRoot types.Hash, maxBytes uint64) ([]byte, uint64) { - blockHeight := uint64(1) - timestamp := time.Now() - newStateRoot, newMaxBytes, err := executor.ExecuteTxs(ctx, txs, blockHeight, timestamp, stateRoot) - require.NoError(t, err) - require.Greater(t, newMaxBytes, uint64(0)) - return newStateRoot, newMaxBytes -} - -func finalizeExecution(t *testing.T, executor coreexecutor.Executor, ctx context.Context) { - err := executor.SetFinal(ctx, 1) - require.NoError(t, err) -} diff --git a/node/failover.go b/node/failover.go new file mode 100644 index 0000000000..ca780ad848 --- /dev/null +++ b/node/failover.go @@ -0,0 +1,279 @@ +package node + +import ( + "context" + "errors" + "fmt" + "net/http" + "sync/atomic" + "time" + + "github.com/evstack/ev-node/block" + coreexecutor "github.com/evstack/ev-node/core/execution" + coresequencer "github.com/evstack/ev-node/core/sequencer" + "github.com/evstack/ev-node/pkg/config" + genesispkg "github.com/evstack/ev-node/pkg/genesis" + "github.com/evstack/ev-node/pkg/p2p" + "github.com/evstack/ev-node/pkg/p2p/key" + "github.com/evstack/ev-node/pkg/raft" + rpcserver "github.com/evstack/ev-node/pkg/rpc/server" + "github.com/evstack/ev-node/pkg/signer" + "github.com/evstack/ev-node/pkg/store" + evsync "github.com/evstack/ev-node/pkg/sync" + ds "github.com/ipfs/go-datastore" + "github.com/rs/zerolog" + "golang.org/x/sync/errgroup" +) + +// failoverState collect the components to reset when switching modes. +type failoverState struct { + logger zerolog.Logger + + p2pClient *p2p.Client + headerSyncService *evsync.HeaderSyncService + dataSyncService *evsync.DataSyncService + rpcServer *http.Server + bc *block.Components +} + +func newSyncMode( + nodeConfig config.Config, + nodeKey *key.NodeKey, + genesis genesispkg.Genesis, + database ds.Batching, + exec coreexecutor.Executor, + da block.DAClient, + logger zerolog.Logger, + rktStore store.Store, + mainKV ds.Batching, + blockMetrics *block.Metrics, + nodeOpts NodeOptions, + raftNode *raft.Node, +) (*failoverState, error) { + blockComponentsFn := func(headerSyncService *evsync.HeaderSyncService, dataSyncService *evsync.DataSyncService) (*block.Components, error) { + return block.NewSyncComponents( + nodeConfig, + genesis, + rktStore, + exec, + da, + headerSyncService, + dataSyncService, + logger, + blockMetrics, + nodeOpts.BlockOptions, + raftNode, + ) + } + return setupFailoverState(nodeConfig, nodeKey, database, genesis, logger, mainKV, rktStore, blockComponentsFn, raftNode) +} +func newAggregatorMode( + nodeConfig config.Config, + nodeKey *key.NodeKey, + signer signer.Signer, + genesis genesispkg.Genesis, + database ds.Batching, + exec coreexecutor.Executor, + sequencer coresequencer.Sequencer, + da block.DAClient, + logger zerolog.Logger, + rktStore store.Store, + mainKV ds.Batching, + blockMetrics *block.Metrics, + nodeOpts NodeOptions, + raftNode *raft.Node, +) (*failoverState, error) { + + blockComponentsFn := func(headerSyncService *evsync.HeaderSyncService, dataSyncService *evsync.DataSyncService) (*block.Components, error) { + return block.NewAggregatorComponents( + nodeConfig, + genesis, + rktStore, + exec, + sequencer, + da, + signer, + headerSyncService, + dataSyncService, + logger, + blockMetrics, + nodeOpts.BlockOptions, + raftNode, + ) + } + + return setupFailoverState(nodeConfig, nodeKey, database, genesis, logger, mainKV, rktStore, blockComponentsFn, raftNode) +} + +func setupFailoverState( + nodeConfig config.Config, + nodeKey *key.NodeKey, + database ds.Batching, + genesis genesispkg.Genesis, + logger zerolog.Logger, + mainKV ds.Batching, + rktStore store.Store, + buildComponentsFn func(headerSyncService *evsync.HeaderSyncService, dataSyncService *evsync.DataSyncService) (*block.Components, error), + raftNode *raft.Node, +) (*failoverState, error) { + p2pClient, err := p2p.NewClient(nodeConfig.P2P, nodeKey.PrivKey, database, genesis.ChainID, logger, nil) + if err != nil { + return nil, err + } + + headerSyncService, err := evsync.NewHeaderSyncService(mainKV, nodeConfig, genesis, p2pClient, logger.With().Str("component", "HeaderSyncService").Logger()) + if err != nil { + return nil, fmt.Errorf("error while initializing HeaderSyncService: %w", err) + } + + dataSyncService, err := evsync.NewDataSyncService(mainKV, nodeConfig, genesis, p2pClient, logger.With().Str("component", "DataSyncService").Logger()) + if err != nil { + return nil, fmt.Errorf("error while initializing DataSyncService: %w", err) + } + + bestKnownHeightProvider := func() uint64 { + hHeight := headerSyncService.Store().Height() + dHeight := dataSyncService.Store().Height() + return min(hHeight, dHeight) + } + handler, err := rpcserver.NewServiceHandler( + rktStore, + headerSyncService.Store(), + dataSyncService.Store(), + p2pClient, + genesis.ProposerAddress, + logger, + nodeConfig, + bestKnownHeightProvider, + raftNode, + ) + if err != nil { + return nil, fmt.Errorf("error creating RPC handler: %w", err) + } + + rpcServer := &http.Server{ + Addr: nodeConfig.RPC.Address, + Handler: handler, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 120 * time.Second, + } + bc, err := buildComponentsFn(headerSyncService, dataSyncService) + if err != nil { + return nil, fmt.Errorf("build follower components: %w", err) + } + + return &failoverState{ + logger: logger, + p2pClient: p2pClient, + headerSyncService: headerSyncService, + dataSyncService: dataSyncService, + rpcServer: rpcServer, + bc: bc, + }, nil +} + +func (f *failoverState) Run(pCtx context.Context) (multiErr error) { + stopService := func(stoppable func(context.Context) error, name string) { + // parent context is cancelled already, so we need to create a new one + shutdownCtx, done := context.WithTimeout(context.Background(), 3*time.Second) + defer done() + + if err := stoppable(shutdownCtx); err != nil && !errors.Is(err, context.Canceled) { + multiErr = errors.Join(multiErr, fmt.Errorf("stopping %s: %w", name, err)) + } + } + cCtx, cancel := context.WithCancel(pCtx) + defer cancel() + wg, ctx := errgroup.WithContext(cCtx) + wg.Go(func() (rerr error) { + defer func() { + if err := f.bc.Stop(); err != nil && !errors.Is(err, context.Canceled) { + rerr = errors.Join(rerr, fmt.Errorf("stopping block components: %w", err)) + } + }() + + f.logger.Info().Str("addr", f.rpcServer.Addr).Msg("Started RPC server") + if err := f.rpcServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + return err + } + return nil + }) + + if err := f.p2pClient.Start(ctx); err != nil { + return fmt.Errorf("start p2p: %w", err) + } + defer f.p2pClient.Close() // nolint: errcheck + + if err := f.headerSyncService.Start(ctx); err != nil { + return fmt.Errorf("error while starting header sync service: %w", err) + } + defer stopService(f.headerSyncService.Stop, "header sync") + + if err := f.dataSyncService.Start(ctx); err != nil { + return fmt.Errorf("error while starting data sync service: %w", err) + } + defer stopService(f.dataSyncService.Stop, "data sync") + + wg.Go(func() error { + defer func() { + shutdownCtx, done := context.WithTimeout(context.Background(), 3*time.Second) + defer done() + _ = f.rpcServer.Shutdown(shutdownCtx) + }() + if err := f.bc.Start(ctx); err != nil && !errors.Is(err, context.Canceled) { + return fmt.Errorf("components started with error: %w", err) + } + return nil + }) + + return wg.Wait() +} + +func (f *failoverState) IsSynced(s *raft.RaftBlockState) bool { + if s.Height == 0 { + return true + } + if f.bc.Syncer != nil { + return f.bc.Syncer.IsSynced(s.Height) + } + if f.bc.Executor != nil { + return f.bc.Executor.IsSynced(s.Height) + } + return false +} + +var _ leaderElection = &singleRoleElector{} +var _ testSupportElection = &singleRoleElector{} + +// singleRoleElector implements leaderElection but with a static role. No switchover. +type singleRoleElector struct { + running atomic.Bool + runnable raft.Runnable +} + +func newSingleRoleElector(factory func() (raft.Runnable, error)) (*singleRoleElector, error) { + r, err := factory() + if err != nil { + return nil, err + } + return &singleRoleElector{runnable: r}, nil +} + +func (a *singleRoleElector) Run(ctx context.Context) error { + a.running.Store(true) + defer a.running.Store(false) + return a.runnable.Run(ctx) +} + +func (a *singleRoleElector) IsRunning() bool { + return a.running.Load() +} + +// for testing purposes only +func (a *singleRoleElector) state() *failoverState { + if v, ok := a.runnable.(*failoverState); ok { + return v + } + return nil +} diff --git a/node/full.go b/node/full.go index c6086bb5da..14515e405a 100644 --- a/node/full.go +++ b/node/full.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" "net/http/pprof" + "strings" "time" ds "github.com/ipfs/go-datastore" @@ -21,12 +22,11 @@ import ( coresequencer "github.com/evstack/ev-node/core/sequencer" "github.com/evstack/ev-node/pkg/config" genesispkg "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" - rpcserver "github.com/evstack/ev-node/pkg/rpc/server" + "github.com/evstack/ev-node/pkg/p2p/key" + raftpkg "github.com/evstack/ev-node/pkg/raft" "github.com/evstack/ev-node/pkg/service" "github.com/evstack/ev-node/pkg/signer" "github.com/evstack/ev-node/pkg/store" - evsync "github.com/evstack/ev-node/pkg/sync" ) const ( @@ -37,6 +37,11 @@ const ( var _ Node = &FullNode{} +type leaderElection interface { + Run(ctx context.Context) error + IsRunning() bool +} + // FullNode represents a client node in Rollkit network. // It connects all the components and orchestrates their work. type FullNode struct { @@ -50,21 +55,18 @@ type FullNode struct { daClient block.DAClient - p2pClient *p2p.Client - hSyncService *evsync.HeaderSyncService - dSyncService *evsync.DataSyncService - Store store.Store - blockComponents *block.Components + Store store.Store + raftNode *raftpkg.Node - prometheusSrv *http.Server - pprofSrv *http.Server - rpcServer *http.Server + prometheusSrv *http.Server + pprofSrv *http.Server + leaderElection leaderElection } // newFullNode creates a new Rollkit full node. func newFullNode( nodeConfig config.Config, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, signer signer.Signer, genesis genesispkg.Genesis, database ds.Batching, @@ -82,59 +84,50 @@ func newFullNode( mainKV := store.NewEvNodeKVStore(database) evstore := store.New(mainKV) - headerSyncService, err := initHeaderSyncService(mainKV, nodeConfig, genesis, p2pClient, logger) - if err != nil { - return nil, err + var raftNode *raftpkg.Node + if nodeConfig.Node.Aggregator && nodeConfig.Raft.Enable { + raftNode, err = initRaftNode(nodeConfig, logger) + if err != nil { + return nil, fmt.Errorf("failed to initialize raft node: %w", err) + } } - dataSyncService, err := initDataSyncService(mainKV, nodeConfig, genesis, p2pClient, logger) - if err != nil { - return nil, err + leaderFactory := func() (raftpkg.Runnable, error) { + logger.Info().Msg("Starting aggregator-MODE") + nodeConfig.Node.Aggregator = true + nodeConfig.P2P.Peers = "" // peers are not supported in aggregator mode + return newAggregatorMode(nodeConfig, nodeKey, signer, genesis, database, exec, sequencer, daClient, logger, evstore, mainKV, blockMetrics, nodeOpts, raftNode) } - - var blockComponents *block.Components - if nodeConfig.Node.Aggregator { - blockComponents, err = block.NewAggregatorComponents( - nodeConfig, - genesis, - evstore, - exec, - sequencer, - daClient, - signer, - headerSyncService, - dataSyncService, - logger, - blockMetrics, - nodeOpts.BlockOptions, - ) - } else { - blockComponents, err = block.NewSyncComponents( - nodeConfig, - genesis, - evstore, - exec, - daClient, - headerSyncService, - dataSyncService, - logger, - blockMetrics, - nodeOpts.BlockOptions, - ) + followerFactory := func() (raftpkg.Runnable, error) { + logger.Info().Msg("Starting sync-MODE") + nodeConfig.Node.Aggregator = false + return newSyncMode(nodeConfig, nodeKey, genesis, database, exec, daClient, logger, evstore, mainKV, blockMetrics, nodeOpts, raftNode) } - if err != nil { - return nil, err + + // Initialize raft node if enabled (for both aggregator and sync nodes) + var leaderElection leaderElection + switch { + case nodeConfig.Node.Aggregator && nodeConfig.Raft.Enable: + leaderElection = raftpkg.NewDynamicLeaderElection(logger, leaderFactory, followerFactory, raftNode) + case nodeConfig.Node.Aggregator && !nodeConfig.Raft.Enable: + if leaderElection, err = newSingleRoleElector(leaderFactory); err != nil { + return nil, err + } + case !nodeConfig.Node.Aggregator && !nodeConfig.Raft.Enable: + if leaderElection, err = newSingleRoleElector(followerFactory); err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("raft config must be used in sequencer setup only") } node := &FullNode{ - genesis: genesis, - nodeConfig: nodeConfig, - p2pClient: p2pClient, - blockComponents: blockComponents, - daClient: daClient, - Store: evstore, - hSyncService: headerSyncService, - dSyncService: dataSyncService, + genesis: genesis, + nodeConfig: nodeConfig, + daClient: daClient, + Store: evstore, + leaderElection: leaderElection, + raftNode: raftNode, } node.BaseService = *service.NewBaseService(logger, "Node", node) @@ -142,36 +135,33 @@ func newFullNode( return node, nil } -func initHeaderSyncService( - mainKV ds.Batching, - nodeConfig config.Config, - genesis genesispkg.Genesis, - p2pClient *p2p.Client, - logger zerolog.Logger, -) (*evsync.HeaderSyncService, error) { - componentLogger := logger.With().Str("component", "HeaderSyncService").Logger() +func initRaftNode(nodeConfig config.Config, logger zerolog.Logger) (*raftpkg.Node, error) { + raftCfg := &raftpkg.Config{ + NodeID: nodeConfig.Raft.NodeID, + RaftAddr: nodeConfig.Raft.RaftAddr, + RaftDir: nodeConfig.Raft.RaftDir, + Bootstrap: nodeConfig.Raft.Bootstrap, + SnapCount: nodeConfig.Raft.SnapCount, + SendTimeout: nodeConfig.Raft.SendTimeout, + HeartbeatTimeout: nodeConfig.Raft.HeartbeatTimeout, + LeaderLeaseTimeout: nodeConfig.Raft.LeaderLeaseTimeout, + } - headerSyncService, err := evsync.NewHeaderSyncService(mainKV, nodeConfig, genesis, p2pClient, componentLogger) + if nodeConfig.Raft.Peers != "" { + raftCfg.Peers = strings.Split(nodeConfig.Raft.Peers, ",") + } + raftNode, err := raftpkg.NewNode(raftCfg, logger) if err != nil { - return nil, fmt.Errorf("error while initializing HeaderSyncService: %w", err) + return nil, fmt.Errorf("create raft node: %w", err) } - return headerSyncService, nil -} -func initDataSyncService( - mainKV ds.Batching, - nodeConfig config.Config, - genesis genesispkg.Genesis, - p2pClient *p2p.Client, - logger zerolog.Logger, -) (*evsync.DataSyncService, error) { - componentLogger := logger.With().Str("component", "DataSyncService").Logger() + logger.Info(). + Str("node_id", nodeConfig.Raft.NodeID). + Str("addr", nodeConfig.Raft.RaftAddr). + Bool("bootstrap", nodeConfig.Raft.Bootstrap). + Msg("initialized raft node") - dataSyncService, err := evsync.NewDataSyncService(mainKV, nodeConfig, genesis, p2pClient, componentLogger) - if err != nil { - return nil, fmt.Errorf("error while initializing DataSyncService: %w", err) - } - return dataSyncService, nil + return raftNode, nil } // initGenesisChunks creates a chunked format of the genesis document to make it easier to @@ -278,65 +268,16 @@ func (n *FullNode) Run(parentCtx context.Context) error { (n.nodeConfig.Instrumentation.IsPrometheusEnabled() || n.nodeConfig.Instrumentation.IsPprofEnabled()) { n.prometheusSrv, n.pprofSrv = n.startInstrumentationServer() } - - // Start RPC server - bestKnownHeightProvider := func() uint64 { - hHeight := n.hSyncService.Store().Height() - dHeight := n.dSyncService.Store().Height() - return min(hHeight, dHeight) - } - - handler, err := rpcserver.NewServiceHandler( - n.Store, - n.hSyncService.Store(), - n.dSyncService.Store(), - n.p2pClient, - n.genesis.ProposerAddress, - n.Logger, - n.nodeConfig, - bestKnownHeightProvider, - ) - if err != nil { - return fmt.Errorf("error creating RPC handler: %w", err) - } - - n.rpcServer = &http.Server{ - Addr: n.nodeConfig.RPC.Address, - Handler: handler, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - IdleTimeout: 120 * time.Second, - } - - go func() { - n.Logger.Info().Str("addr", n.nodeConfig.RPC.Address).Msg("started RPC server") - if err := n.rpcServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - n.Logger.Error().Err(err).Msg("RPC server error") + // Start leader election + if n.raftNode != nil { + if err := n.raftNode.Start(ctx); err != nil { + return fmt.Errorf("error while starting leader election: %w", err) } - }() - - n.Logger.Info().Msg("starting P2P client") - err = n.p2pClient.Start(ctx) - if err != nil { - return fmt.Errorf("error while starting P2P client: %w", err) - } - - if err = n.hSyncService.Start(ctx); err != nil { - return fmt.Errorf("error while starting header sync service: %w", err) - } - - if err = n.dSyncService.Start(ctx); err != nil { - return fmt.Errorf("error while starting data sync service: %w", err) } var runtimeErr error - // Start the block components (blocking) - if err := n.blockComponents.Start(ctx); err != nil { - if !errors.Is(err, context.Canceled) { - runtimeErr = fmt.Errorf("running block components: %w", err) - } else { - n.Logger.Info().Msg("context canceled, stopping node") - } + if err := n.leaderElection.Run(ctx); err != nil && !errors.Is(err, context.Canceled) { + runtimeErr = err } // blocking components start exited, propagate shutdown to all other processes @@ -349,45 +290,18 @@ func (n *FullNode) Run(parentCtx context.Context) error { var shutdownMultiErr error // Variable to accumulate multiple errors - // Stop block components - if err := n.blockComponents.Stop(); err != nil { - n.Logger.Error().Err(err).Msg("error stopping block components") - shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("stopping block components: %w", err)) - } - - // Stop Header Sync Service - err = n.hSyncService.Stop(shutdownCtx) - if err != nil { - // Log context canceled errors at a lower level if desired, or handle specific non-cancel errors - if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) { - n.Logger.Error().Err(err).Msg("error stopping header sync service") - shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("stopping header sync service: %w", err)) - } else { - n.Logger.Debug().Err(err).Msg("header sync service stop context ended") // Log cancellation as debug - } - } - - // Stop Data Sync Service - err = n.dSyncService.Stop(shutdownCtx) - if err != nil { - // Log context canceled errors at a lower level if desired, or handle specific non-cancel errors - if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) { - n.Logger.Error().Err(err).Msg("error stopping data sync service") - shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("stopping data sync service: %w", err)) + // Stop leader election + if n.raftNode != nil { + if err := n.raftNode.Stop(); err != nil && !errors.Is(err, context.Canceled) { + shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("stopping leader election: %w", err)) } else { - n.Logger.Debug().Err(err).Msg("data sync service stop context ended") // Log cancellation as debug + n.Logger.Debug().Msg("leader election stopped") } } - // Stop P2P Client - err = n.p2pClient.Close() - if err != nil { - shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("closing P2P client: %w", err)) - } - // Shutdown Prometheus Server if n.prometheusSrv != nil { - err = n.prometheusSrv.Shutdown(shutdownCtx) + err := n.prometheusSrv.Shutdown(shutdownCtx) // http.ErrServerClosed is expected on graceful shutdown if err != nil && !errors.Is(err, http.ErrServerClosed) { shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("shutting down Prometheus server: %w", err)) @@ -398,7 +312,7 @@ func (n *FullNode) Run(parentCtx context.Context) error { // Shutdown Pprof Server if n.pprofSrv != nil { - err = n.pprofSrv.Shutdown(shutdownCtx) + err := n.pprofSrv.Shutdown(shutdownCtx) if err != nil && !errors.Is(err, http.ErrServerClosed) { shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("shutting down pprof server: %w", err)) } else { @@ -406,32 +320,13 @@ func (n *FullNode) Run(parentCtx context.Context) error { } } - // Shutdown RPC Server - if n.rpcServer != nil { - err = n.rpcServer.Shutdown(shutdownCtx) - if err != nil && !errors.Is(err, http.ErrServerClosed) { - shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("shutting down RPC server: %w", err)) - } else { - n.Logger.Debug().Err(err).Msg("RPC server shutdown context ended") - } - } - // Ensure Store.Close is called last to maximize chance of data flushing - if err = n.Store.Close(); err != nil { + if err := n.Store.Close(); err != nil { shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("closing store: %w", err)) } else { n.Logger.Debug().Msg("store closed") } - // Save caches if needed - if n.blockComponents != nil && n.blockComponents.Cache != nil { - if err := n.blockComponents.Cache.SaveToDisk(); err != nil { - shutdownMultiErr = errors.Join(shutdownMultiErr, fmt.Errorf("saving caches: %w", err)) - } else { - n.Logger.Debug().Msg("caches saved") - } - } - // Log final status if shutdownMultiErr != nil { for _, err := range shutdownMultiErr.(interface{ Unwrap() []error }).Unwrap() { @@ -465,5 +360,5 @@ func (n *FullNode) GetGenesisChunks() ([]string, error) { // IsRunning returns true if the node is running. func (n *FullNode) IsRunning() bool { - return n.blockComponents != nil + return n.leaderElection.IsRunning() } diff --git a/node/full_node_integration_test.go b/node/full_node_integration_test.go index c0aaf50506..3ee9167e04 100644 --- a/node/full_node_integration_test.go +++ b/node/full_node_integration_test.go @@ -49,27 +49,29 @@ func TestTxGossipingMultipleNodesNoDA(t *testing.T) { } // Inject a transaction into the sequencer's executor - if nodes[0].blockComponents != nil && nodes[0].blockComponents.Executor != nil { + if state := castState(t, nodes[0]); state.bc.Executor != nil { // Access the core executor from the block executor - coreExec := nodes[0].blockComponents.Executor.GetCoreExecutor() + coreExec := state.bc.Executor.GetCoreExecutor() if dummyExec, ok := coreExec.(interface{ InjectTx([]byte) }); ok { dummyExec.InjectTx([]byte("test tx")) } else { t.Fatal("Warning: Could not cast core executor to DummyExecutor") } + } else { + t.Fatal("executor empty") } blocksToWaitFor := uint64(3) // Wait for all nodes to reach at least blocksToWaitFor blocks - for _, nodeItem := range nodes { + for i, nodeItem := range nodes { requireEmptyChan(t, errChan) - require.NoError(waitForAtLeastNBlocks(nodeItem, blocksToWaitFor, Store)) + require.NoError(waitForAtLeastNBlocks(nodeItem, blocksToWaitFor, Store), "node %d", i) } - // Shutdown all nodes and wait - shutdownAndWait(t, cancels, &runningWg, 10*time.Second) - // Assert that all nodes have the same block up to height blocksToWaitFor assertAllNodesSynced(t, nodes, blocksToWaitFor) + + // Shutdown all nodes and wait + shutdownAndWait(t, cancels, &runningWg, 10*time.Second) } // TestTxGossipingMultipleNodesDAIncluded tests that transactions are gossiped and blocks are sequenced and synced across multiple nodes only using DA. P2P gossiping is disabled. @@ -82,9 +84,6 @@ func TestTxGossipingMultipleNodesDAIncluded(t *testing.T) { numNodes := 4 nodes, cleanups := createNodesWithCleanup(t, numNodes, config) - for _, cleanup := range cleanups { - defer cleanup() - } ctxs, cancels := createNodeContexts(numNodes) var runningWg sync.WaitGroup @@ -92,6 +91,7 @@ func TestTxGossipingMultipleNodesDAIncluded(t *testing.T) { errChan := make(chan error, numNodes) // Start only the sequencer first startNodeInBackground(t, nodes, ctxs, &runningWg, 0, errChan) + t.Cleanup(func() { shutdownAndWait(t, cleanups, &runningWg, 10*time.Second) }) // Wait for the first block to be produced by the sequencer err := waitForFirstBlock(nodes[0], Header) @@ -113,9 +113,9 @@ func TestTxGossipingMultipleNodesDAIncluded(t *testing.T) { } // Inject transactions into the sequencer's executor - if nodes[0].blockComponents != nil && nodes[0].blockComponents.Executor != nil { + if state := castState(t, nodes[0]); state != nil && state.bc.Executor != nil { // Access the core executor from the block executor - coreExec := nodes[0].blockComponents.Executor.GetCoreExecutor() + coreExec := state.bc.Executor.GetCoreExecutor() if dummyExec, ok := coreExec.(interface{ InjectTx([]byte) }); ok { dummyExec.InjectTx([]byte("test tx 1")) dummyExec.InjectTx([]byte("test tx 2")) @@ -125,18 +125,26 @@ func TestTxGossipingMultipleNodesDAIncluded(t *testing.T) { } } - blocksToWaitFor := uint64(4) + blocksToWaitFor := uint64(5) // Wait for all nodes to reach at least blocksToWaitFor blocks with DA inclusion for _, nodeItem := range nodes { requireEmptyChan(t, errChan) require.NoError(waitForAtLeastNDAIncludedHeight(nodeItem, blocksToWaitFor)) } + // Assert that all nodes have the same block up to height blocksToWaitFor + assertAllNodesSynced(t, nodes, blocksToWaitFor) + // Shutdown all nodes and wait shutdownAndWait(t, cancels, &runningWg, 5*time.Second) +} - // Assert that all nodes have the same block up to height blocksToWaitFor - assertAllNodesSynced(t, nodes, blocksToWaitFor) +func castState(t *testing.T, node *FullNode) *failoverState { + v, ok := node.leaderElection.(testSupportElection) + require.True(t, ok) + state := v.state() + require.NotNil(t, state) + return state } // TestFastDASync verifies that a new node can quickly synchronize with the DA layer using fast sync. @@ -155,16 +163,13 @@ func TestFastDASync(t *testing.T) { config.DA.BlockTime = evconfig.DurationWrapper{Duration: 200 * time.Millisecond} nodes, cleanups := createNodesWithCleanup(t, 2, config) - for _, cleanup := range cleanups { - defer cleanup() - } - ctxs, cancels := createNodeContexts(len(nodes)) var runningWg sync.WaitGroup errChan := make(chan error, len(nodes)) // Start only the first node startNodeInBackground(t, nodes, ctxs, &runningWg, 0, errChan) + t.Cleanup(func() { shutdownAndWait(t, cleanups, &runningWg, 10*time.Second) }) // Wait for the first node to produce a few blocks blocksToWaitFor := uint64(2) @@ -175,6 +180,7 @@ func TestFastDASync(t *testing.T) { // Now start the second node and time its sync startNodeInBackground(t, nodes, ctxs, &runningWg, 1, errChan) + start := time.Now() // Wait for the second node to catch up to the first node require.NoError(waitForAtLeastNBlocks(nodes[1], blocksToWaitFor, Store)) @@ -309,6 +315,7 @@ func testSingleSequencerSingleFullNode(t *testing.T, source Source) { // Start the sequencer first startNodeInBackground(t, nodes, ctxs, &runningWg, 0, errChan) + t.Cleanup(func() { shutdownAndWait(t, cancels, &runningWg, 10*time.Second) }) // Wait for the sequencer to produce at first block require.NoError(waitForFirstBlock(nodes[0], source)) @@ -328,9 +335,6 @@ func testSingleSequencerSingleFullNode(t *testing.T, source Source) { // Verify both nodes are synced using the helper require.NoError(verifyNodesSynced(nodes[0], nodes[1], source)) - - // Cancel all node contexts to signal shutdown and wait - shutdownAndWait(t, cancels, &runningWg, 5*time.Second) } // testSingleSequencerTwoFullNodes sets up a single sequencer and two full nodes, starts the sequencer, waits for it to produce a block, then starts the full nodes. @@ -352,6 +356,7 @@ func testSingleSequencerTwoFullNodes(t *testing.T, source Source) { // Start the sequencer first startNodeInBackground(t, nodes, ctxs, &runningWg, 0, errChan) + t.Cleanup(func() { shutdownAndWait(t, cancels, &runningWg, 10*time.Second) }) // Wait for the sequencer to produce at first block require.NoError(waitForFirstBlock(nodes[0], source)) diff --git a/node/helpers.go b/node/helpers.go index 0dc1a20cc3..c24f38ac38 100644 --- a/node/helpers.go +++ b/node/helpers.go @@ -3,9 +3,12 @@ package node import ( "context" + "encoding/binary" "errors" "fmt" "time" + + "github.com/evstack/ev-node/pkg/store" ) // Source is an enum representing different sources of height @@ -57,9 +60,15 @@ func getNodeHeight(node Node, source Source) (uint64, error) { } } +type testSupportElection interface { + state() *failoverState +} + func getNodeHeightFromHeader(node Node) (uint64, error) { if fn, ok := node.(*FullNode); ok { - return fn.hSyncService.Store().Height(), nil + if v, ok := fn.leaderElection.(testSupportElection); ok { + return v.state().headerSyncService.Store().Height(), nil + } } if ln, ok := node.(*LightNode); ok { return ln.hSyncService.Store().Height(), nil @@ -69,7 +78,9 @@ func getNodeHeightFromHeader(node Node) (uint64, error) { func getNodeHeightFromData(node Node) (uint64, error) { if fn, ok := node.(*FullNode); ok { - return fn.dSyncService.Store().Height(), nil + if v, ok := fn.leaderElection.(testSupportElection); ok { + return v.state().dataSyncService.Store().Height(), nil + } } return 0, errors.New("not a full node") } @@ -98,19 +109,20 @@ func waitForAtLeastNBlocks(node Node, n uint64, source Source) error { // waitForAtLeastNDAIncludedHeight waits for the DA included height to be at least n func waitForAtLeastNDAIncludedHeight(node Node, n uint64) error { return Retry(300, 100*time.Millisecond, func() error { - if fn, ok := node.(*FullNode); ok { - if fn.blockComponents != nil && fn.blockComponents.Submitter != nil { - nHeight := fn.blockComponents.Submitter.GetDAIncludedHeight() - if nHeight == 0 { - return fmt.Errorf("waiting for DA inclusion") - } - if nHeight >= n { - return nil - } - return fmt.Errorf("current DA inclusion height %d, expected %d", nHeight, n) - } + fn, ok := node.(*FullNode) + if !ok { + return fmt.Errorf("not a full node") + } + + bz, err := fn.Store.GetMetadata(context.Background(), store.DAIncludedHeightKey) + if err != nil || len(bz) != 8 { + return fmt.Errorf("waiting for DA inclusion") + } + nHeight := binary.LittleEndian.Uint64(bz) + if nHeight >= n { + return nil } - return fmt.Errorf("not a full node or submitter not initialized") + return fmt.Errorf("current DA inclusion height %d, expected %d", nHeight, n) }) } diff --git a/node/helpers_test.go b/node/helpers_test.go index 46ded00674..742df34b6b 100644 --- a/node/helpers_test.go +++ b/node/helpers_test.go @@ -16,15 +16,14 @@ import ( coresequencer "github.com/evstack/ev-node/core/sequencer" "github.com/evstack/ev-node/test/testda" "github.com/ipfs/go-datastore" - dssync "github.com/ipfs/go-datastore/sync" "github.com/libp2p/go-libp2p/core/peer" "github.com/rs/zerolog" "github.com/stretchr/testify/require" evconfig "github.com/evstack/ev-node/pkg/config" - "github.com/evstack/ev-node/pkg/p2p" "github.com/evstack/ev-node/pkg/p2p/key" remote_signer "github.com/evstack/ev-node/pkg/signer/noop" + "github.com/evstack/ev-node/pkg/store" "github.com/evstack/ev-node/types" ) @@ -68,7 +67,7 @@ func newDummyDAClient(maxBlobSize uint64) *testda.DummyDA { return getSharedDummyDA(maxBlobSize) } -func createTestComponents(t *testing.T, config evconfig.Config) (coreexecutor.Executor, coresequencer.Sequencer, block.DAClient, *p2p.Client, datastore.Batching, *key.NodeKey, func()) { +func createTestComponents(t *testing.T, config evconfig.Config) (coreexecutor.Executor, coresequencer.Sequencer, block.DAClient, *key.NodeKey, datastore.Batching, func()) { executor := coreexecutor.NewDummyExecutor() sequencer := coresequencer.NewDummySequencer() daClient := newDummyDAClient(0) @@ -79,21 +78,19 @@ func createTestComponents(t *testing.T, config evconfig.Config) (coreexecutor.Ex PrivKey: genesisValidatorKey, PubKey: genesisValidatorKey.GetPublic(), } - logger := zerolog.Nop() - p2pClient, err := p2p.NewClient(config.P2P, p2pKey.PrivKey, dssync.MutexWrap(datastore.NewMapDatastore()), "test-chain", logger, p2p.NopMetrics()) + ds, err := store.NewTestInMemoryKVStore() require.NoError(t, err) - require.NotNil(t, p2pClient) - ds := dssync.MutexWrap(datastore.NewMapDatastore()) stop := daClient.StartHeightTicker(config.DA.BlockTime.Duration) - return executor, sequencer, daClient, p2pClient, ds, p2pKey, stop + return executor, sequencer, daClient, p2pKey, ds, stop } func getTestConfig(t *testing.T, n int) evconfig.Config { // Use a higher base port to reduce chances of conflicts with system services startPort := 40000 // Spread port ranges further apart return evconfig.Config{ - RootDir: t.TempDir(), + RootDir: t.TempDir(), + ClearCache: true, // Clear cache between tests to avoid interference with other tests and slow shutdown on serialization Node: evconfig.NodeConfig{ Aggregator: true, BlockTime: evconfig.DurationWrapper{Duration: 100 * time.Millisecond}, @@ -124,7 +121,7 @@ func newTestNode( executor coreexecutor.Executor, sequencer coresequencer.Sequencer, daClient block.DAClient, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, ds datastore.Batching, stopDAHeightTicker func(), ) (*FullNode, func()) { @@ -133,17 +130,21 @@ func newTestNode( remoteSigner, err := remote_signer.NewNoopSigner(genesisValidatorKey) require.NoError(t, err) + logger := zerolog.Nop() + if testing.Verbose() { + logger = zerolog.New(zerolog.NewTestWriter(t)) + } node, err := NewNode( config, executor, sequencer, daClient, remoteSigner, - p2pClient, + nodeKey, genesis, ds, DefaultMetricsProvider(evconfig.DefaultInstrumentationConfig()), - zerolog.Nop(), + logger, NodeOptions{}, ) require.NoError(t, err) @@ -159,8 +160,8 @@ func newTestNode( func createNodeWithCleanup(t *testing.T, config evconfig.Config) (*FullNode, func()) { resetSharedDummyDA() - executor, sequencer, daClient, p2pClient, ds, _, stopDAHeightTicker := createTestComponents(t, config) - return newTestNode(t, config, executor, sequencer, daClient, p2pClient, ds, stopDAHeightTicker) + executor, sequencer, daClient, nodeKey, ds, stopDAHeightTicker := createTestComponents(t, config) + return newTestNode(t, config, executor, sequencer, daClient, nodeKey, ds, stopDAHeightTicker) } func createNodeWithCustomComponents( @@ -169,11 +170,11 @@ func createNodeWithCustomComponents( executor coreexecutor.Executor, sequencer coresequencer.Sequencer, daClient block.DAClient, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, ds datastore.Batching, stopDAHeightTicker func(), ) (*FullNode, func()) { - return newTestNode(t, config, executor, sequencer, daClient, p2pClient, ds, stopDAHeightTicker) + return newTestNode(t, config, executor, sequencer, daClient, nodeKey, ds, stopDAHeightTicker) } // Creates the given number of nodes the given nodes using the given wait group to synchronize them @@ -192,7 +193,7 @@ func createNodesWithCleanup(t *testing.T, num int, config evconfig.Config) ([]*F aggListenAddress := config.P2P.ListenAddress aggPeers := config.P2P.Peers - executor, sequencer, daClient, p2pClient, ds, aggP2PKey, stopDAHeightTicker := createTestComponents(t, config) + executor, sequencer, daClient, aggP2PKey, ds, stopDAHeightTicker := createTestComponents(t, config) aggPeerID, err := peer.IDFromPrivateKey(aggP2PKey.PrivKey) require.NoError(err) @@ -206,7 +207,7 @@ func createNodesWithCleanup(t *testing.T, num int, config evconfig.Config) ([]*F sequencer, daClient, remoteSigner, - p2pClient, + aggP2PKey, genesis, ds, DefaultMetricsProvider(evconfig.DefaultInstrumentationConfig()), @@ -233,16 +234,16 @@ func createNodesWithCleanup(t *testing.T, num int, config evconfig.Config) ([]*F } config.P2P.ListenAddress = fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 40001+i) config.RPC.Address = fmt.Sprintf("127.0.0.1:%d", 8001+i) - executor, sequencer, daClient, p2pClient, _, nodeP2PKey, stopDAHeightTicker := createTestComponents(t, config) + executor, sequencer, daClient, nodeP2PKey, ds, stopDAHeightTicker := createTestComponents(t, config) node, err := NewNode( config, executor, sequencer, daClient, nil, - p2pClient, + nodeP2PKey, genesis, - dssync.MutexWrap(datastore.NewMapDatastore()), + ds, DefaultMetricsProvider(evconfig.DefaultInstrumentationConfig()), logger, NodeOptions{}, @@ -290,7 +291,7 @@ func startNodeInBackground(t *testing.T, nodes []*FullNode, ctxs []context.Conte } // Helper to cancel all contexts and wait for goroutines with timeout -func shutdownAndWait(t *testing.T, cancels []context.CancelFunc, wg *sync.WaitGroup, timeout time.Duration) { +func shutdownAndWait[T ~func()](t *testing.T, cancels []T, wg *sync.WaitGroup, timeout time.Duration) { for _, cancel := range cancels { cancel() } diff --git a/node/light.go b/node/light.go index bdc4a92351..cc265c7c3f 100644 --- a/node/light.go +++ b/node/light.go @@ -7,6 +7,7 @@ import ( "net/http" "time" + "github.com/evstack/ev-node/pkg/p2p/key" ds "github.com/ipfs/go-datastore" "github.com/rs/zerolog" @@ -38,10 +39,15 @@ type LightNode struct { func newLightNode( conf config.Config, genesis genesis.Genesis, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, database ds.Batching, logger zerolog.Logger, ) (ln *LightNode, err error) { + p2pClient, err := p2p.NewClient(conf.P2P, nodeKey.PrivKey, database, genesis.ChainID, logger, nil) + if err != nil { + return nil, err + } + componentLogger := logger.With().Str("component", "HeaderSyncService").Logger() headerSyncService, err := sync.NewHeaderSyncService(database, conf, genesis, p2pClient, componentLogger) if err != nil { @@ -93,6 +99,7 @@ func (ln *LightNode) Run(parentCtx context.Context) error { ln.Logger, ln.nodeConfig, bestKnown, + nil, ) if err != nil { return fmt.Errorf("error creating RPC handler: %w", err) diff --git a/node/light_test.go b/node/light_test.go index c6def936e6..f459ad54b0 100644 --- a/node/light_test.go +++ b/node/light_test.go @@ -13,7 +13,6 @@ import ( "github.com/evstack/ev-node/pkg/config" "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" p2p_key "github.com/evstack/ev-node/pkg/p2p/key" ) @@ -38,14 +37,9 @@ func TestLightNodeLifecycle(t *testing.T) { require.NoError(err) logger := zerolog.Nop() - p2pMetrics := p2p.NopMetrics() - db := ds_sync.MutexWrap(ds.NewMapDatastore()) - p2pClient, err := p2p.NewClient(conf.P2P, p2pKey.PrivKey, db, gen.ChainID, logger, p2pMetrics) - require.NoError(err) - - ln, err := newLightNode(conf, gen, p2pClient, db, logger) + ln, err := newLightNode(conf, gen, p2pKey, db, logger) require.NoError(err) require.NotNil(ln) diff --git a/node/node.go b/node/node.go index ca4bf15124..7ce087eeeb 100644 --- a/node/node.go +++ b/node/node.go @@ -9,7 +9,7 @@ import ( coresequencer "github.com/evstack/ev-node/core/sequencer" "github.com/evstack/ev-node/pkg/config" "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" + "github.com/evstack/ev-node/pkg/p2p/key" "github.com/evstack/ev-node/pkg/service" "github.com/evstack/ev-node/pkg/signer" ) @@ -34,7 +34,7 @@ func NewNode( sequencer coresequencer.Sequencer, daClient block.DAClient, signer signer.Signer, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, genesis genesis.Genesis, database ds.Batching, metricsProvider MetricsProvider, @@ -42,7 +42,7 @@ func NewNode( nodeOptions NodeOptions, ) (Node, error) { if conf.Node.Light { - return newLightNode(conf, genesis, p2pClient, database, logger) + return newLightNode(conf, genesis, nodeKey, database, logger) } if err := nodeOptions.BlockOptions.Validate(); err != nil { @@ -51,7 +51,7 @@ func NewNode( return newFullNode( conf, - p2pClient, + nodeKey, signer, genesis, database, diff --git a/node/single_sequencer_integration_test.go b/node/single_sequencer_integration_test.go index 754f8017ce..809bc952ce 100644 --- a/node/single_sequencer_integration_test.go +++ b/node/single_sequencer_integration_test.go @@ -16,6 +16,7 @@ import ( coreexecutor "github.com/evstack/ev-node/core/execution" evconfig "github.com/evstack/ev-node/pkg/config" + "github.com/evstack/ev-node/pkg/store" "github.com/evstack/ev-node/test/testda" ) @@ -68,6 +69,7 @@ func (s *FullNodeTestSuite) SetupTest() { // Start the node in a goroutine using Run instead of Start s.startNodeInBackground(s.node) + s.T().Cleanup(func() { shutdownAndWait(s.T(), []context.CancelFunc{s.cancel}, &s.runningWg, 10*time.Second) }) // Verify that the node is running and producing blocks err := waitForFirstBlock(s.node, Header) @@ -78,7 +80,7 @@ func (s *FullNodeTestSuite) SetupTest() { require.NoError(err, "Failed to get DA inclusion") // Verify block components are properly initialized - require.NotNil(s.node.blockComponents, "Block components should be initialized") + require.NotNil(castState(s.T(), s.node).bc, "Block components should be initialized") } // TearDownTest cancels the test context and waits for the node to stop, ensuring proper cleanup after each test. @@ -125,13 +127,13 @@ func (s *FullNodeTestSuite) TestBlockProduction() { testTx := []byte("test transaction") // Inject transaction through the node's block components (same as integration tests) - if s.node.blockComponents != nil && s.node.blockComponents.Executor != nil { + if state := castState(s.T(), s.node); state.bc != nil && state.bc.Executor != nil { // Access the core executor from the block executor - coreExec := s.node.blockComponents.Executor.GetCoreExecutor() + coreExec := state.bc.Executor.GetCoreExecutor() if dummyExec, ok := coreExec.(interface{ InjectTx([]byte) }); ok { dummyExec.InjectTx(testTx) // Notify the executor about new transactions - s.node.blockComponents.Executor.NotifyNewTransactions() + state.bc.Executor.NotifyNewTransactions() } else { s.T().Fatalf("Could not cast core executor to DummyExecutor") } @@ -183,12 +185,12 @@ func (s *FullNodeTestSuite) TestBlockProduction() { // It injects a transaction, waits for several blocks to be produced and DA-included, and asserts that all blocks are DA included. func (s *FullNodeTestSuite) TestSubmitBlocksToDA() { // Inject transaction through the node's block components - if s.node.blockComponents != nil && s.node.blockComponents.Executor != nil { - coreExec := s.node.blockComponents.Executor.GetCoreExecutor() + if state := castState(s.T(), s.node); state.bc != nil && state.bc.Executor != nil { + coreExec := state.bc.Executor.GetCoreExecutor() if dummyExec, ok := coreExec.(interface{ InjectTx([]byte) }); ok { dummyExec.InjectTx([]byte("test transaction")) // Notify the executor about new transactions - s.node.blockComponents.Executor.NotifyNewTransactions() + state.bc.Executor.NotifyNewTransactions() } else { s.T().Fatalf("Could not cast core executor to DummyExecutor") } @@ -207,7 +209,7 @@ func (s *FullNodeTestSuite) TestSubmitBlocksToDA() { header, data, err := s.node.Store.GetBlockData(s.ctx, height) require.NoError(s.T(), err) - ok, err := s.node.blockComponents.Submitter.IsHeightDAIncluded(height, header, data) + ok, err := castState(s.T(), s.node).bc.Submitter.IsHeightDAIncluded(height, header, data) require.NoError(s.T(), err) require.True(s.T(), ok, "Block at height %d is not DA included", height) } @@ -219,8 +221,7 @@ func (s *FullNodeTestSuite) TestGenesisInitialization() { require := require.New(s.T()) // Verify genesis state - state, err := s.node.Store.GetState(s.ctx) - require.NoError(err) + state := castState(s.T(), s.node).bc.GetLastState() require.Equal(s.node.genesis.InitialHeight, state.InitialHeight) require.Equal(s.node.genesis.ChainID, state.ChainID) } @@ -232,8 +233,10 @@ func TestStateRecovery(t *testing.T) { // Set up one sequencer config := getTestConfig(t, 1) - executor, sequencer, dac, p2pClient, ds, _, stopDAHeightTicker := createTestComponents(t, config) - node, cleanup := createNodeWithCustomComponents(t, config, executor, sequencer, dac, p2pClient, ds, stopDAHeightTicker) + executor, sequencer, dac, nodeKey, _, stopDAHeightTicker := createTestComponents(t, config) + ds, err := store.NewDefaultKVStore(config.RootDir, "db", "test") + require.NoError(err) + node, cleanup := createNodeWithCustomComponents(t, config, executor, sequencer, dac, nodeKey, ds, stopDAHeightTicker) defer cleanup() var runningWg sync.WaitGroup @@ -243,6 +246,7 @@ func TestStateRecovery(t *testing.T) { // Start the sequencer first startNodeInBackground(t, []*FullNode{node}, []context.Context{ctx}, &runningWg, 0, nil) + t.Cleanup(func() { shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 10*time.Second) }) blocksToWaitFor := uint64(20) // Wait for the sequencer to produce at first block @@ -257,8 +261,10 @@ func TestStateRecovery(t *testing.T) { shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 60*time.Second) // Create a new node instance using the same components - executor, sequencer, dac, p2pClient, _, _, stopDAHeightTicker = createTestComponents(t, config) - node, cleanup = createNodeWithCustomComponents(t, config, executor, sequencer, dac, p2pClient, ds, stopDAHeightTicker) + executor, sequencer, dac, nodeKey, _, stopDAHeightTicker = createTestComponents(t, config) + ds, err = store.NewDefaultKVStore(config.RootDir, "db", "test") + require.NoError(err) + node, cleanup = createNodeWithCustomComponents(t, config, executor, sequencer, dac, nodeKey, ds, stopDAHeightTicker) defer cleanup() // Verify state persistence @@ -286,6 +292,7 @@ func TestMaxPendingHeadersAndData(t *testing.T) { var runningWg sync.WaitGroup startNodeInBackground(t, []*FullNode{node}, []context.Context{ctx}, &runningWg, 0, nil) + t.Cleanup(func() { shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 10*time.Second) }) // Wait blocks to be produced up to max pending numExtraBlocks := uint64(5) @@ -295,9 +302,6 @@ func TestMaxPendingHeadersAndData(t *testing.T) { height, err := getNodeHeight(node, Store) require.NoError(err) require.LessOrEqual(height, config.Node.MaxPendingHeadersAndData) - - // Stop the node and wait for shutdown - shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 10*time.Second) } // TestBatchQueueThrottlingWithDAFailure tests that when DA layer fails and MaxPendingHeadersAndData @@ -314,7 +318,7 @@ func TestBatchQueueThrottlingWithDAFailure(t *testing.T) { config.DA.BlockTime = evconfig.DurationWrapper{Duration: 100 * time.Millisecond} // Longer DA time to ensure blocks are produced first // Create test components - executor, sequencer, dummyDA, p2pClient, ds, _, stopDAHeightTicker := createTestComponents(t, config) + executor, sequencer, dummyDA, ds, nodeKey, stopDAHeightTicker := createTestComponents(t, config) defer stopDAHeightTicker() // Cast executor to DummyExecutor so we can inject transactions @@ -326,14 +330,17 @@ func TestBatchQueueThrottlingWithDAFailure(t *testing.T) { require.True(ok, "Expected testda.DummyDA implementation") // Create node with components - node, cleanup := createNodeWithCustomComponents(t, config, executor, sequencer, dummyDAImpl, p2pClient, ds, func() {}) + node, cleanup := createNodeWithCustomComponents(t, config, executor, sequencer, dummyDAImpl, ds, nodeKey, func() {}) defer cleanup() ctx, cancel := context.WithCancel(t.Context()) defer cancel() var runningWg sync.WaitGroup - startNodeInBackground(t, []*FullNode{node}, []context.Context{ctx}, &runningWg, 0, nil) + errChan := make(chan error, 1) + startNodeInBackground(t, []*FullNode{node}, []context.Context{ctx}, &runningWg, 0, errChan) + t.Cleanup(func() { shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 10*time.Second) }) + require.Len(errChan, 0, "Expected no errors when starting node") // Wait for the node to start producing blocks waitForBlockN(t, 1, node, config.Node.BlockTime.Duration) @@ -386,7 +393,7 @@ func TestBatchQueueThrottlingWithDAFailure(t *testing.T) { finalHeight, err := getNodeHeight(node, Store) require.NoError(err) t.Logf("Final height: %d", finalHeight) - + cancel() // stop the node // The height should not have increased much due to MaxPendingHeadersAndData limit // Allow at most 3 additional blocks due to timing and pending blocks in queue heightIncrease := finalHeight - heightAfterDAFailure @@ -420,6 +427,7 @@ func waitForBlockN(t *testing.T, n uint64, node *FullNode, blockInterval time.Du return got >= n }, timeout[0], blockInterval/2) } + func TestReadinessEndpointWhenBlockProductionStops(t *testing.T) { require := require.New(t) @@ -434,13 +442,17 @@ func TestReadinessEndpointWhenBlockProductionStops(t *testing.T) { node, cleanup := createNodeWithCleanup(t, config) defer cleanup() - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() var runningWg sync.WaitGroup - startNodeInBackground(t, []*FullNode{node}, []context.Context{ctx}, &runningWg, 0, nil) + errChan := make(chan error, 1) + startNodeInBackground(t, []*FullNode{node}, []context.Context{ctx}, &runningWg, 0, errChan) + t.Cleanup(func() { shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 10*time.Second) }) + require.Len(errChan, 0, "Expected no errors when starting node") - waitForBlockN(t, 1, node, config.Node.BlockTime.Duration) + waitForBlockN(t, 2, node, config.Node.BlockTime.Duration) + require.Len(errChan, 0, "Expected no errors when starting node") require.Eventually(func() bool { resp, err := httpClient.Get("http://" + config.RPC.Address + "/health/ready") @@ -465,6 +477,4 @@ func TestReadinessEndpointWhenBlockProductionStops(t *testing.T) { defer resp.Body.Close() return resp.StatusCode == http.StatusServiceUnavailable }, 10*time.Second, 100*time.Millisecond, "Readiness should be UNREADY after aggregator stops producing blocks (5x block time)") - - shutdownAndWait(t, []context.CancelFunc{cancel}, &runningWg, 10*time.Second) } diff --git a/node/single_sequencer_test.go b/node/single_sequencer_test.go index b0bb077f38..5675435266 100644 --- a/node/single_sequencer_test.go +++ b/node/single_sequencer_test.go @@ -50,4 +50,5 @@ func TestStartup(t *testing.T) { // Run the cleanup function from setupTestNodeWithCleanup cleanup() + time.Sleep(time.Second) // shutdown takes some time to persist caches } diff --git a/pkg/cmd/run_node.go b/pkg/cmd/run_node.go index 92a3c1ba7a..777bc0aabc 100644 --- a/pkg/cmd/run_node.go +++ b/pkg/cmd/run_node.go @@ -23,7 +23,7 @@ import ( rollconf "github.com/evstack/ev-node/pkg/config" blobrpc "github.com/evstack/ev-node/pkg/da/jsonrpc" genesispkg "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" + "github.com/evstack/ev-node/pkg/p2p/key" "github.com/evstack/ev-node/pkg/signer" "github.com/evstack/ev-node/pkg/signer/file" "github.com/evstack/ev-node/pkg/telemetry" @@ -82,7 +82,7 @@ func StartNode( cmd *cobra.Command, executor coreexecutor.Executor, sequencer coresequencer.Sequencer, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, datastore datastore.Batching, nodeConfig rollconf.Config, genesis genesispkg.Genesis, @@ -170,7 +170,7 @@ func StartNode( sequencer, daClient, signer, - p2pClient, + nodeKey, genesis, datastore, metrics, diff --git a/pkg/cmd/run_node_test.go b/pkg/cmd/run_node_test.go index 6ed94033af..2e58c1c637 100644 --- a/pkg/cmd/run_node_test.go +++ b/pkg/cmd/run_node_test.go @@ -13,7 +13,7 @@ import ( "github.com/evstack/ev-node/node" rollconf "github.com/evstack/ev-node/pkg/config" genesis "github.com/evstack/ev-node/pkg/genesis" - "github.com/evstack/ev-node/pkg/p2p" + "github.com/evstack/ev-node/pkg/p2p/key" "github.com/evstack/ev-node/pkg/signer" filesigner "github.com/evstack/ev-node/pkg/signer/file" "github.com/ipfs/go-datastore" @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" ) -func createTestComponents(_ context.Context, t *testing.T) (coreexecutor.Executor, coresequencer.Sequencer, signer.Signer, *p2p.Client, datastore.Batching, func()) { +func createTestComponents(_ context.Context, t *testing.T) (coreexecutor.Executor, coresequencer.Sequencer, signer.Signer, *key.NodeKey, datastore.Batching, func()) { executor := coreexecutor.NewDummyExecutor() sequencer := coresequencer.NewDummySequencer() tmpDir := t.TempDir() @@ -31,10 +31,9 @@ func createTestComponents(_ context.Context, t *testing.T) (coreexecutor.Executo panic(err) } // Create a dummy P2P client and datastore for testing - p2pClient := &p2p.Client{} ds := datastore.NewMapDatastore() - return executor, sequencer, keyProvider, p2pClient, ds, func() {} + return executor, sequencer, keyProvider, nil, ds, func() {} } func TestParseFlags(t *testing.T) { @@ -69,13 +68,13 @@ func TestParseFlags(t *testing.T) { args := append([]string{"start"}, flags...) - executor, sequencer, keyProvider, p2pClient, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) + executor, sequencer, keyProvider, nodeKey, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) defer stopDAHeightTicker() nodeConfig := rollconf.DefaultConfig() nodeConfig.RootDir = t.TempDir() - newRunNodeCmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, p2pClient, ds, nodeConfig) + newRunNodeCmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, nodeKey, ds, nodeConfig) _ = newRunNodeCmd.Flags().Set(rollconf.FlagRootDir, "custom/root/dir") if err := newRunNodeCmd.ParseFlags(args); err != nil { t.Errorf("Error: %v", err) @@ -144,13 +143,13 @@ func TestAggregatorFlagInvariants(t *testing.T) { for i, flags := range flagVariants { args := append([]string{"start"}, flags...) - executor, sequencer, keyProvider, p2pClient, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) + executor, sequencer, keyProvider, nodeKey, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) defer stopDAHeightTicker() nodeConfig := rollconf.DefaultConfig() nodeConfig.RootDir = t.TempDir() - newRunNodeCmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, p2pClient, ds, nodeConfig) + newRunNodeCmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, nodeKey, ds, nodeConfig) _ = newRunNodeCmd.Flags().Set(rollconf.FlagRootDir, "custom/root/dir") if err := newRunNodeCmd.ParseFlags(args); err != nil { @@ -180,13 +179,13 @@ func TestDefaultAggregatorValue(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - executor, sequencer, keyProvider, p2pClient, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) + executor, sequencer, keyProvider, nodeKey, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) defer stopDAHeightTicker() nodeConfig := rollconf.DefaultConfig() nodeConfig.RootDir = t.TempDir() - newRunNodeCmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, p2pClient, ds, nodeConfig) + newRunNodeCmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, nodeKey, ds, nodeConfig) _ = newRunNodeCmd.Flags().Set(rollconf.FlagRootDir, "custom/root/dir") // Create a new command without specifying any flags @@ -262,10 +261,10 @@ func TestCentralizedAddresses(t *testing.T) { "--rollkit.da.address=http://central-da:26657", } - executor, sequencer, keyProvider, p2pClient, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) + executor, sequencer, keyProvider, nodeKey, ds, stopDAHeightTicker := createTestComponents(context.Background(), t) defer stopDAHeightTicker() - cmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, p2pClient, ds, nodeConfig) + cmd := newRunNodeCmd(t.Context(), executor, sequencer, keyProvider, nodeKey, ds, nodeConfig) _ = cmd.Flags().Set(rollconf.FlagRootDir, "custom/root/dir") if err := cmd.ParseFlags(args); err != nil { t.Fatalf("ParseFlags error: %v", err) @@ -528,7 +527,7 @@ func TestStartNodeSignerPathResolution(t *testing.T) { func TestStartNodeErrors(t *testing.T) { baseCtx := context.Background() - executor, sequencer, _, p2pClient, ds, stopDAHeightTicker := createTestComponents(baseCtx, t) + executor, sequencer, _, nodeKey, ds, stopDAHeightTicker := createTestComponents(baseCtx, t) defer stopDAHeightTicker() tmpDir := t.TempDir() @@ -634,7 +633,7 @@ func TestStartNodeErrors(t *testing.T) { dummySigner, _ := filesigner.CreateFileSystemSigner(dummySignerPath, []byte("password")) - cmd := newRunNodeCmd(baseCtx, executor, sequencer, dummySigner, p2pClient, ds, nodeConfig) + cmd := newRunNodeCmd(baseCtx, executor, sequencer, dummySigner, nodeKey, ds, nodeConfig) cmd.SetContext(baseCtx) @@ -645,7 +644,7 @@ func TestStartNodeErrors(t *testing.T) { runFunc := func() { currentTestLogger := zerolog.Nop() - err := StartNode(currentTestLogger, cmd, executor, sequencer, p2pClient, ds, nodeConfig, testGenesis, node.NodeOptions{}) + err := StartNode(currentTestLogger, cmd, executor, sequencer, nodeKey, ds, nodeConfig, testGenesis, node.NodeOptions{}) if tc.expectedError != "" { assert.ErrorContains(t, err, tc.expectedError) } else { @@ -662,7 +661,7 @@ func TestStartNodeErrors(t *testing.T) { } else { assert.NotPanics(t, runFunc) checkLogger := zerolog.Nop() - err := StartNode(checkLogger, cmd, executor, sequencer, p2pClient, ds, nodeConfig, testGenesis, node.NodeOptions{}) + err := StartNode(checkLogger, cmd, executor, sequencer, nodeKey, ds, nodeConfig, testGenesis, node.NodeOptions{}) if tc.expectedError != "" { assert.ErrorContains(t, err, tc.expectedError) } @@ -677,7 +676,7 @@ func newRunNodeCmd( executor coreexecutor.Executor, sequencer coresequencer.Sequencer, remoteSigner signer.Signer, - p2pClient *p2p.Client, + nodeKey *key.NodeKey, datastore datastore.Batching, nodeConfig rollconf.Config, ) *cobra.Command { @@ -696,7 +695,7 @@ func newRunNodeCmd( Aliases: []string{"node", "run"}, Short: "Run the rollkit node", RunE: func(cmd *cobra.Command, args []string) error { - return StartNode(zerolog.Nop(), cmd, executor, sequencer, p2pClient, datastore, nodeConfig, testGenesis, node.NodeOptions{}) + return StartNode(zerolog.Nop(), cmd, executor, sequencer, nodeKey, datastore, nodeConfig, testGenesis, node.NodeOptions{}) }, } diff --git a/pkg/config/config.go b/pkg/config/config.go index 0710997e59..03bbb4051b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -139,6 +139,29 @@ const ( FlagRPCAddress = FlagPrefixEvnode + "rpc.address" // FlagRPCEnableDAVisualization is a flag for enabling DA visualization endpoints FlagRPCEnableDAVisualization = FlagPrefixEvnode + "rpc.enable_da_visualization" + + // Raft configuration flags + + // FlagRaftEnable is a flag for enabling Raft consensus + FlagRaftEnable = FlagPrefixEvnode + "raft.enable" + // FlagRaftNodeID is a flag for specifying the Raft node ID + FlagRaftNodeID = FlagPrefixEvnode + "raft.node_id" + // FlagRaftAddr is a flag for specifying the Raft communication address + FlagRaftAddr = FlagPrefixEvnode + "raft.raft_addr" + // FlagRaftDir is a flag for specifying the Raft data directory + FlagRaftDir = FlagPrefixEvnode + "raft.raft_dir" + // FlagRaftBootstrap is a flag for bootstrapping a new Raft cluster + FlagRaftBootstrap = FlagPrefixEvnode + "raft.bootstrap" + // FlagRaftPeers is a flag for specifying Raft peer addresses + FlagRaftPeers = FlagPrefixEvnode + "raft.peers" + // FlagRaftSnapCount is a flag for specifying snapshot frequency + FlagRaftSnapCount = FlagPrefixEvnode + "raft.snap_count" + // FlagRaftSendTimeout max time to wait for a message to be sent to a peer + FlagRaftSendTimeout = FlagPrefixEvnode + "raft.send_timeout" + // FlagRaftHeartbeatTimeout is a flag for specifying heartbeat timeout + FlagRaftHeartbeatTimeout = FlagPrefixEvnode + "raft.heartbeat_timeout" + // FlagRaftLeaderLeaseTimeout is a flag for specifying leader lease timeout + FlagRaftLeaderLeaseTimeout = FlagPrefixEvnode + "raft.leader_lease_timeout" ) // Config stores Rollkit configuration. @@ -168,6 +191,9 @@ type Config struct { // Remote signer configuration Signer SignerConfig `mapstructure:"signer" yaml:"signer"` + + // Raft consensus configuration + Raft RaftConfig `mapstructure:"raft" yaml:"raft"` } // DAConfig contains all Data Availability configuration parameters @@ -250,6 +276,50 @@ type RPCConfig struct { EnableDAVisualization bool `mapstructure:"enable_da_visualization" yaml:"enable_da_visualization" comment:"Enable DA visualization endpoints for monitoring blob submissions. Default: false"` } +// RaftConfig contains all Raft consensus configuration parameters +type RaftConfig struct { + Enable bool `mapstructure:"enable" yaml:"enable" comment:"Enable Raft consensus for leader election and state replication"` + NodeID string `mapstructure:"node_id" yaml:"node_id" comment:"Unique identifier for this node in the Raft cluster"` + RaftAddr string `mapstructure:"raft_addr" yaml:"raft_addr" comment:"Address for Raft communication (host:port)"` + RaftDir string `mapstructure:"raft_dir" yaml:"raft_dir" comment:"Directory for Raft logs and snapshots"` + Bootstrap bool `mapstructure:"bootstrap" yaml:"bootstrap" comment:"Bootstrap a new Raft cluster (only for the first node)"` + Peers string `mapstructure:"peers" yaml:"peers" comment:"Comma-separated list of peer Raft addresses (nodeID@host:port)"` + SnapCount uint64 `mapstructure:"snap_count" yaml:"snap_count" comment:"Number of log entries between snapshots"` + SendTimeout time.Duration `mapstructure:"send_timeout" yaml:"send_timeout" comment:"Max duration to wait for a message to be sent to a peer"` + HeartbeatTimeout time.Duration `mapstructure:"heartbeat_timeout" yaml:"heartbeat_timeout" comment:"Time between leader heartbeats to followers"` + LeaderLeaseTimeout time.Duration `mapstructure:"leader_lease_timeout" yaml:"leader_lease_timeout" comment:"Duration of the leader lease"` +} + +func (c RaftConfig) Validate() error { + if !c.Enable { + return nil + } + var multiErr error + if c.NodeID == "" { + multiErr = fmt.Errorf("node ID is required") + } + if c.RaftAddr == "" { + multiErr = errors.Join(multiErr, fmt.Errorf("raft address is required")) + } + if c.RaftDir == "" { + multiErr = errors.Join(multiErr, fmt.Errorf("raft directory is required")) + } + + if c.SendTimeout <= 0 { + multiErr = errors.Join(multiErr, fmt.Errorf("send timeout must be positive")) + } + + if c.HeartbeatTimeout <= 0 { + multiErr = errors.Join(multiErr, fmt.Errorf("heartbeat timeout must be positive")) + } + + if c.LeaderLeaseTimeout <= 0 { + multiErr = errors.Join(multiErr, fmt.Errorf("leader lease timeout must be positive")) + } + + return multiErr +} + // Validate validates the config and ensures that the root directory exists. // It creates the directory if it does not exist. func (c *Config) Validate() error { @@ -291,7 +361,9 @@ func (c *Config) Validate() error { return fmt.Errorf("LazyBlockInterval (%v) must be greater than BlockTime (%v) in lazy mode", c.Node.LazyBlockInterval.Duration, c.Node.BlockTime.Duration) } - + if err := c.Raft.Validate(); err != nil { + return err + } return nil } @@ -395,6 +467,18 @@ func AddFlags(cmd *cobra.Command) { // flag constraints cmd.MarkFlagsMutuallyExclusive(FlagLight, FlagAggregator) + + // Raft configuration flags + cmd.Flags().Bool(FlagRaftEnable, def.Raft.Enable, "enable Raft consensus for leader election and state replication") + cmd.Flags().String(FlagRaftNodeID, def.Raft.NodeID, "unique identifier for this node in the Raft cluster") + cmd.Flags().String(FlagRaftAddr, def.Raft.RaftAddr, "address for Raft communication (host:port)") + cmd.Flags().String(FlagRaftDir, def.Raft.RaftDir, "directory for Raft logs and snapshots") + cmd.Flags().Bool(FlagRaftBootstrap, def.Raft.Bootstrap, "bootstrap a new Raft cluster (only for the first node)") + cmd.Flags().String(FlagRaftPeers, def.Raft.Peers, "comma-separated list of peer Raft addresses (nodeID@host:port)") + cmd.Flags().Uint64(FlagRaftSnapCount, def.Raft.SnapCount, "number of log entries between snapshots") + cmd.Flags().Duration(FlagRaftSendTimeout, def.Raft.SendTimeout, "max duration to wait for a message to be sent to a peer") + cmd.Flags().Duration(FlagRaftHeartbeatTimeout, def.Raft.HeartbeatTimeout, "time between leader heartbeats to followers") + cmd.Flags().Duration(FlagRaftLeaderLeaseTimeout, def.Raft.LeaderLeaseTimeout, "duration of the leader lease") } // Load loads the node configuration in the following order of precedence: diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 57506c0cf7..a3eb6a1d04 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -112,7 +112,7 @@ func TestAddFlags(t *testing.T) { assertFlagValue(t, flags, FlagRPCEnableDAVisualization, DefaultConfig().RPC.EnableDAVisualization) // Count the number of flags we're explicitly checking - expectedFlagCount := 49 // Update this number if you add more flag checks above + expectedFlagCount := 59 // Update this number if you add more flag checks above // Get the actual number of flags (both regular and persistent) actualFlagCount := 0 @@ -361,6 +361,84 @@ func TestDAConfig_GetDataNamespace(t *testing.T) { } } +func TestRaftConfig_Validate(t *testing.T) { + // helper to build a valid base config per test (temp dir varies per subtest) + newValid := func() RaftConfig { + return RaftConfig{ + Enable: true, + NodeID: "node-1", + RaftAddr: "127.0.0.1:9000", + RaftDir: t.TempDir(), + Bootstrap: false, + Peers: "", + SnapCount: 1, + SendTimeout: 1 * time.Second, + HeartbeatTimeout: 1 * time.Second, + LeaderLeaseTimeout: 1 * time.Second, + } + } + + specs := map[string]struct { + mutate func(c *RaftConfig) + expErr string + }{ + "disabled": { + mutate: func(c *RaftConfig) { c.Enable = false }, + }, + "valid": { + mutate: func(c *RaftConfig) {}, + }, + "empty node id": { + mutate: func(c *RaftConfig) { c.NodeID = "" }, + expErr: "node ID is required", + }, + "empty raft addr": { + mutate: func(c *RaftConfig) { c.RaftAddr = "" }, + expErr: "raft address is required", + }, + "empty raft dir": { + mutate: func(c *RaftConfig) { c.RaftDir = "" }, + expErr: "raft directory is required", + }, + "non-positive send timeout": { + mutate: func(c *RaftConfig) { c.SendTimeout = 0 }, + expErr: "send timeout must be positive", + }, + "non-positive heartbeat timeout": { + mutate: func(c *RaftConfig) { c.HeartbeatTimeout = 0 }, + expErr: "heartbeat timeout must be positive", + }, + "non-positive leader lease timeout": { + mutate: func(c *RaftConfig) { c.LeaderLeaseTimeout = 0 }, + expErr: "leader lease timeout must be positive", + }, + "multiple invalid returns last": { + mutate: func(c *RaftConfig) { + c.NodeID = "" + c.RaftAddr = "" + c.HeartbeatTimeout = 0 + c.LeaderLeaseTimeout = 0 + }, + expErr: "node ID is required\nraft address is required\nheartbeat timeout must be positive\nleader lease timeout must be positive", + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + cfg := newValid() + spec.mutate(&cfg) + err := cfg.Validate() + + if spec.expErr != "" { + require.Error(t, err) + assert.Equal(t, spec.expErr, err.Error()) + return + } + require.NoError(t, err) + }) + } +} + func assertFlagValue(t *testing.T, flags *pflag.FlagSet, name string, expectedValue any) { flag := flags.Lookup(name) assert.NotNil(t, flag, "Flag %s should exist", name) diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 062c9fe19c..7d2053108c 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -93,6 +93,12 @@ func DefaultConfig() Config { Address: "127.0.0.1:7331", EnableDAVisualization: false, }, + Raft: RaftConfig{ + SendTimeout: 200 * time.Millisecond, + HeartbeatTimeout: 350 * time.Millisecond, + LeaderLeaseTimeout: 175 * time.Millisecond, + RaftDir: filepath.Join(DefaultRootDir, "raft"), + }, } } diff --git a/pkg/raft/election.go b/pkg/raft/election.go new file mode 100644 index 0000000000..20a10e8dac --- /dev/null +++ b/pkg/raft/election.go @@ -0,0 +1,162 @@ +package raft + +import ( + "context" + "errors" + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/hashicorp/raft" + "github.com/rs/zerolog" +) + +var ErrLeadershipLost = fmt.Errorf("leader lock lost") + +// Runnable represents a component that can be started and performs specific operations while running. +// Run runs the main logic of the component using the provided context and returns an error if it fails. +// IsSynced checks whether the component is synced with the given RaftBlockState. +type Runnable interface { + Run(ctx context.Context) error + IsSynced(*RaftBlockState) bool +} + +type sourceNode interface { + Config() Config + leaderCh() <-chan bool + leaderID() string + NodeID() string + GetState() *RaftBlockState + leadershipTransfer() error + waitForMsgsLanded(duration time.Duration) error +} + +type DynamicLeaderElection struct { + logger zerolog.Logger + leaderFactory, followerFactory func() (Runnable, error) + node sourceNode + running atomic.Bool +} + +// NewDynamicLeaderElection constructor +func NewDynamicLeaderElection( + logger zerolog.Logger, + leaderFactory func() (Runnable, error), + followerFactory func() (Runnable, error), + node *Node, +) *DynamicLeaderElection { + return &DynamicLeaderElection{logger: logger, leaderFactory: leaderFactory, followerFactory: followerFactory, node: node} +} + +// Run starts the leader election process and manages the lifecycle of leader or follower roles based on Raft events. +// This is a blocking call. +func (d *DynamicLeaderElection) Run(ctx context.Context) error { + var isStarted, isCurrentlyLeader bool + var workerCancel context.CancelFunc = func() {} // noop + var wg sync.WaitGroup + errCh := make(chan error, 1) + + defer func() { + workerCancel() + wg.Wait() + close(errCh) + }() + + startWorker := func(name string, workerFunc func(ctx context.Context) error) { + workerCancel() + workerCtx, cancel := context.WithCancel(ctx) + workerCancel = cancel + wg.Add(1) + + // call workerFunc in a separate goroutine + go func(childCtx context.Context) { + defer wg.Done() + if err := workerFunc(childCtx); err != nil && !errors.Is(err, context.Canceled) { + select { + case errCh <- fmt.Errorf(name+" worker exited unexpectedly: %s", err): + default: // do not block + } + } + }(workerCtx) + } + ticker := time.NewTicker(300 * time.Millisecond) + defer ticker.Stop() + d.running.Store(true) + defer d.running.Store(false) + var runnable Runnable + for { + select { + case becameLeader := <-d.node.leaderCh(): + d.logger.Info().Msg("Raft leader changed notification") + if becameLeader && !isCurrentlyLeader { // new leader + if isStarted { + d.logger.Info().Msg("became leader, stopping follower operations") + // wait for in flight raft msgs to land, this is critical to avoid double sign on old state + raftSynced := d.node.waitForMsgsLanded(d.node.Config().SendTimeout) == nil + if d.node.leaderID() != d.node.NodeID() { + d.logger.Info().Msg("lost leadership during sync wait") + continue + } + if !raftSynced || !runnable.IsSynced(d.node.GetState()) { + d.logger.Info().Uint64("raft_state_height", d.node.GetState().Height). + Msg("became leader, but not synced. Pass on leadership") + if err := d.node.leadershipTransfer(); err != nil && !errors.Is(err, raft.ErrNotLeader) { + // the leadership transfer can fail due to no suitable leader. Better stop than double sign on old state + return err + } + continue + } + d.logger.Info().Msg("became leader, stopping follower operations") + workerCancel() + wg.Wait() + } + d.logger.Info().Msg("starting leader operations") + var err error + if runnable, err = d.leaderFactory(); err != nil { + return err + } + isStarted = true + isCurrentlyLeader = true + startWorker("leader", runnable.Run) + } else if !becameLeader && isCurrentlyLeader { // lost leadership + workerCancel() + d.logger.Info().Msg("lost leadership") + return ErrLeadershipLost + } else if !becameLeader && !isCurrentlyLeader && !isStarted { // start as a follower + d.logger.Info().Msg("starting follower operations") + isStarted = true + var err error + if runnable, err = d.followerFactory(); err != nil { + return err + } + startWorker("follower", runnable.Run) + } + case <-ticker.C: // LeaderCh fires only when leader changes not on initial election + if isStarted { + ticker.Stop() + ticker.C = nil + continue + } + if leaderID := d.node.leaderID(); leaderID != "" && leaderID != d.node.NodeID() { + ticker.Stop() + ticker.C = nil + d.logger.Info().Msg("starting follower operations") + isStarted = true + var err error + if runnable, err = d.followerFactory(); err != nil { + return err + } + startWorker("follower", runnable.Run) + } + case err := <-errCh: + return err + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (d *DynamicLeaderElection) IsRunning() bool { + return d.running.Load() +} diff --git a/pkg/raft/election_test.go b/pkg/raft/election_test.go new file mode 100644 index 0000000000..68caf76064 --- /dev/null +++ b/pkg/raft/election_test.go @@ -0,0 +1,290 @@ +package raft + +import ( + "context" + "errors" + "strings" + "sync" + "testing" + "time" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDynamicLeaderElectionRun(t *testing.T) { + specs := map[string]struct { + setup func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) + assertF func(t *testing.T, err error) + }{ + "start as follower via ticker": { + setup: func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) { + m := newMocksourceNode(t) + leaderCh := make(chan bool, 1) + m.EXPECT().leaderCh().Return((<-chan bool)(leaderCh)) + m.EXPECT().leaderID().Return("other") + m.EXPECT().NodeID().Return("self") + + started := make(chan struct{}) + follower := &testRunnable{startedCh: started} + leader := &testRunnable{} + + logger := zerolog.Nop() + d := &DynamicLeaderElection{logger: logger, node: m, + leaderFactory: func() (Runnable, error) { return leader, nil }, + followerFactory: func() (Runnable, error) { return follower, nil }, + } + ctx, cancel := context.WithCancel(t.Context()) + + // Wait for follower to start via ticker path + var once sync.Once + go func() { + <-started + once.Do(cancel) + }() + return d, ctx, func() { once.Do(cancel) } + }, + assertF: func(t *testing.T, err error) { + require.Error(t, err) + assert.ErrorIs(t, err, context.Canceled) + }, + }, + "leader loss returns": { + setup: func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) { + m := newMocksourceNode(t) + leaderCh := make(chan bool, 2) + m.EXPECT().leaderCh().Return((<-chan bool)(leaderCh)) + + leader := &testRunnable{runFn: func(ctx context.Context) error { + // block until canceled by election + <-ctx.Done() + return ctx.Err() + }} + logger := zerolog.Nop() + d := &DynamicLeaderElection{logger: logger, node: m, + leaderFactory: func() (Runnable, error) { return leader, nil }, + followerFactory: func() (Runnable, error) { return &testRunnable{}, nil }, + } + + ctx, cancel := context.WithCancel(t.Context()) + // Signal become leader then loss + go func() { + leaderCh <- true + time.Sleep(2 * time.Millisecond) + leaderCh <- false + }() + return d, ctx, cancel + }, + assertF: func(t *testing.T, err error) { + require.Error(t, err) + assert.ErrorIs(t, err, ErrLeadershipLost) + }, + }, + "worker error surfaces": { + setup: func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) { + m := newMocksourceNode(t) + leaderCh := make(chan bool, 1) + m.EXPECT().leaderCh().Return((<-chan bool)(leaderCh)) + + wantErr := errors.New("boom") + leader := &testRunnable{runFn: func(ctx context.Context) error { return wantErr }} + logger := zerolog.Nop() + d := &DynamicLeaderElection{logger: logger, node: m, + leaderFactory: func() (Runnable, error) { return leader, nil }, + followerFactory: func() (Runnable, error) { return &testRunnable{}, nil }, + } + ctx, cancel := context.WithCancel(t.Context()) + go func() { leaderCh <- true }() + return d, ctx, cancel + }, + assertF: func(t *testing.T, err error) { + require.Error(t, err) + assert.True(t, strings.Contains(err.Error(), "leader worker exited unexpectedly: boom"), err.Error()) + }, + }, + "leadership transfer when not synced": { + setup: func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) { + m := newMocksourceNode(t) + leaderCh := make(chan bool, 2) + m.EXPECT().leaderCh().Return((<-chan bool)(leaderCh)) + m.EXPECT().Config().Return(testCfg()) + m.EXPECT().waitForMsgsLanded(2 * time.Millisecond).Return(nil) + m.EXPECT().NodeID().Return("self") + m.EXPECT().leaderID().Return("self") + m.EXPECT().GetState().Return(&RaftBlockState{Height: 1}) + m.EXPECT().leadershipTransfer().Return(nil) + + fStarted := make(chan struct{}) + follower := &testRunnable{startedCh: fStarted, isSyncedFn: func(*RaftBlockState) bool { return false }} + leader := &testRunnable{runFn: func(ctx context.Context) error { + t.Fatal("leader should not be running") + return nil + }} + + logger := zerolog.Nop() + d := &DynamicLeaderElection{logger: logger, node: m, + leaderFactory: func() (Runnable, error) { return leader, nil }, + followerFactory: func() (Runnable, error) { return follower, nil }, + } + ctx, cancel := context.WithCancel(t.Context()) + // Start as follower via false, then signal leader true + go func() { + leaderCh <- false + <-fStarted // ensure follower started + leaderCh <- true + // allow time for SendTimeout sleep and transfer + time.Sleep(3 * time.Millisecond) + cancel() + }() + return d, ctx, cancel + }, + assertF: func(t *testing.T, err error) { + require.Error(t, err) + assert.ErrorIs(t, err, context.Canceled) + }, + }, + "lost leadership during sync wait": { + setup: func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) { + m := newMocksourceNode(t) + leaderCh := make(chan bool, 2) + m.EXPECT().leaderCh().Return((<-chan bool)(leaderCh)) + m.EXPECT().Config().Return(testCfg()) + m.EXPECT().waitForMsgsLanded(2 * time.Millisecond).Return(nil) + m.EXPECT().NodeID().Return("self") + m.EXPECT().leaderID().Return("other") // Simulate leadership lost + + fStarted := make(chan struct{}) + follower := &testRunnable{startedCh: fStarted} + // Leader should not be started + leader := &testRunnable{runFn: func(ctx context.Context) error { + t.Fatal("leader should not be running") + return nil + }} + + logger := zerolog.Nop() + d := &DynamicLeaderElection{logger: logger, node: m, + leaderFactory: func() (Runnable, error) { return leader, nil }, + followerFactory: func() (Runnable, error) { return follower, nil }, + } + ctx, cancel := context.WithCancel(t.Context()) + go func() { + leaderCh <- false + <-fStarted + leaderCh <- true + time.Sleep(3 * time.Millisecond) + cancel() + }() + return d, ctx, cancel + }, + assertF: func(t *testing.T, err error) { + require.Error(t, err) + assert.ErrorIs(t, err, context.Canceled) + }, + }, + "follower starts then becomes leader": { + setup: func(t *testing.T) (*DynamicLeaderElection, context.Context, context.CancelFunc) { + m := newMocksourceNode(t) + leaderCh := make(chan bool, 2) + m.EXPECT().leaderCh().Return((<-chan bool)(leaderCh)) + // On leadership change to true, election will sleep SendTimeout, then check sync against state + m.EXPECT().Config().Return(testCfg()) + m.EXPECT().waitForMsgsLanded(2 * time.Millisecond).Return(nil) + m.EXPECT().NodeID().Return("self") + m.EXPECT().leaderID().Return("self") + m.EXPECT().GetState().Return(&RaftBlockState{Height: 1}) + + fStarted := make(chan struct{}) + lStarted := make(chan struct{}) + follower := &testRunnable{startedCh: fStarted} + leader := &testRunnable{startedCh: lStarted} + + logger := zerolog.Nop() + d := &DynamicLeaderElection{logger: logger, node: m, + leaderFactory: func() (Runnable, error) { return leader, nil }, + followerFactory: func() (Runnable, error) { return follower, nil }, + } + ctx, cancel := context.WithCancel(t.Context()) + go func() { + // Start as follower first + leaderCh <- false + <-fStarted // ensure follower started + // Now become leader + leaderCh <- true + // Wait for transition to leader + select { + case <-lStarted: + case <-time.After(15 * time.Millisecond): + t.Log("timed out waiting for leader to start") + return + } + // give a tiny buffer then cancel + time.Sleep(2 * time.Millisecond) + cancel() + }() + return d, ctx, cancel + }, + assertF: func(t *testing.T, err error) { + require.Error(t, err) + assert.ErrorIs(t, err, context.Canceled) + }, + }, + } + + for name, spec := range specs { + name, spec := name, spec + t.Run(name, func(t *testing.T) { + d, runCtx, cancel := spec.setup(t) + defer cancel() + err := d.Run(runCtx) + spec.assertF(t, err) + }) + } +} + +// Helper to quickly build a Config with very short timeouts for tests +func testCfg() Config { + return Config{SendTimeout: 2 * time.Millisecond} +} + +// testRunnable is a small helper implementing Runnable for tests. +// Run behaviour is provided via runFn. IsSynced behaviour via isSyncedFn. +// When runFn is nil, it blocks until context is cancelled. +// When startedCh is non-nil, it will be closed once Run starts. +// When doneCh is non-nil, it will be closed right before Run returns. +// These channels are used only by tests to observe state. +type testRunnable struct { + runFn func(ctx context.Context) error + isSyncedFn func(*RaftBlockState) bool + startedCh chan struct{} + doneCh chan struct{} +} + +func (t *testRunnable) Run(ctx context.Context) error { + if t.startedCh != nil { + select { + case <-t.startedCh: + default: + close(t.startedCh) + } + } + if t.runFn != nil { + err := t.runFn(ctx) + if t.doneCh != nil { + close(t.doneCh) + } + return err + } + <-ctx.Done() + if t.doneCh != nil { + close(t.doneCh) + } + return ctx.Err() +} + +func (t *testRunnable) IsSynced(s *RaftBlockState) bool { + if t.isSyncedFn != nil { + return t.isSyncedFn(s) + } + return true +} diff --git a/pkg/raft/node.go b/pkg/raft/node.go new file mode 100644 index 0000000000..b66d29a1a0 --- /dev/null +++ b/pkg/raft/node.go @@ -0,0 +1,391 @@ +package raft + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "os" + "path/filepath" + "strings" + "sync/atomic" + "time" + + "github.com/hashicorp/raft" + raftboltdb "github.com/hashicorp/raft-boltdb" + "github.com/rs/zerolog" + "google.golang.org/protobuf/proto" +) + +// Node represents a raft consensus node +type Node struct { + raft *raft.Raft + fsm *FSM + config *Config + logger zerolog.Logger +} + +// Config holds raft node configuration +type Config struct { + NodeID string + RaftAddr string + RaftDir string + Bootstrap bool + Peers []string + SnapCount uint64 + SendTimeout time.Duration + HeartbeatTimeout time.Duration + LeaderLeaseTimeout time.Duration +} + +// FSM implements raft.FSM for block state +type FSM struct { + logger zerolog.Logger + state *atomic.Pointer[RaftBlockState] + applyCh chan<- RaftApplyMsg +} + +// NewNode creates a new raft node +func NewNode(cfg *Config, logger zerolog.Logger) (*Node, error) { + if err := os.MkdirAll(cfg.RaftDir, 0755); err != nil { + return nil, fmt.Errorf("create raft dir: %w", err) + } + + raftConfig := raft.DefaultConfig() + raftConfig.LocalID = raft.ServerID(cfg.NodeID) + raftConfig.LogLevel = "INFO" + raftConfig.HeartbeatTimeout = cfg.HeartbeatTimeout + raftConfig.LeaderLeaseTimeout = cfg.LeaderLeaseTimeout + + startPointer := new(atomic.Pointer[RaftBlockState]) + startPointer.Store(&RaftBlockState{}) + fsm := &FSM{ + logger: logger.With().Str("component", "raft-fsm").Logger(), + state: startPointer, + } + + logStore, err := raftboltdb.NewBoltStore(filepath.Join(cfg.RaftDir, "raft-log.db")) + if err != nil { + return nil, fmt.Errorf("create log store: %w", err) + } + + stableStore, err := raftboltdb.NewBoltStore(filepath.Join(cfg.RaftDir, "raft-stable.db")) + if err != nil { + return nil, fmt.Errorf("create stable store: %w", err) + } + + snapshotStore, err := raft.NewFileSnapshotStore(cfg.RaftDir, int(cfg.SnapCount), os.Stderr) + if err != nil { + return nil, fmt.Errorf("create snapshot store: %w", err) + } + + addr, err := net.ResolveTCPAddr("tcp", cfg.RaftAddr) + if err != nil { + return nil, fmt.Errorf("resolve raft addr: %w", err) + } + + transport, err := raft.NewTCPTransport(cfg.RaftAddr, addr, 3, 10*time.Second, os.Stderr) + if err != nil { + return nil, fmt.Errorf("create transport: %w", err) + } + + r, err := raft.NewRaft(raftConfig, fsm, logStore, stableStore, snapshotStore, transport) + if err != nil { + return nil, fmt.Errorf("create raft: %w", err) + } + + node := &Node{ + raft: r, + fsm: fsm, + config: cfg, + logger: logger.With().Str("component", "raft-node").Logger(), + } + + return node, nil +} + +func (n *Node) Start(_ context.Context) error { + if n == nil { + return nil + } + if !n.config.Bootstrap { + // it is intended to fail fast here. at this stage only bootstrap mode is supported. + return fmt.Errorf("raft cluster requires bootstrap mode") + } + + if future := n.raft.GetConfiguration(); future.Error() == nil && len(future.Configuration().Servers) > 0 { + n.logger.Info().Msg("cluster already bootstrapped, skipping") + return nil + } + + n.logger.Info().Msg("Boostrap raft cluster") + thisNode := raft.Server{ID: raft.ServerID(n.config.NodeID), Address: raft.ServerAddress(n.config.RaftAddr)} + cfg := raft.Configuration{ + Servers: []raft.Server{ + thisNode, + }, + } + for _, peer := range n.config.Peers { + addr, err := splitPeerAddr(peer) + if err != nil { + return fmt.Errorf("peer %q : %w", peer, err) + } + if addr != thisNode { + cfg.Servers = append(cfg.Servers, addr) + } + } + + if svrs := deduplicateServers(cfg.Servers); len(svrs) != len(cfg.Servers) { + return fmt.Errorf("duplicate peers found in config: %v", cfg.Servers) + } + + if err := n.raft.BootstrapCluster(cfg).Error(); err != nil { + return fmt.Errorf("bootstrap cluster: %w", err) + } + n.logger.Info().Msg("bootstrapped raft cluster") + return nil +} + +func (n *Node) waitForMsgsLanded(timeout time.Duration) error { + if n == nil { + return nil + } + timeoutTicker := time.NewTicker(timeout) + defer timeoutTicker.Stop() + ticker := time.NewTicker(min(n.config.SendTimeout, timeout) / 2) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + if n.raft.AppliedIndex() >= n.raft.LastIndex() { + return nil + } + case <-timeoutTicker.C: + return errors.New("max wait time reached") + } + } +} + +func (n *Node) Stop() error { + if n == nil { + return nil + } + return n.raft.Shutdown().Error() +} + +// IsLeader returns true if this node is the raft leader +func (n *Node) IsLeader() bool { + if n == nil || n.raft == nil { + return false + } + return n.raft.State() == raft.Leader +} + +func (n *Node) NodeID() string { + return n.config.NodeID +} + +func (n *Node) leaderID() string { + _, id := n.raft.LeaderWithID() + return string(id) +} + +func (n *Node) leaderCh() <-chan bool { + return n.raft.LeaderCh() +} + +func (n *Node) leadershipTransfer() error { + return n.raft.LeadershipTransfer().Error() +} + +func (n *Node) Config() Config { + return *n.config +} + +// Broadcast proposes a block state to be replicated via raft +func (n *Node) Broadcast(_ context.Context, state *RaftBlockState) error { + if !n.IsLeader() { + return fmt.Errorf("not leader") + } + + data, err := proto.Marshal(state) + if err != nil { + return fmt.Errorf("marshal block state: %w", err) + } + + future := n.raft.Apply(data, n.config.SendTimeout) + if err := future.Error(); err != nil { + return fmt.Errorf("apply log: %w", err) + } + + return nil +} + +// GetState returns the current replicated state +func (n *Node) GetState() *RaftBlockState { + return proto.Clone(n.fsm.state.Load()).(*RaftBlockState) +} + +// AddPeer adds a peer to the raft cluster +func (n *Node) AddPeer(nodeID, addr string) error { + n.logger.Debug().Msgf("received join request for remote node %s at %s", nodeID, addr) + + configFuture := n.raft.GetConfiguration() + if err := configFuture.Error(); err != nil { + return err + } + + // remove first when node is already a member of the cluster + for _, srv := range configFuture.Configuration().Servers { + if srv.ID == raft.ServerID(nodeID) || srv.Address == raft.ServerAddress(addr) { + if srv.Address == raft.ServerAddress(addr) && srv.ID == raft.ServerID(nodeID) { + n.logger.Debug().Msgf("node %s at %s already member of cluster, ignoring join request", nodeID, addr) + return nil + } + future := n.raft.RemoveServer(srv.ID, 0, 0) + if err := future.Error(); err != nil { + return fmt.Errorf("removing existing node %s at %s: %w", nodeID, addr, err) + } + } + } + + f := n.raft.AddVoter(raft.ServerID(nodeID), raft.ServerAddress(addr), 0, 0) + if f.Error() != nil { + return f.Error() + } + n.logger.Debug().Msgf("node %s at %s joined successfully", nodeID, addr) + return nil +} + +// RemovePeer removes a peer from the raft cluster +func (n *Node) RemovePeer(nodeID string) error { + future := n.raft.RemoveServer(raft.ServerID(nodeID), 0, 0) + return future.Error() +} + +// Shutdown stops the raft node +func (n *Node) Shutdown() error { + return n.raft.Shutdown().Error() +} + +// SetApplyCallback sets a callback channel to receive notifications when a new block state is replicated. +// The channel must have sufficient buffer space since updates are published only once without blocking. +// If the channel is full, state updates will be skipped to prevent blocking the raft cluster. +func (n *Node) SetApplyCallback(ch chan<- RaftApplyMsg) { + n.fsm.applyCh = ch +} + +// Apply implements raft.FSM +func (f *FSM) Apply(log *raft.Log) interface{} { + var state RaftBlockState + if err := proto.Unmarshal(log.Data, &state); err != nil { + f.logger.Error().Err(err).Msg("unmarshal block state") + return err + } + if err := assertValid(f.state.Load(), &state); err != nil { + return err + } + f.state.Store(&state) + f.logger.Debug().Uint64("height", state.Height).Msg("received block state") + + if f.applyCh != nil { + select { + case f.applyCh <- RaftApplyMsg{Index: log.Index, State: &state}: + default: + // on a slow consumer, the raft cluster should not be blocked. Followers can sync from DA or other peers, too. + f.logger.Warn().Msg("apply channel full, dropping message") + } + } + + return nil +} + +// Snapshot implements raft.FSM +func (f *FSM) Snapshot() (raft.FSMSnapshot, error) { + return &fsmSnapshot{state: *f.state.Load()}, nil +} + +// Restore implements raft.FSM +func (f *FSM) Restore(rc io.ReadCloser) error { + defer rc.Close() + + data, err := io.ReadAll(rc) + if err != nil { + return fmt.Errorf("read snapshot: %w", err) + } + + var state RaftBlockState + if err := proto.Unmarshal(data, &state); err != nil { + return fmt.Errorf("decode snapshot: %w", err) + } + + f.state.Store(&state) + f.logger.Info().Uint64("height", state.Height).Msg("restored from snapshot") + return nil +} + +type fsmSnapshot struct { + state RaftBlockState +} + +func (s *fsmSnapshot) Persist(sink raft.SnapshotSink) error { + err := func() error { + data, err := proto.Marshal(&s.state) + if err != nil { + return err + } + if _, err := sink.Write(data); err != nil { + return err + } + return sink.Close() + }() + + if err != nil { + _ = sink.Cancel() + return err + } + + return nil +} + +func (s *fsmSnapshot) Release() {} + +func splitPeerAddr(peer string) (raft.Server, error) { + parts := strings.Split(peer, "@") + if len(parts) != 2 { + return raft.Server{}, errors.New("expecting nodeID@address for peer") + } + + nodeID, address := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]) + + if nodeID == "" { + return raft.Server{}, errors.New("nodeID cannot be empty") + } + if address == "" { + return raft.Server{}, errors.New("address cannot be empty") + } + // we can skip address validation as they come from a local configuration + + return raft.Server{ + ID: raft.ServerID(nodeID), + Address: raft.ServerAddress(address), + }, nil +} + +func deduplicateServers(servers []raft.Server) []raft.Server { + if len(servers) == 0 { + return []raft.Server{} + } + seen := make(map[raft.ServerID]struct{}) + unique := make([]raft.Server, 0, len(servers)) + for _, server := range servers { + key := server.ID + if _, exists := seen[key]; !exists { + seen[key] = struct{}{} + unique = append(unique, server) + } + } + return unique +} diff --git a/pkg/raft/node_mock.go b/pkg/raft/node_mock.go new file mode 100644 index 0000000000..d121498d33 --- /dev/null +++ b/pkg/raft/node_mock.go @@ -0,0 +1,357 @@ +// Code generated by mockery; DO NOT EDIT. +// github.com/vektra/mockery +// template: testify + +package raft + +import ( + "time" + + mock "github.com/stretchr/testify/mock" +) + +// newMocksourceNode creates a new instance of mocksourceNode. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMocksourceNode(t interface { + mock.TestingT + Cleanup(func()) +}) *mocksourceNode { + mock := &mocksourceNode{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} + +// mocksourceNode is an autogenerated mock type for the sourceNode type +type mocksourceNode struct { + mock.Mock +} + +type mocksourceNode_Expecter struct { + mock *mock.Mock +} + +func (_m *mocksourceNode) EXPECT() *mocksourceNode_Expecter { + return &mocksourceNode_Expecter{mock: &_m.Mock} +} + +// Config provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) Config() Config { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for Config") + } + + var r0 Config + if returnFunc, ok := ret.Get(0).(func() Config); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(Config) + } + return r0 +} + +// mocksourceNode_Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Config' +type mocksourceNode_Config_Call struct { + *mock.Call +} + +// Config is a helper method to define mock.On call +func (_e *mocksourceNode_Expecter) Config() *mocksourceNode_Config_Call { + return &mocksourceNode_Config_Call{Call: _e.mock.On("Config")} +} + +func (_c *mocksourceNode_Config_Call) Run(run func()) *mocksourceNode_Config_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mocksourceNode_Config_Call) Return(config Config) *mocksourceNode_Config_Call { + _c.Call.Return(config) + return _c +} + +func (_c *mocksourceNode_Config_Call) RunAndReturn(run func() Config) *mocksourceNode_Config_Call { + _c.Call.Return(run) + return _c +} + +// GetState provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) GetState() *RaftBlockState { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetState") + } + + var r0 *RaftBlockState + if returnFunc, ok := ret.Get(0).(func() *RaftBlockState); ok { + r0 = returnFunc() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*RaftBlockState) + } + } + return r0 +} + +// mocksourceNode_GetState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetState' +type mocksourceNode_GetState_Call struct { + *mock.Call +} + +// GetState is a helper method to define mock.On call +func (_e *mocksourceNode_Expecter) GetState() *mocksourceNode_GetState_Call { + return &mocksourceNode_GetState_Call{Call: _e.mock.On("GetState")} +} + +func (_c *mocksourceNode_GetState_Call) Run(run func()) *mocksourceNode_GetState_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mocksourceNode_GetState_Call) Return(raftBlockState *RaftBlockState) *mocksourceNode_GetState_Call { + _c.Call.Return(raftBlockState) + return _c +} + +func (_c *mocksourceNode_GetState_Call) RunAndReturn(run func() *RaftBlockState) *mocksourceNode_GetState_Call { + _c.Call.Return(run) + return _c +} + +// NodeID provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) NodeID() string { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for NodeID") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func() string); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// mocksourceNode_NodeID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeID' +type mocksourceNode_NodeID_Call struct { + *mock.Call +} + +// NodeID is a helper method to define mock.On call +func (_e *mocksourceNode_Expecter) NodeID() *mocksourceNode_NodeID_Call { + return &mocksourceNode_NodeID_Call{Call: _e.mock.On("NodeID")} +} + +func (_c *mocksourceNode_NodeID_Call) Run(run func()) *mocksourceNode_NodeID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mocksourceNode_NodeID_Call) Return(s string) *mocksourceNode_NodeID_Call { + _c.Call.Return(s) + return _c +} + +func (_c *mocksourceNode_NodeID_Call) RunAndReturn(run func() string) *mocksourceNode_NodeID_Call { + _c.Call.Return(run) + return _c +} + +// leaderCh provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) leaderCh() <-chan bool { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for leaderCh") + } + + var r0 <-chan bool + if returnFunc, ok := ret.Get(0).(func() <-chan bool); ok { + r0 = returnFunc() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan bool) + } + } + return r0 +} + +// mocksourceNode_leaderCh_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'leaderCh' +type mocksourceNode_leaderCh_Call struct { + *mock.Call +} + +// leaderCh is a helper method to define mock.On call +func (_e *mocksourceNode_Expecter) leaderCh() *mocksourceNode_leaderCh_Call { + return &mocksourceNode_leaderCh_Call{Call: _e.mock.On("leaderCh")} +} + +func (_c *mocksourceNode_leaderCh_Call) Run(run func()) *mocksourceNode_leaderCh_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mocksourceNode_leaderCh_Call) Return(boolCh <-chan bool) *mocksourceNode_leaderCh_Call { + _c.Call.Return(boolCh) + return _c +} + +func (_c *mocksourceNode_leaderCh_Call) RunAndReturn(run func() <-chan bool) *mocksourceNode_leaderCh_Call { + _c.Call.Return(run) + return _c +} + +// leaderID provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) leaderID() string { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for leaderID") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func() string); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// mocksourceNode_leaderID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'leaderID' +type mocksourceNode_leaderID_Call struct { + *mock.Call +} + +// leaderID is a helper method to define mock.On call +func (_e *mocksourceNode_Expecter) leaderID() *mocksourceNode_leaderID_Call { + return &mocksourceNode_leaderID_Call{Call: _e.mock.On("leaderID")} +} + +func (_c *mocksourceNode_leaderID_Call) Run(run func()) *mocksourceNode_leaderID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mocksourceNode_leaderID_Call) Return(s string) *mocksourceNode_leaderID_Call { + _c.Call.Return(s) + return _c +} + +func (_c *mocksourceNode_leaderID_Call) RunAndReturn(run func() string) *mocksourceNode_leaderID_Call { + _c.Call.Return(run) + return _c +} + +// leadershipTransfer provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) leadershipTransfer() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for leadershipTransfer") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 +} + +// mocksourceNode_leadershipTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'leadershipTransfer' +type mocksourceNode_leadershipTransfer_Call struct { + *mock.Call +} + +// leadershipTransfer is a helper method to define mock.On call +func (_e *mocksourceNode_Expecter) leadershipTransfer() *mocksourceNode_leadershipTransfer_Call { + return &mocksourceNode_leadershipTransfer_Call{Call: _e.mock.On("leadershipTransfer")} +} + +func (_c *mocksourceNode_leadershipTransfer_Call) Run(run func()) *mocksourceNode_leadershipTransfer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *mocksourceNode_leadershipTransfer_Call) Return(err error) *mocksourceNode_leadershipTransfer_Call { + _c.Call.Return(err) + return _c +} + +func (_c *mocksourceNode_leadershipTransfer_Call) RunAndReturn(run func() error) *mocksourceNode_leadershipTransfer_Call { + _c.Call.Return(run) + return _c +} + +// waitForMsgsLanded provides a mock function for the type mocksourceNode +func (_mock *mocksourceNode) waitForMsgsLanded(duration time.Duration) error { + ret := _mock.Called(duration) + + if len(ret) == 0 { + panic("no return value specified for waitForMsgsLanded") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(time.Duration) error); ok { + r0 = returnFunc(duration) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// mocksourceNode_waitForMsgsLanded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'waitForMsgsLanded' +type mocksourceNode_waitForMsgsLanded_Call struct { + *mock.Call +} + +// waitForMsgsLanded is a helper method to define mock.On call +// - duration time.Duration +func (_e *mocksourceNode_Expecter) waitForMsgsLanded(duration interface{}) *mocksourceNode_waitForMsgsLanded_Call { + return &mocksourceNode_waitForMsgsLanded_Call{Call: _e.mock.On("waitForMsgsLanded", duration)} +} + +func (_c *mocksourceNode_waitForMsgsLanded_Call) Run(run func(duration time.Duration)) *mocksourceNode_waitForMsgsLanded_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 time.Duration + if args[0] != nil { + arg0 = args[0].(time.Duration) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *mocksourceNode_waitForMsgsLanded_Call) Return(err error) *mocksourceNode_waitForMsgsLanded_Call { + _c.Call.Return(err) + return _c +} + +func (_c *mocksourceNode_waitForMsgsLanded_Call) RunAndReturn(run func(duration time.Duration) error) *mocksourceNode_waitForMsgsLanded_Call { + _c.Call.Return(run) + return _c +} diff --git a/pkg/raft/node_test.go b/pkg/raft/node_test.go new file mode 100644 index 0000000000..9e3f8237a5 --- /dev/null +++ b/pkg/raft/node_test.go @@ -0,0 +1,110 @@ +package raft + +import ( + "errors" + "testing" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSplitPeerAddr(t *testing.T) { + specs := map[string]struct { + in string + exp raft.Server + expErr error + }{ + "valid": { + in: "node1@127.0.0.1:1234", + exp: raft.Server{ID: raft.ServerID("node1"), Address: raft.ServerAddress("127.0.0.1:1234")}, + }, + "trims whitespace": { + in: " node2 @ 10.0.0.2:9000 ", + exp: raft.Server{ID: raft.ServerID("node2"), Address: raft.ServerAddress("10.0.0.2:9000")}, + }, + "missing at": { + in: "node1", + expErr: errors.New("expecting nodeID@address for peer"), + }, + "empty node id": { + in: "@127.0.0.1:1234", + expErr: errors.New("nodeID cannot be empty"), + }, + "empty address": { + in: "node1@", + expErr: errors.New("address cannot be empty"), + }, + "multiple ats": { + in: "a@b@c", + expErr: errors.New("expecting nodeID@address for peer"), + }, + "only spaces": { + in: " @ ", + expErr: errors.New("nodeID cannot be empty"), + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx := t.Context() + _ = ctx // keep to follow guideline to prefer t.Context; function under test doesn't use context + + got, err := splitPeerAddr(spec.in) + if spec.expErr != nil { + require.Error(t, err) + assert.Equal(t, spec.expErr.Error(), err.Error()) + return + } + require.NoError(t, err) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestDeduplicateServers(t *testing.T) { + + specs := map[string]struct { + in []raft.Server + exp []raft.Server + }{ + "empty": { + in: nil, + exp: []raft.Server{}, + }, + "no duplicates": { + in: []raft.Server{ + {ID: raft.ServerID("n1"), Address: raft.ServerAddress("a1")}, + {ID: raft.ServerID("n2"), Address: raft.ServerAddress("a2")}, + }, + exp: []raft.Server{ + {ID: raft.ServerID("n1"), Address: raft.ServerAddress("a1")}, + {ID: raft.ServerID("n2"), Address: raft.ServerAddress("a2")}, + }, + }, + "duplicates keep first": { + in: []raft.Server{ + {ID: raft.ServerID("n1"), Address: raft.ServerAddress("a1")}, + {ID: raft.ServerID("n2"), Address: raft.ServerAddress("a2")}, + {ID: raft.ServerID("n1"), Address: raft.ServerAddress("a3")}, + {ID: raft.ServerID("n3"), Address: raft.ServerAddress("a4")}, + {ID: raft.ServerID("n2"), Address: raft.ServerAddress("a5")}, + }, + exp: []raft.Server{ + {ID: raft.ServerID("n1"), Address: raft.ServerAddress("a1")}, + {ID: raft.ServerID("n2"), Address: raft.ServerAddress("a2")}, + {ID: raft.ServerID("n3"), Address: raft.ServerAddress("a4")}, + }, + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx := t.Context() + _ = ctx + + got := deduplicateServers(spec.in) + assert.Equal(t, spec.exp, got) + }) + } +} diff --git a/pkg/raft/types.go b/pkg/raft/types.go new file mode 100644 index 0000000000..bb5c6728b2 --- /dev/null +++ b/pkg/raft/types.go @@ -0,0 +1,27 @@ +package raft + +import ( + "fmt" + + pb "github.com/evstack/ev-node/types/pb/evnode/v1" +) + +// RaftBlockState represents a replicated block state +type RaftBlockState = pb.RaftBlockState + +// assertValid checks basic constraints but does not ensure that no gaps exist or chain continuity +func assertValid(s *RaftBlockState, next *RaftBlockState) error { + if s.Height > next.Height { + return fmt.Errorf("invalid height: %d > %d", s.Height, next.Height) + } + if s.Timestamp > next.Timestamp { + return fmt.Errorf("invalid timestamp: %d > %d", s.Timestamp, next.Timestamp) + } + return nil +} + +// RaftApplyMsg is sent when raft applies a log entry +type RaftApplyMsg struct { + Index uint64 + State *RaftBlockState +} diff --git a/pkg/rpc/example/example.go b/pkg/rpc/example/example.go index f3c020fa87..fd1f74f263 100644 --- a/pkg/rpc/example/example.go +++ b/pkg/rpc/example/example.go @@ -22,7 +22,7 @@ func StartStoreServer(s store.Store, address string, logger zerolog.Logger) { rpcAddr := fmt.Sprintf("%s:%d", "localhost", 8080) cfg := config.DefaultConfig() - handler, err := server.NewServiceHandler(s, nil, nil, nil, nil, logger, cfg, nil) + handler, err := server.NewServiceHandler(s, nil, nil, nil, nil, logger, cfg, nil, nil) if err != nil { panic(err) } @@ -82,7 +82,7 @@ func ExampleServer(s store.Store) { // Start RPC server rpcAddr := fmt.Sprintf("%s:%d", "localhost", 8080) cfg := config.DefaultConfig() - handler, err := server.NewServiceHandler(s, nil, nil, nil, nil, logger, cfg, nil) + handler, err := server.NewServiceHandler(s, nil, nil, nil, nil, logger, cfg, nil, nil) if err != nil { panic(err) } diff --git a/pkg/rpc/server/da_visualization_test.go b/pkg/rpc/server/da_visualization_test.go index 69d69776f2..7d6b28c81b 100644 --- a/pkg/rpc/server/da_visualization_test.go +++ b/pkg/rpc/server/da_visualization_test.go @@ -261,7 +261,7 @@ func TestRegisterCustomHTTPEndpointsDAVisualization(t *testing.T) { // Create mux and register endpoints mux := http.NewServeMux() nopLogger := zerolog.Nop() - RegisterCustomHTTPEndpoints(mux, nil, nil, config.DefaultConfig(), nil, nopLogger) + RegisterCustomHTTPEndpoints(mux, nil, nil, config.DefaultConfig(), nil, nopLogger, nil) // Test /da endpoint req, err := http.NewRequest("GET", "/da", nil) @@ -299,7 +299,7 @@ func TestRegisterCustomHTTPEndpointsWithoutServer(t *testing.T) { mux := http.NewServeMux() logger := zerolog.Nop() - RegisterCustomHTTPEndpoints(mux, nil, nil, config.DefaultConfig(), nil, logger) + RegisterCustomHTTPEndpoints(mux, nil, nil, config.DefaultConfig(), nil, logger, nil) // Test that endpoints return service unavailable when server is not set endpoints := []string{"/da", "/da/submissions", "/da/blob"} diff --git a/pkg/rpc/server/http.go b/pkg/rpc/server/http.go index 5d336e4c48..43709c1740 100644 --- a/pkg/rpc/server/http.go +++ b/pkg/rpc/server/http.go @@ -1,6 +1,7 @@ package server import ( + "encoding/json" "fmt" "net/http" "time" @@ -15,7 +16,7 @@ import ( type BestKnownHeightProvider func() uint64 // RegisterCustomHTTPEndpoints registers custom HTTP handlers on the mux. -func RegisterCustomHTTPEndpoints(mux *http.ServeMux, s store.Store, pm p2p.P2PRPC, cfg config.Config, bestKnownHeightProvider BestKnownHeightProvider, logger zerolog.Logger) { +func RegisterCustomHTTPEndpoints(mux *http.ServeMux, s store.Store, pm p2p.P2PRPC, cfg config.Config, bestKnownHeightProvider BestKnownHeightProvider, logger zerolog.Logger, raftNode RaftNodeSource) { // /health/live performs a basic liveness check to determine if the process is alive and responsive. // Returns 200 if the process can access its store, 503 otherwise. // This is a lightweight check suitable for Kubernetes liveness probes. @@ -130,6 +131,28 @@ func RegisterCustomHTTPEndpoints(mux *http.ServeMux, s store.Store, pm p2p.P2PRP fmt.Fprintln(w, "READY") }) + // optional Raft node details + if raftNode != nil { + mux.HandleFunc("/raft/node", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + rsp := struct { + IsLeader bool `json:"is_leader"` + NodeID string `json:"node_id"` + }{ + IsLeader: raftNode.IsLeader(), + NodeID: raftNode.NodeID(), + } + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(rsp); err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } + }) + + } + // DA Visualization endpoints mux.HandleFunc("/da", func(w http.ResponseWriter, r *http.Request) { server := GetDAVisualizationServer() diff --git a/pkg/rpc/server/http_test.go b/pkg/rpc/server/http_test.go index ab761a0a3e..a8e535a792 100644 --- a/pkg/rpc/server/http_test.go +++ b/pkg/rpc/server/http_test.go @@ -23,7 +23,7 @@ func TestRegisterCustomHTTPEndpoints(t *testing.T) { mockStore := mocks.NewMockStore(t) mockStore.On("Height", mock.Anything).Return(uint64(100), nil) - RegisterCustomHTTPEndpoints(mux, mockStore, nil, config.DefaultConfig(), nil, logger) + RegisterCustomHTTPEndpoints(mux, mockStore, nil, config.DefaultConfig(), nil, logger, nil) testServer := httptest.NewServer(mux) defer testServer.Close() @@ -113,7 +113,7 @@ func TestHealthReady_aggregatorBlockDelay(t *testing.T) { bestKnownHeightProvider := func() uint64 { return state.LastBlockHeight } - RegisterCustomHTTPEndpoints(mux, mockStore, nil, cfg, bestKnownHeightProvider, logger) + RegisterCustomHTTPEndpoints(mux, mockStore, nil, cfg, bestKnownHeightProvider, logger, nil) ts := httptest.NewServer(mux) t.Cleanup(ts.Close) diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 817ca1f377..f080e2a0cf 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -367,6 +367,11 @@ func (p *P2PServer) GetNetInfo( }), nil } +type RaftNodeSource interface { + IsLeader() bool + NodeID() string +} + // NewServiceHandler creates a new HTTP handler for Store, P2P and Config services func NewServiceHandler( store store.Store, @@ -377,6 +382,7 @@ func NewServiceHandler( logger zerolog.Logger, config config.Config, bestKnown BestKnownHeightProvider, + raftNode RaftNodeSource, ) (http.Handler, error) { storeServer := NewStoreServer(store, headerStore, dataStore, logger) p2pServer := NewP2PServer(peerManager) @@ -405,7 +411,7 @@ func NewServiceHandler( mux.Handle(configPath, configHandler) // Register custom HTTP endpoints - RegisterCustomHTTPEndpoints(mux, store, peerManager, config, bestKnown, logger) + RegisterCustomHTTPEndpoints(mux, store, peerManager, config, bestKnown, logger, raftNode) // Use h2c to support HTTP/2 without TLS return h2c.NewHandler(mux, &http2.Server{ diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 32e9b0ebec..c9e2d6483d 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -416,7 +416,7 @@ func TestHealthLiveEndpoint(t *testing.T) { // Mock successful store access mockStore.On("Height", mock.Anything).Return(uint64(100), nil) - handler, err := NewServiceHandler(mockStore, nil, nil, mockP2PManager, nil, logger, testConfig, nil) + handler, err := NewServiceHandler(mockStore, nil, nil, mockP2PManager, nil, logger, testConfig, nil, nil) require.NoError(t, err) server := httptest.NewServer(handler) @@ -441,7 +441,7 @@ func TestHealthLiveEndpoint(t *testing.T) { // Mock store access failure mockStore.On("Height", mock.Anything).Return(uint64(0), fmt.Errorf("store unavailable")) - handler, err := NewServiceHandler(mockStore, nil, nil, mockP2PManager, nil, logger, testConfig, nil) + handler, err := NewServiceHandler(mockStore, nil, nil, mockP2PManager, nil, logger, testConfig, nil, nil) require.NoError(t, err) server := httptest.NewServer(handler) @@ -466,7 +466,7 @@ func TestHealthLiveEndpoint(t *testing.T) { // Mock successful store access at genesis mockStore.On("Height", mock.Anything).Return(uint64(0), nil) - handler, err := NewServiceHandler(mockStore, nil, nil, mockP2PManager, nil, logger, testConfig, nil) + handler, err := NewServiceHandler(mockStore, nil, nil, mockP2PManager, nil, logger, testConfig, nil, nil) require.NoError(t, err) server := httptest.NewServer(handler) @@ -543,7 +543,7 @@ func TestHealthReadyEndpoint(t *testing.T) { } bestKnown := func() uint64 { return tc.bestKnown } - handler, err := NewServiceHandler(mockStore, nil, nil, mockP2P, nil, logger, testConfig, bestKnown) + handler, err := NewServiceHandler(mockStore, nil, nil, mockP2P, nil, logger, testConfig, bestKnown, nil) require.NoError(t, err) server := httptest.NewServer(handler) defer server.Close() @@ -584,7 +584,7 @@ func TestHealthReadyEndpoint(t *testing.T) { mockStore.On("GetState", mock.Anything).Return(state, nil) bestKnown := func() uint64 { return 100 } - handler, err := NewServiceHandler(mockStore, nil, nil, mockP2P, nil, logger, testConfig, bestKnown) + handler, err := NewServiceHandler(mockStore, nil, nil, mockP2P, nil, logger, testConfig, bestKnown, nil) require.NoError(t, err) server := httptest.NewServer(handler) defer server.Close() @@ -614,7 +614,7 @@ func TestHealthReadyEndpoint(t *testing.T) { mockStore.On("GetState", mock.Anything).Return(state, nil) bestKnown := func() uint64 { return 100 } - handler, err := NewServiceHandler(mockStore, nil, nil, mockP2P, nil, logger, testConfig, bestKnown) + handler, err := NewServiceHandler(mockStore, nil, nil, mockP2P, nil, logger, testConfig, bestKnown, nil) require.NoError(t, err) server := httptest.NewServer(handler) defer server.Close() diff --git a/pkg/store/store.go b/pkg/store/store.go index 972b94e0e4..b36dd7f8eb 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -190,6 +190,11 @@ func (s *DefaultStore) GetMetadata(ctx context.Context, key string) ([]byte, err return data, nil } +// Sync flushes the store state to disk +func (s *DefaultStore) Sync(ctx context.Context) error { + return s.db.Sync(ctx, ds.NewKey("/")) +} + // Rollback rolls back block data until the given height from the store. // When aggregator is true, it will check the latest data included height and prevent rollback further than that. // NOTE: this function does not rollback metadata. Those should be handled separately if required. diff --git a/pkg/sync/sync_service.go b/pkg/sync/sync_service.go index 9b018460ed..50915b2f49 100644 --- a/pkg/sync/sync_service.go +++ b/pkg/sync/sync_service.go @@ -307,6 +307,11 @@ func (syncService *SyncService[H]) startSubscriber(ctx context.Context) error { return nil } +// Height returns the current height stored +func (s *SyncService[H]) Height() uint64 { + return s.store.Height() +} + // initFromP2PWithRetry initializes the syncer from P2P with a retry mechanism. // It inspects the local store to determine the first height to request: // - when the store already contains items, it reuses the latest height as the starting point; diff --git a/proto/evnode/v1/state.proto b/proto/evnode/v1/state.proto index 2d4130a76c..1e8f35422d 100644 --- a/proto/evnode/v1/state.proto +++ b/proto/evnode/v1/state.proto @@ -20,6 +20,17 @@ message State { reserved 7; } +// RaftBlockState represents a replicated block state +message RaftBlockState { + uint64 height = 1; + uint64 last_submitted_da_header_height = 2; + uint64 last_submitted_da_data_height = 3; + bytes hash = 4; + uint64 timestamp = 5; + bytes header = 6; + bytes data = 7; +} + // SequencerDACheckpoint tracks the position in the DA where transactions were last processed message SequencerDACheckpoint { // DA block height being processed diff --git a/test/e2e/base_test.go b/test/e2e/base_test.go index 7ab30a6e31..3b9a9cc1eb 100644 --- a/test/e2e/base_test.go +++ b/test/e2e/base_test.go @@ -64,6 +64,7 @@ func TestBasic(t *testing.T) { ) require.NoError(t, err, "failed to init aggregator", output) + kvPort := mustGetAvailablePort(t) // start aggregator sut.ExecCmd(binaryPath, "start", @@ -72,7 +73,7 @@ func TestBasic(t *testing.T) { "--evnode.signer.passphrase_file="+passphraseFile, "--evnode.node.block_time=5ms", "--evnode.da.block_time=15ms", - "--kv-endpoint=127.0.0.1:9090", + fmt.Sprintf("--kv-endpoint=127.0.0.1:%d", kvPort), ) sut.AwaitNodeUp(t, "http://127.0.0.1:7331", 2*time.Second) @@ -111,7 +112,7 @@ func TestBasic(t *testing.T) { const myKey = "foo" myValue := fmt.Sprintf("bar%d", time.Now().UnixNano()) tx := fmt.Sprintf("%s=%s", myKey, myValue) - kvStoreEndpoint := "http://127.0.0.1:9090/tx" // Assuming this is the endpoint based on init flag + kvStoreEndpoint := fmt.Sprintf("http://127.0.0.1:%d/tx", kvPort) // Assuming this is the endpoint based on init flag ctx, done := context.WithTimeout(context.Background(), 5*time.Second) // Increased timeout for HTTP request defer done() @@ -165,6 +166,7 @@ func TestNodeRestartPersistence(t *testing.T) { ) require.NoError(t, err, "failed to init node", output) + kvPort := mustGetAvailablePort(t) // Start node sut.ExecCmd(binaryPath, "start", @@ -173,7 +175,7 @@ func TestNodeRestartPersistence(t *testing.T) { "--evnode.signer.passphrase_file="+passphraseFile, "--evnode.node.block_time=5ms", "--evnode.da.block_time=15ms", - "--kv-endpoint=127.0.0.1:9090", + fmt.Sprintf("--kv-endpoint=127.0.0.1:%d", kvPort), ) sut.AwaitNodeUp(t, "http://127.0.0.1:7331", 2*time.Second) t.Log("Node started and is up.") @@ -213,7 +215,7 @@ func TestNodeRestartPersistence(t *testing.T) { "--evnode.signer.passphrase_file="+passphraseFile, "--evnode.node.block_time=5ms", "--evnode.da.block_time=15ms", - "--kv-endpoint=127.0.0.1:9090", + fmt.Sprintf("--kv-endpoint=127.0.0.1:%d", kvPort), ) sut.AwaitNodeUp(t, "http://127.0.0.1:7331", 2*time.Second) t.Log("Node restarted and is up.") diff --git a/test/e2e/evm_test_common.go b/test/e2e/evm_test_common.go index f6564c27ce..b999cdaca7 100644 --- a/test/e2e/evm_test_common.go +++ b/test/e2e/evm_test_common.go @@ -56,6 +56,14 @@ func getAvailablePort() (int, error) { return addr.Port, nil } +// same as getAvailablePort but fails test if not successful +func mustGetAvailablePort(t *testing.T) int { + t.Helper() + port, err := getAvailablePort() + require.NoError(t, err) + return port +} + // TestEndpoints holds unique port numbers for each test instance type TestEndpoints struct { DAPort string @@ -310,6 +318,7 @@ func setupSequencerNode(t *testing.T, sut *SystemUnderTest, sequencerHome, jwtSe // Use helper methods to get complete URLs args := []string{ "start", + "--evnode.log.format", "json", "--evm.jwt-secret-file", jwtSecretFile, "--evm.genesis-hash", genesisHash, "--evnode.node.block_time", DefaultBlockTime, @@ -352,6 +361,7 @@ func setupSequencerNodeLazy(t *testing.T, sut *SystemUnderTest, sequencerHome, j // Use helper methods to get complete URLs args := []string{ "start", + "--evnode.log.format", "json", "--evm.jwt-secret-file", jwtSecretFile, "--evm.genesis-hash", genesisHash, "--evnode.node.block_time", DefaultBlockTime, @@ -412,6 +422,7 @@ func setupFullNode(t *testing.T, sut *SystemUnderTest, fullNodeHome, sequencerHo // Use helper methods to get complete URLs args := []string{ "start", + "--evnode.log.format", "json", "--home", fullNodeHome, "--evm.jwt-secret-file", fullNodeJwtSecretFile, "--evm.genesis-hash", genesisHash, @@ -446,21 +457,25 @@ var globalNonce uint64 = 0 // // This is used in full node sync tests to verify that both nodes // include the same transaction in the same block number. -func submitTransactionAndGetBlockNumber(t *testing.T, sequencerClient *ethclient.Client) (common.Hash, uint64) { +func submitTransactionAndGetBlockNumber(t *testing.T, sequencerClients ...*ethclient.Client) (common.Hash, uint64) { t.Helper() // Submit transaction to sequencer EVM with unique nonce tx := evm.GetRandomTransaction(t, TestPrivateKey, TestToAddress, DefaultChainID, DefaultGasLimit, &globalNonce) - require.NoError(t, sequencerClient.SendTransaction(context.Background(), tx)) + for _, c := range sequencerClients { + require.NoError(t, c.SendTransaction(context.Background(), tx)) + } // Wait for transaction to be included and get block number ctx := context.Background() var txBlockNumber uint64 require.Eventually(t, func() bool { - receipt, err := sequencerClient.TransactionReceipt(ctx, tx.Hash()) - if err == nil && receipt != nil && receipt.Status == 1 { - txBlockNumber = receipt.BlockNumber.Uint64() - return true + for _, c := range sequencerClients { + receipt, err := c.TransactionReceipt(ctx, tx.Hash()) + if err == nil && receipt != nil && receipt.Status == 1 { + txBlockNumber = receipt.BlockNumber.Uint64() + return true + } } return false }, 8*time.Second, SlowPollingInterval) @@ -617,6 +632,7 @@ func restartDAAndSequencer(t *testing.T, sut *SystemUnderTest, sequencerHome, jw jwtSecretFile := filepath.Join(sequencerHome, "jwt-secret.hex") sut.ExecCmd(evmSingleBinaryPath, "start", + "--evnode.log.format", "json", "--evm.jwt-secret-file", jwtSecretFile, "--evm.genesis-hash", genesisHash, "--evnode.node.block_time", DefaultBlockTime, @@ -665,6 +681,7 @@ func restartDAAndSequencerLazy(t *testing.T, sut *SystemUnderTest, sequencerHome jwtSecretFile := filepath.Join(sequencerHome, "jwt-secret.hex") sut.ExecCmd(evmSingleBinaryPath, "start", + "--evnode.log.format", "json", "--evm.jwt-secret-file", jwtSecretFile, "--evm.genesis-hash", genesisHash, "--evnode.node.block_time", DefaultBlockTime, diff --git a/test/e2e/failover_e2e_test.go b/test/e2e/failover_e2e_test.go new file mode 100644 index 0000000000..0436260ed7 --- /dev/null +++ b/test/e2e/failover_e2e_test.go @@ -0,0 +1,632 @@ +//go:build e2e + +package e2e + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "maps" + "math/big" + "net/http" + "os" + "path/filepath" + "slices" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + libshare "github.com/celestiaorg/go-square/v3/share" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + evmtest "github.com/evstack/ev-node/execution/evm/test" + blobrpc "github.com/evstack/ev-node/pkg/da/jsonrpc" + coreda "github.com/evstack/ev-node/pkg/da/types" + rpcclient "github.com/evstack/ev-node/pkg/rpc/client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/evstack/ev-node/execution/evm" + "github.com/evstack/ev-node/pkg/rpc/client" + "github.com/evstack/ev-node/types" + pb "github.com/evstack/ev-node/types/pb/evnode/v1" +) + +// TestLeaseFailoverE2E runs three node binaries configured to use raft consensus. +// It forces a leader shutdown and verifies leadership failover occurs in the raft cluster. +func TestLeaseFailoverE2E(t *testing.T) { + flag.Parse() + sut := NewSystemUnderTest(t) + if testing.Verbose() { + os.Setenv("GOLOG_LOG_LEVEL", "DEBUG") + t.Cleanup(func() { + os.Unsetenv("GOLOG_LOG_LEVEL") + }) + } + + workDir := t.TempDir() + + // Get JWT secrets and setup common components first + jwtSecret, fullNodeJwtSecret, genesisHash, testEndpoints := setupCommonEVMTest(t, sut, true) + rethFn := evmtest.SetupTestRethNode(t) + jwtSecret3 := rethFn.JWTSecretHex() + fnInfo, err := rethFn.GetNetworkInfo(context.Background()) + require.NoError(t, err, "failed to get full node reth network info") + fullNode3EthPort := fnInfo.External.Ports.RPC + fullNode3EnginePort := fnInfo.External.Ports.Engine + + // Allocate raft ports for all nodes + node1RaftPort := mustGetAvailablePort(t) + node2RaftPort := mustGetAvailablePort(t) + node3RaftPort := mustGetAvailablePort(t) + + // Setup raft addresses + node1RaftAddr := fmt.Sprintf("127.0.0.1:%d", node1RaftPort) + node2RaftAddr := fmt.Sprintf("127.0.0.1:%d", node2RaftPort) + node3RaftAddr := fmt.Sprintf("127.0.0.1:%d", node3RaftPort) + raftCluster := []string{"node1@" + node1RaftAddr, "node2@" + node2RaftAddr, "node3@" + node3RaftAddr} + + bootstrapDir := filepath.Join(workDir, "bootstrap") + passphraseFile := initChain(t, sut, bootstrapDir) + + clusterNodes := &raftClusterNodes{ + nodes: make(map[string]*nodeDetails), + } + node1P2PAddr := testEndpoints.GetRollkitP2PAddress() + node2P2PAddr := testEndpoints.GetFullNodeP2PAddress() + node3P2PAddr := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", mustGetAvailablePort(t)) + + // Start node1 (bootstrap mode) + go func() { + p2pPeers := node2P2PAddr + "," + node3P2PAddr + proc := setupRaftSequencerNode(t, sut, workDir, "node1", node1RaftAddr, jwtSecret, genesisHash, testEndpoints.GetDAAddress(), + bootstrapDir, raftCluster, p2pPeers, testEndpoints.GetRollkitRPCListen(), testEndpoints.GetRollkitP2PAddress(), + testEndpoints.GetSequencerEngineURL(), testEndpoints.GetSequencerEthURL(), true, passphraseFile) + clusterNodes.Set("node1", testEndpoints.GetRollkitRPCAddress(), proc, testEndpoints.GetSequencerEthURL(), node1RaftAddr, testEndpoints.GetRollkitP2PAddress(), testEndpoints.GetSequencerEngineURL(), testEndpoints.GetSequencerEthURL()) + t.Log("Node1 is up") + }() + + // Start node2 (bootstrap node) + go func() { + t.Log("Starting Node2") + p2pPeers := node1P2PAddr + "," + node3P2PAddr + proc := setupRaftSequencerNode(t, sut, workDir, "node2", node2RaftAddr, fullNodeJwtSecret, genesisHash, testEndpoints.GetDAAddress(), bootstrapDir, raftCluster, p2pPeers, testEndpoints.GetFullNodeRPCListen(), testEndpoints.GetFullNodeP2PAddress(), testEndpoints.GetFullNodeEngineURL(), testEndpoints.GetFullNodeEthURL(), true, passphraseFile) + clusterNodes.Set("node2", testEndpoints.GetFullNodeRPCAddress(), proc, testEndpoints.GetFullNodeEthURL(), node2RaftAddr, testEndpoints.GetFullNodeP2PAddress(), testEndpoints.GetFullNodeEngineURL(), testEndpoints.GetFullNodeEthURL()) + t.Log("Node2 is up") + }() + + // Start node3 (bootstrap node) + node3EthAddr := fmt.Sprintf("http://127.0.0.1:%s", fullNode3EthPort) + go func() { + t.Log("Starting Node3") + p2pPeers := node1P2PAddr + "," + node2P2PAddr + node3RPCListen := fmt.Sprintf("127.0.0.1:%d", mustGetAvailablePort(t)) + ethEngineURL := fmt.Sprintf("http://127.0.0.1:%s", fullNode3EnginePort) + proc := setupRaftSequencerNode(t, sut, workDir, "node3", node3RaftAddr, jwtSecret3, genesisHash, testEndpoints.GetDAAddress(), bootstrapDir, raftCluster, p2pPeers, node3RPCListen, node3P2PAddr, ethEngineURL, node3EthAddr, true, passphraseFile) + clusterNodes.Set("node3", "http://"+node3RPCListen, proc, node3EthAddr, node3RaftAddr, node3P2PAddr, ethEngineURL, node3EthAddr) + t.Log("Node3 is up") + }() + + var leaderNode string + require.EventuallyWithT(t, func(collect *assert.CollectT) { + leaderNode = clusterNodes.Leader(collect) + }, 5*time.Second, 200*time.Millisecond) + + sut.AwaitNodeUp(t, clusterNodes.Details(leaderNode).rpcAddr, NodeStartupTimeout) + // Wait for at least 2 blocks to be produced + sut.AwaitNBlocks(t, 2, clusterNodes.Details(leaderNode).rpcAddr, 6*time.Second) + + // Submit a tx and ensure it propagates to all nodes + txHash1, blk1 := submitTransactionAndGetBlockNumber(t, clusterNodes.Details(leaderNode).ethClient(t)) + + for node, details := range clusterNodes.Followers(t) { + require.Eventually(t, func() bool { + rec, err := details.ethClient(t).TransactionReceipt(t.Context(), txHash1) + return err == nil && rec != nil && rec.Status == 1 && rec.BlockNumber.Uint64() == blk1 + }, 20*time.Second, SlowPollingInterval, "tx1 not seen on "+node) + } + + oldLeader := leaderNode + t.Logf("+++ Killing current leader (%s)\n", oldLeader) + _ = clusterNodes.Details(oldLeader).Kill() + + const daStartHeight = 1 + lastDABlockOldLeader := queryLastDAHeight(t, daStartHeight, jwtSecret, testEndpoints.GetDAAddress()) + t.Log("+++ Last DA block by old leader: ", lastDABlockOldLeader) + leaderElectionStart := time.Now() + + // Wait for new leader election - submit tx to node2 + var newLeader string + require.EventuallyWithT(t, func(collect *assert.CollectT) { + newLeader = clusterNodes.Leader(collect) + }, 5*time.Second, 200*time.Millisecond) + require.NotEqual(t, oldLeader, newLeader) + t.Logf("+++ New leader: %s within ~%s\n", newLeader, time.Since(leaderElectionStart)) + + // submit TX to new leader + _, blk2 := submitTxToURL(t, clusterNodes.Details(newLeader).ethClient(t)) + require.Greater(t, blk2, blk1, "post-failover block should advance") + + // Verify DA progress + var lastDABlockNewLeader uint64 + require.Eventually(t, func() bool { + lastDABlockNewLeader = queryLastDAHeight(t, lastDABlockOldLeader, jwtSecret, testEndpoints.GetDAAddress()) + return lastDABlockNewLeader > lastDABlockOldLeader + }, 2*must(time.ParseDuration(DefaultDABlockTime)), 100*time.Millisecond) + t.Logf("+++ Last DA block by new leader: %d\n", lastDABlockNewLeader) + + // Restart oldLeader to rejoin cluster + var raftClusterRPCs []string + for _, f := range clusterNodes.AllNodes() { + if f.IsRunning() { + raftClusterRPCs = append(raftClusterRPCs, f.rpcAddr) + } + } + oldDetails := clusterNodes.Details(oldLeader) + restartedNodeProcess := setupRaftSequencerNode(t, sut, workDir, oldLeader, oldDetails.raftAddr, jwtSecret, genesisHash, testEndpoints.GetDAAddress(), "", raftCluster, clusterNodes.Details(newLeader).p2pAddr, oldDetails.rpcAddr, oldDetails.p2pAddr, oldDetails.engineURL, oldDetails.ethAddr, false, passphraseFile) + t.Log("Restarted old leader to sync with cluster: " + oldLeader) + + if IsNodeUp(t, oldDetails.rpcAddr, NodeStartupTimeout) { + clusterNodes.Set(oldLeader, oldDetails.rpcAddr, restartedNodeProcess, oldDetails.ethAddr, oldDetails.raftAddr, "", oldDetails.engineURL, oldDetails.ethAddr) + } else { + t.Log("+++ old leader did not recover on restart. Skipping node verification") + } + targetHeight := blk2 + 1 + // give node some time to catch up + for range 10 { + if bn, _ := clusterNodes.Details(oldLeader).ethClient(t).BlockNumber(t.Context()); bn > targetHeight { + break + } + time.Sleep(200 * time.Millisecond) + } + + // Ensure at least two nodes are actually producing/serving blocks beyond the last known height + minReady, ready := 2, 0 + running := make(map[string]struct{}) + require.Eventually(t, func() bool { + ready = 0 + for name, n := range clusterNodes.AllNodes() { + if !n.IsRunning() { + continue + } + bn, err := n.ethClient(t).BlockNumber(t.Context()) + if err != nil { + t.Logf("err node %s : %s", name, err) + continue + } + if bn >= targetHeight { + ready++ + running[name] = struct{}{} + } + } + return ready >= minReady + }, 20*time.Second, 200*time.Millisecond, "expected at least 2 raft nodes serving height >= %d", targetHeight) + t.Logf("+++ %d/3 nodes are up and running: %s / old: %s", ready, slices.Collect(maps.Keys(running)), oldLeader) + + t.Log("+++ Verifying no double-signing...") + var state *pb.State + require.Eventually(t, func() bool { + state, err = clusterNodes.Details(newLeader).rpcClient(t).GetState(t.Context()) + return err == nil + }, time.Second, 100*time.Millisecond) + + lastDABlockNewLeader = queryLastDAHeight(t, lastDABlockNewLeader, jwtSecret, testEndpoints.GetDAAddress()) + + genesisHeight := state.InitialHeight + verifyNoDoubleSigning(t, clusterNodes, genesisHeight, state.LastBlockHeight) + + // wait for the next DA block to ensure all blocks are propagated + require.Eventually(t, func() bool { + before := lastDABlockNewLeader + lastDABlockNewLeader = queryLastDAHeight(t, lastDABlockNewLeader, jwtSecret, testEndpoints.GetDAAddress()) + return before < lastDABlockNewLeader + }, 2*must(time.ParseDuration(DefaultDABlockTime)), 100*time.Millisecond) + + t.Log("+++ Verifying no DA gaps...") + verifyDABlocks(t, daStartHeight, lastDABlockNewLeader, jwtSecret, testEndpoints.GetDAAddress(), genesisHeight, state.LastBlockHeight) + + // Cleanup processes + clusterNodes.killAll() + t.Logf("Completed leader change in: %s", time.Since(leaderElectionStart)) +} + +// verifyNoDoubleSigning checks that no two blocks at the same height have different hashes across nodes +func verifyNoDoubleSigning(t *testing.T, clusterNodes *raftClusterNodes, genesisHeight uint64, lastBlockHeight uint64) { + t.Helper() + // Compare block hashes across nodes + for height := genesisHeight; height <= lastBlockHeight; height++ { + nodeByHash := make(map[common.Hash][]string, 1) + for nodeName, node := range clusterNodes.AllNodes() { + if !node.running.Load() { + continue + } + var header *ethtypes.Header + require.Eventually(t, func() bool { + header, _ = node.ethClient(t).HeaderByNumber(t.Context(), big.NewInt(int64(height))) + return header != nil + }, 2*time.Second, 100*time.Millisecond, nodeName) + nodeByHash[header.Hash()] = append(nodeByHash[header.Hash()], nodeName) + } + if !assert.Len(t, nodeByHash, 1, "double signing detected at height %d: %v", height, nodeByHash) { + for _, nodes := range nodeByHash { + rsp, err := clusterNodes.Details(nodes[0]).rpcClient(t).GetBlockByHeight(t.Context(), height) + require.NoError(t, err) + t.Logf("%s: %v", nodes[0], rsp.Block) + } + t.FailNow() + } + } +} + +// verifyDABlocks checks that DA block heights form a continuous sequence without gaps +func verifyDABlocks(t *testing.T, daStartHeight, lastDABlock uint64, jwtSecret string, daAddress string, genesisHeight, lastEVBlock uint64) { + t.Helper() + blobClient, err := blobrpc.NewClient(t.Context(), daAddress, jwtSecret, "") + require.NoError(t, err) + defer blobClient.Close() + + ns, err := libshare.NewNamespaceFromBytes(coreda.NamespaceFromString(DefaultDANamespace).Bytes()) + require.NoError(t, err) + evHeightsToEvBlockParts := make(map[uint64]int) + deduplicationCache := make(map[string]uint64) // mixed header and data hashes + + lastEVHeight := genesisHeight + // Verify each block is present exactly once + for daHeight := daStartHeight; daHeight <= lastDABlock; daHeight++ { + blobs, err := blobClient.Blob.GetAll(t.Context(), daHeight, []libshare.Namespace{ns}) + require.NoError(t, err, "height %d/%d", daHeight, lastDABlock) + require.NotEmpty(t, blobs) + + for _, blob := range blobs { + if evHeight, hash, blobType := extractBlockHeight(t, blob.Data()); evHeight != 0 { + t.Logf("extracting block height from blob (da height %d): %4d (%s)", daHeight, evHeight, blobType) + if height, ok := deduplicationCache[hash.String()]; ok { + require.Equal(t, evHeight, height) + continue + } + require.GreaterOrEqual(t, evHeight, lastEVHeight) + lastEVHeight = evHeight + deduplicationCache[hash.String()] = evHeight + evHeightsToEvBlockParts[evHeight]++ + } + } + } + + for h := genesisHeight; h <= lastEVBlock; h++ { + // can be 1 or 2 blobs per block if data is not empty + require.NotEmpty(t, evHeightsToEvBlockParts[h], "missing block on DA for height %d/%d", h, lastEVBlock) + require.Less(t, evHeightsToEvBlockParts[h], 3, "duplicate block on DA for height %d/%d", h, lastEVBlock) + } +} + +// extractBlockHeight attempts to decode a blob as SignedHeader or SignedData and extract the block height +func extractBlockHeight(t *testing.T, blob []byte) (uint64, types.Hash, string) { + t.Helper() + if len(blob) == 0 { + t.Log("empty blob, skipping") + return 0, nil, "" + } + var headerPb pb.SignedHeader + if err := proto.Unmarshal(blob, &headerPb); err == nil { + var signedHeader types.SignedHeader + if err := signedHeader.FromProto(&headerPb); err == nil { + if err := signedHeader.Header.ValidateBasic(); err == nil { + return signedHeader.Height(), signedHeader.Hash(), "header" + } else { + jsonBZ, _ := json.MarshalIndent(signedHeader.Header, "", " ") + t.Logf("invalid header: %v: %s", err, string(jsonBZ)) + } + } else { + t.Logf("failed to unmarshal signed header: %v", err) + } + } else { + t.Logf("failed to unmarshal blob: %v", err) + } + + var signedData types.SignedData + if err := signedData.UnmarshalBinary(blob); err == nil { + if signedData.Metadata != nil { + return signedData.Height(), signedData.Hash(), "data" + } + } else { + t.Logf("failed to unmarshal signed data: %v", err) + } + return 0, nil, "" +} + +func initChain(t *testing.T, sut *SystemUnderTest, workDir string) string { + passphraseFile := createPassphraseFile(t, workDir) + output, err := sut.RunCmd(evmSingleBinaryPath, + "init", + "--chain_id", DefaultChainID, + "--rollkit.node.aggregator=true", + "--evnode.signer.passphrase_file", passphraseFile, + "--home", workDir, + ) + require.NoError(t, err, "failed to init node", output) + return passphraseFile +} +func setupRaftSequencerNode( + t *testing.T, + sut *SystemUnderTest, + workDir, nodeID, raftAddr, jwtSecret, genesisHash, daAddress, bootstrapDir string, + allRaftClusterMembers []string, + p2pPeers, rpcAddr, p2pAddr, engineURL, ethURL string, + bootstrap bool, + passphraseFile string, +) *os.Process { + t.Helper() + nodeHome := filepath.Join(workDir, nodeID) + raftDir := filepath.Join(nodeHome, "raft") + + jwtSecretFile := filepath.Join(nodeHome, "jwt-secret.hex") + if bootstrap { + initChain(t, sut, nodeHome) + jwtSecretFile = createJWTSecretFile(t, nodeHome, jwtSecret) + + // Copy genesis and signer files for non-genGenesis nodes + MustCopyFile(t, filepath.Join(bootstrapDir, "config", "genesis.json"), + filepath.Join(nodeHome, "config", "genesis.json")) + MustCopyFile(t, filepath.Join(bootstrapDir, "config", "signer.json"), + filepath.Join(nodeHome, "config", "signer.json")) + } + if strings.HasPrefix(rpcAddr, "http://") { + rpcAddr = rpcAddr[7:] + } + raftPeers := slices.DeleteFunc(slices.Clone(allRaftClusterMembers), func(v string) bool { return strings.Contains(v, nodeID+"@") || strings.TrimSpace(v) == "" }) + + // Start node with raft configuration + process := sut.ExecCmdWithLogPrefix(nodeID, evmSingleBinaryPath, + "start", + "--evnode.log.format", "json", + //"--evnode.log.level", "DEBUG", + "--home", nodeHome, + "--evm.jwt-secret-file", jwtSecretFile, + "--evm.genesis-hash", genesisHash, + "--rollkit.da.address", daAddress, + "--rollkit.node.block_time", DefaultBlockTime, + "--rollkit.node.aggregator=true", + "--evnode.signer.passphrase_file", passphraseFile, + "--evnode.signer.signer_path", filepath.Join(nodeHome, "config"), + "--rollkit.da.block_time", (200 * time.Millisecond).String(), + "--rollkit.da.namespace", DefaultDANamespace, + + "--evnode.raft.enable=true", + "--evnode.raft.node_id="+nodeID, + "--evnode.raft.raft_addr="+raftAddr, + "--evnode.raft.raft_dir="+raftDir, + "--evnode.raft.bootstrap=true", + "--evnode.raft.peers="+strings.Join(raftPeers, ","), + "--evnode.raft.snap_count=10", + "--evnode.raft.send_timeout=300ms", + "--evnode.raft.heartbeat_timeout=300ms", + + "--rollkit.p2p.peers", p2pPeers, + "--rollkit.rpc.address", rpcAddr, + "--rollkit.p2p.listen_address", p2pAddr, + "--evm.engine-url", engineURL, + "--evm.eth-url", ethURL, + ) + time.Sleep(SlowPollingInterval) + + //sut.AwaitNodeUp(t, "http://"+rpcAddr, NodeStartupTimeout) + return process +} + +// submitTxToURL submits a tx to the specified EVM endpoint and waits for inclusion. +func submitTxToURL(t *testing.T, client *ethclient.Client) (common.Hash, uint64) { + t.Helper() + ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) + defer cancel() + + priv, err := crypto.HexToECDSA(TestPrivateKey) + require.NoError(t, err) + from := crypto.PubkeyToAddress(priv.PublicKey) + + nonce, err := client.PendingNonceAt(ctx, from) + require.NoError(t, err) + ln := nonce + + tx := evm.GetRandomTransaction(t, TestPrivateKey, TestToAddress, DefaultChainID, DefaultGasLimit, &ln) + require.NoError(t, client.SendTransaction(ctx, tx)) + + var blk uint64 + require.Eventually(t, func() bool { + rec, err := client.TransactionReceipt(t.Context(), tx.Hash()) + if err == nil && rec != nil && rec.Status == 1 { + blk = rec.BlockNumber.Uint64() + return true + } + return false + }, 20*time.Second, SlowPollingInterval) + + return tx.Hash(), blk +} + +const defaultMaxBlobSize = 2 * 1024 * 1024 // 2MB + +func queryLastDAHeight(t *testing.T, startHeight uint64, jwtSecret string, daAddress string) uint64 { + t.Helper() + blobClient, err := blobrpc.NewClient(t.Context(), daAddress, jwtSecret, "") + require.NoError(t, err) + defer blobClient.Close() + ns, err := libshare.NewNamespaceFromBytes(coreda.NamespaceFromString(DefaultDANamespace).Bytes()) + require.NoError(t, err) + var lastDABlock = startHeight + for { + blobs, err := blobClient.Blob.GetAll(t.Context(), lastDABlock, []libshare.Namespace{ns}) + if err != nil { + if strings.Contains(err.Error(), "future") { + return lastDABlock - 1 + } + t.Fatal("failed to get blobs:", err) + } + if len(blobs) != 0 && testing.Verbose() { + t.Log("+++ DA block: ", lastDABlock, " blobs: ", len(blobs)) + } + lastDABlock++ + } +} + +type nodeDetails struct { + raftAddr string + rpcAddr string + process *os.Process + ethAddr string + + extClientOnce sync.Once + xEthClient atomic.Pointer[ethclient.Client] + xRPCClient atomic.Pointer[rpcclient.Client] + running atomic.Bool + p2pAddr string + engineURL string + ethURL string +} + +func (d *nodeDetails) ethClient(t *testing.T) *ethclient.Client { + t.Helper() + d.initExtClients(t) + return d.xEthClient.Load() +} + +func (d *nodeDetails) rpcClient(t *testing.T) *rpcclient.Client { + t.Helper() + d.initExtClients(t) + return d.xRPCClient.Load() + +} + +func (d *nodeDetails) initExtClients(t *testing.T) { + require.NotNil(t, d) + d.extClientOnce.Do(func() { + client, err := ethclient.Dial(d.ethAddr) + require.NoError(t, err) + d.xEthClient.Store(client) + t.Cleanup(client.Close) + rpcClient := rpcclient.NewClient(d.rpcAddr) + require.NotNil(t, rpcClient) + d.xRPCClient.Store(rpcClient) + }) +} + +func (d *nodeDetails) IsRunning() bool { + return d.running.Load() +} + +func (d *nodeDetails) Kill() (err error) { + err = d.process.Kill() + d.running.Store(false) + return +} + +type raftClusterNodes struct { + mx sync.Mutex + nodes map[string]*nodeDetails +} + +func (c *raftClusterNodes) Set(node string, listen string, proc *os.Process, eth string, raftAddr string, p2pAddr string, engineURL string, ethURL string) { + c.mx.Lock() + defer c.mx.Unlock() + d := &nodeDetails{raftAddr: raftAddr, rpcAddr: listen, process: proc, ethAddr: eth, p2pAddr: p2pAddr, engineURL: engineURL, ethURL: ethURL} + d.running.Store(true) + c.nodes[node] = d +} + +func (c *raftClusterNodes) Leader(t require.TestingT) string { + node, _ := leader(t, c.AllNodes()) + return node +} + +func (c *raftClusterNodes) Details(node string) *nodeDetails { + c.mx.Lock() + defer c.mx.Unlock() + return c.nodes[node] +} + +func (c *raftClusterNodes) Followers(t require.TestingT) map[string]*nodeDetails { + all := c.AllNodes() + leader, _ := leader(t, all) + delete(all, leader) + return all +} + +func (c *raftClusterNodes) killAll() { + for _, d := range c.AllNodes() { + _ = d.Kill() + } +} + +// allNodes returns snapshot of nodes map +func (c *raftClusterNodes) AllNodes() map[string]*nodeDetails { + c.mx.Lock() + defer c.mx.Unlock() + return maps.Clone(c.nodes) +} + +// fails when no leader is found +func leader(t require.TestingT, nodes map[string]*nodeDetails) (string, *nodeDetails) { + client := &http.Client{Timeout: 1 * time.Second} + type nodeStatus struct { + IsLeader bool `json:"is_leader"` + } + for node, details := range nodes { + if !details.running.Load() { + continue + } + resp, err := client.Get(details.rpcAddr + "/raft/node") + require.NoError(t, err) + defer resp.Body.Close() + + var status nodeStatus + require.NoError(t, json.NewDecoder(resp.Body).Decode(&status)) + + if status.IsLeader { + return node, details + } + } + + t.Errorf("no leader found") + return "", nil +} + +func must[T any](r T, err error) T { + if err != nil { + panic(err) + } + return r +} + +// IsNodeUp waits until a node is operational by validating it produces blocks. +// Returns true if node is up within the specified timeout. +// Unlike AwaitNodeUp, this method Does not fail tests. +func IsNodeUp(t *testing.T, rpcAddr string, timeout time.Duration) bool { + t.Helper() + t.Logf("Query node is up: %s", rpcAddr) + ctx, done := context.WithTimeout(context.Background(), timeout) + defer done() + + ticker := time.Tick(min(timeout/10, 200*time.Millisecond)) + c := client.NewClient(rpcAddr) + require.NotNil(t, c) + var lastBlock uint64 + for { + select { + case <-ticker: + switch s, err := c.GetState(ctx); { + case err != nil: // ignore + case lastBlock == 0: + lastBlock = s.LastBlockHeight + case lastBlock < s.LastBlockHeight: + return true + } + case <-ctx.Done(): + return false + } + } +} diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 77440192e6..a58b7e4eed 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -16,6 +16,7 @@ require ( github.com/evstack/ev-node/execution/evm/test v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.46.0 github.com/stretchr/testify v1.11.1 + google.golang.org/protobuf v1.36.10 ) replace ( @@ -249,7 +250,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/grpc v1.75.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect diff --git a/test/e2e/sut_helper.go b/test/e2e/sut_helper.go index 3aaa032a0a..beba2b6195 100644 --- a/test/e2e/sut_helper.go +++ b/test/e2e/sut_helper.go @@ -369,4 +369,4 @@ func NodeID(t *testing.T, nodeDir string) peer.ID { node1ID, err := peer.IDFromPrivateKey(node1Key.PrivKey) require.NoError(t, err) return node1ID -} +} \ No newline at end of file diff --git a/test/mocks/store.go b/test/mocks/store.go index 7f2aa180d0..ad05c76f5c 100644 --- a/test/mocks/store.go +++ b/test/mocks/store.go @@ -880,3 +880,54 @@ func (_c *MockStore_SetMetadata_Call) RunAndReturn(run func(ctx context.Context, _c.Call.Return(run) return _c } + +// Sync provides a mock function for the type MockStore +func (_mock *MockStore) Sync(ctx context.Context) error { + ret := _mock.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Sync") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = returnFunc(ctx) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockStore_Sync_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sync' +type MockStore_Sync_Call struct { + *mock.Call +} + +// Sync is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockStore_Expecter) Sync(ctx interface{}) *MockStore_Sync_Call { + return &MockStore_Sync_Call{Call: _e.mock.On("Sync", ctx)} +} + +func (_c *MockStore_Sync_Call) Run(run func(ctx context.Context)) *MockStore_Sync_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockStore_Sync_Call) Return(err error) *MockStore_Sync_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockStore_Sync_Call) RunAndReturn(run func(ctx context.Context) error) *MockStore_Sync_Call { + _c.Call.Return(run) + return _c +} diff --git a/types/pb/evnode/v1/state.pb.go b/types/pb/evnode/v1/state.pb.go index 492991a38f..a76c7efb28 100644 --- a/types/pb/evnode/v1/state.pb.go +++ b/types/pb/evnode/v1/state.pb.go @@ -123,6 +123,99 @@ func (x *State) GetLastHeaderHash() []byte { return nil } +// RaftBlockState represents a replicated block state +type RaftBlockState struct { + state protoimpl.MessageState `protogen:"open.v1"` + Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + LastSubmittedDaHeaderHeight uint64 `protobuf:"varint,2,opt,name=last_submitted_da_header_height,json=lastSubmittedDaHeaderHeight,proto3" json:"last_submitted_da_header_height,omitempty"` + LastSubmittedDaDataHeight uint64 `protobuf:"varint,3,opt,name=last_submitted_da_data_height,json=lastSubmittedDaDataHeight,proto3" json:"last_submitted_da_data_height,omitempty"` + Hash []byte `protobuf:"bytes,4,opt,name=hash,proto3" json:"hash,omitempty"` + Timestamp uint64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Header []byte `protobuf:"bytes,6,opt,name=header,proto3" json:"header,omitempty"` + Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RaftBlockState) Reset() { + *x = RaftBlockState{} + mi := &file_evnode_v1_state_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RaftBlockState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RaftBlockState) ProtoMessage() {} + +func (x *RaftBlockState) ProtoReflect() protoreflect.Message { + mi := &file_evnode_v1_state_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RaftBlockState.ProtoReflect.Descriptor instead. +func (*RaftBlockState) Descriptor() ([]byte, []int) { + return file_evnode_v1_state_proto_rawDescGZIP(), []int{1} +} + +func (x *RaftBlockState) GetHeight() uint64 { + if x != nil { + return x.Height + } + return 0 +} + +func (x *RaftBlockState) GetLastSubmittedDaHeaderHeight() uint64 { + if x != nil { + return x.LastSubmittedDaHeaderHeight + } + return 0 +} + +func (x *RaftBlockState) GetLastSubmittedDaDataHeight() uint64 { + if x != nil { + return x.LastSubmittedDaDataHeight + } + return 0 +} + +func (x *RaftBlockState) GetHash() []byte { + if x != nil { + return x.Hash + } + return nil +} + +func (x *RaftBlockState) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *RaftBlockState) GetHeader() []byte { + if x != nil { + return x.Header + } + return nil +} + +func (x *RaftBlockState) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + // SequencerDACheckpoint tracks the position in the DA where transactions were last processed type SequencerDACheckpoint struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -136,7 +229,7 @@ type SequencerDACheckpoint struct { func (x *SequencerDACheckpoint) Reset() { *x = SequencerDACheckpoint{} - mi := &file_evnode_v1_state_proto_msgTypes[1] + mi := &file_evnode_v1_state_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -148,7 +241,7 @@ func (x *SequencerDACheckpoint) String() string { func (*SequencerDACheckpoint) ProtoMessage() {} func (x *SequencerDACheckpoint) ProtoReflect() protoreflect.Message { - mi := &file_evnode_v1_state_proto_msgTypes[1] + mi := &file_evnode_v1_state_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -161,7 +254,7 @@ func (x *SequencerDACheckpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use SequencerDACheckpoint.ProtoReflect.Descriptor instead. func (*SequencerDACheckpoint) Descriptor() ([]byte, []int) { - return file_evnode_v1_state_proto_rawDescGZIP(), []int{1} + return file_evnode_v1_state_proto_rawDescGZIP(), []int{2} } func (x *SequencerDACheckpoint) GetDaHeight() uint64 { @@ -191,7 +284,15 @@ const file_evnode_v1_state_proto_rawDesc = "" + "\x0flast_block_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\rlastBlockTime\x12\x1b\n" + "\tda_height\x18\x06 \x01(\x04R\bdaHeight\x12\x19\n" + "\bapp_hash\x18\b \x01(\fR\aappHash\x12(\n" + - "\x10last_header_hash\x18\t \x01(\fR\x0elastHeaderHashJ\x04\b\a\x10\b\"O\n" + + "\x10last_header_hash\x18\t \x01(\fR\x0elastHeaderHashJ\x04\b\a\x10\b\"\x8e\x02\n" + + "\x0eRaftBlockState\x12\x16\n" + + "\x06height\x18\x01 \x01(\x04R\x06height\x12D\n" + + "\x1flast_submitted_da_header_height\x18\x02 \x01(\x04R\x1blastSubmittedDaHeaderHeight\x12@\n" + + "\x1dlast_submitted_da_data_height\x18\x03 \x01(\x04R\x19lastSubmittedDaDataHeight\x12\x12\n" + + "\x04hash\x18\x04 \x01(\fR\x04hash\x12\x1c\n" + + "\ttimestamp\x18\x05 \x01(\x04R\ttimestamp\x12\x16\n" + + "\x06header\x18\x06 \x01(\fR\x06header\x12\x12\n" + + "\x04data\x18\a \x01(\fR\x04data\"O\n" + "\x15SequencerDACheckpoint\x12\x1b\n" + "\tda_height\x18\x01 \x01(\x04R\bdaHeight\x12\x19\n" + "\btx_index\x18\x02 \x01(\x04R\atxIndexB/Z-github.com/evstack/ev-node/types/pb/evnode/v1b\x06proto3" @@ -208,16 +309,17 @@ func file_evnode_v1_state_proto_rawDescGZIP() []byte { return file_evnode_v1_state_proto_rawDescData } -var file_evnode_v1_state_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_evnode_v1_state_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_evnode_v1_state_proto_goTypes = []any{ (*State)(nil), // 0: evnode.v1.State - (*SequencerDACheckpoint)(nil), // 1: evnode.v1.SequencerDACheckpoint - (*Version)(nil), // 2: evnode.v1.Version - (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp + (*RaftBlockState)(nil), // 1: evnode.v1.RaftBlockState + (*SequencerDACheckpoint)(nil), // 2: evnode.v1.SequencerDACheckpoint + (*Version)(nil), // 3: evnode.v1.Version + (*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp } var file_evnode_v1_state_proto_depIdxs = []int32{ - 2, // 0: evnode.v1.State.version:type_name -> evnode.v1.Version - 3, // 1: evnode.v1.State.last_block_time:type_name -> google.protobuf.Timestamp + 3, // 0: evnode.v1.State.version:type_name -> evnode.v1.Version + 4, // 1: evnode.v1.State.last_block_time:type_name -> google.protobuf.Timestamp 2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name @@ -237,7 +339,7 @@ func file_evnode_v1_state_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_evnode_v1_state_proto_rawDesc), len(file_evnode_v1_state_proto_rawDesc)), NumEnums: 0, - NumMessages: 2, + NumMessages: 3, NumExtensions: 0, NumServices: 0, },