Skip to content

Commit 46c667d

Browse files
committed
Add "chain queues".
1 parent 50f4a9c commit 46c667d

File tree

13 files changed

+515
-30
lines changed

13 files changed

+515
-30
lines changed

.github/workflows/release.yml

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ jobs:
5050

5151
- name: Fetch xgo
5252
run: |
53-
go install github.com/wealdtech/xgo@latest
53+
go install github.com/crazy-max/xgo@v0.14.0
5454
5555
- name: Cross-compile linux
5656
run: |
57-
xgo -v -x -ldflags="-X github.com/wealdtech/ethdo/cmd.ReleaseVersion=${RELEASE_VERSION}" --targets="linux/amd64" github.com/wealdtech/ethdo
57+
xgo -v -x -ldflags="-X github.com/wealdtech/ethdo/cmd.ReleaseVersion=${RELEASE_VERSION}" --targets="linux/amd64,linux/arm64" github.com/wealdtech/ethdo
5858
5959
- name: Cross-compile windows
6060
run: |
@@ -72,11 +72,11 @@ jobs:
7272
tar zcf ethdo-${RELEASE_VERSION}-linux-amd64.tar.gz ethdo
7373
sha256sum ethdo-${RELEASE_VERSION}-linux-amd64.tar.gz >ethdo-${RELEASE_VERSION}-linux-amd64.sha256
7474
75-
# - name: Create linux ARM64 tgz file
76-
# run: |
77-
# mv ethdo-linux-arm64 ethdo
78-
# tar zcf ethdo-${RELEASE_VERSION}-linux-arm64.tar.gz ethdo
79-
# sha256sum ethdo-${RELEASE_VERSION}-linux-arm64.tar.gz >ethdo-${RELEASE_VERSION}-linux-arm64.sha256
75+
- name: Create linux ARM64 tgz file
76+
run: |
77+
mv ethdo-linux-arm64 ethdo
78+
tar zcf ethdo-${RELEASE_VERSION}-linux-arm64.tar.gz ethdo
79+
sha256sum ethdo-${RELEASE_VERSION}-linux-arm64.tar.gz >ethdo-${RELEASE_VERSION}-linux-arm64.sha256
8080
8181
- name: Create release
8282
id: create_release
@@ -133,24 +133,24 @@ jobs:
133133
asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-amd64.tar.gz
134134
asset_content_type: application/gzip
135135

136-
# - name: Upload linux ARM64 checksum file
137-
# id: upload-release-asset-linux-arm64-checksum
138-
# uses: actions/upload-release-asset@v1
139-
# env:
140-
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
141-
# with:
142-
# upload_url: ${{ steps.create_release.outputs.upload_url }}
143-
# asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.sha256
144-
# asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.sha256
145-
# asset_content_type: text/plain
146-
147-
# - name: Upload linux ARM64 tgz file
148-
# id: upload-release-asset-linux-arm64
149-
# uses: actions/upload-release-asset@v1
150-
# env:
151-
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152-
# with:
153-
# upload_url: ${{ steps.create_release.outputs.upload_url }}
154-
# asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.tar.gz
155-
# asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.tar.gz
156-
# asset_content_type: application/gzip
136+
- name: Upload linux ARM64 checksum file
137+
id: upload-release-asset-linux-arm64-checksum
138+
uses: actions/upload-release-asset@v1
139+
env:
140+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
141+
with:
142+
upload_url: ${{ steps.create_release.outputs.upload_url }}
143+
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.sha256
144+
asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.sha256
145+
asset_content_type: text/plain
146+
147+
- name: Upload linux ARM64 tgz file
148+
id: upload-release-asset-linux-arm64
149+
uses: actions/upload-release-asset@v1
150+
env:
151+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152+
with:
153+
upload_url: ${{ steps.create_release.outputs.upload_url }}
154+
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.tar.gz
155+
asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.tar.gz
156+
asset_content_type: application/gzip

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
1.20.0:
2+
- add "chain queues"
3+
14
1.19.1:
25
- add the ability to import keystores to ethdo wallets
36
- use defaults to connect to beacon nodes if no explicit connection defined

cmd/chain/queues/command.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright © 2022 Weald Technology Trading.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package chainqueues
15+
16+
import (
17+
"context"
18+
"time"
19+
20+
eth2client "github.com/attestantio/go-eth2-client"
21+
"github.com/pkg/errors"
22+
"github.com/spf13/viper"
23+
"github.com/wealdtech/ethdo/services/chaintime"
24+
)
25+
26+
type command struct {
27+
quiet bool
28+
verbose bool
29+
debug bool
30+
json bool
31+
32+
// Beacon node connection.
33+
timeout time.Duration
34+
connection string
35+
allowInsecureConnections bool
36+
37+
// Input.
38+
epoch string
39+
40+
// Data access.
41+
eth2Client eth2client.Service
42+
validatorsProvider eth2client.ValidatorsProvider
43+
chainTime chaintime.Service
44+
45+
// Output.
46+
activationQueue int
47+
exitQueue int
48+
}
49+
50+
func newCommand(ctx context.Context) (*command, error) {
51+
c := &command{
52+
quiet: viper.GetBool("quiet"),
53+
verbose: viper.GetBool("verbose"),
54+
debug: viper.GetBool("debug"),
55+
json: viper.GetBool("json"),
56+
}
57+
58+
// Timeout.
59+
if viper.GetDuration("timeout") == 0 {
60+
return nil, errors.New("timeout is required")
61+
}
62+
c.timeout = viper.GetDuration("timeout")
63+
64+
if viper.GetString("epoch") != "" {
65+
c.epoch = viper.GetString("epoch")
66+
}
67+
68+
if viper.GetString("connection") == "" {
69+
return nil, errors.New("connection is required")
70+
}
71+
c.connection = viper.GetString("connection")
72+
c.allowInsecureConnections = viper.GetBool("allow-insecure-connections")
73+
74+
return c, nil
75+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright © 2022 Weald Technology Trading.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package chainqueues
15+
16+
import (
17+
"context"
18+
"os"
19+
"testing"
20+
21+
"github.com/spf13/viper"
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
func TestInput(t *testing.T) {
26+
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
27+
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
28+
}
29+
30+
tests := []struct {
31+
name string
32+
vars map[string]interface{}
33+
err string
34+
}{
35+
{
36+
name: "TimeoutMissing",
37+
vars: map[string]interface{}{},
38+
err: "timeout is required",
39+
},
40+
{
41+
name: "ConnectionMissing",
42+
vars: map[string]interface{}{
43+
"timeout": "5s",
44+
"data": "{}",
45+
},
46+
err: "connection is required",
47+
},
48+
{
49+
name: "Good",
50+
vars: map[string]interface{}{
51+
"timeout": "5s",
52+
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
53+
},
54+
},
55+
}
56+
57+
for _, test := range tests {
58+
t.Run(test.name, func(t *testing.T) {
59+
viper.Reset()
60+
61+
for k, v := range test.vars {
62+
viper.Set(k, v)
63+
}
64+
_, err := newCommand(context.Background())
65+
if test.err != "" {
66+
require.EqualError(t, err, test.err)
67+
} else {
68+
require.NoError(t, err)
69+
}
70+
})
71+
}
72+
}

cmd/chain/queues/output.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright © 2022 Weald Technology Trading.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package chainqueues
15+
16+
import (
17+
"context"
18+
"encoding/json"
19+
"fmt"
20+
"strings"
21+
)
22+
23+
type jsonOutput struct {
24+
ActivationQueue int `json:"activation_queue"`
25+
ExitQueue int `json:"exit_queue"`
26+
}
27+
28+
func (c *command) output(ctx context.Context) (string, error) {
29+
if c.quiet {
30+
return "", nil
31+
}
32+
33+
if c.json {
34+
return c.outputJSON(ctx)
35+
}
36+
return c.outputText(ctx)
37+
}
38+
39+
func (c *command) outputJSON(ctx context.Context) (string, error) {
40+
output := &jsonOutput{
41+
ActivationQueue: c.activationQueue,
42+
ExitQueue: c.exitQueue,
43+
}
44+
data, err := json.Marshal(output)
45+
if err != nil {
46+
return "", err
47+
}
48+
49+
return string(data), nil
50+
}
51+
52+
func (c *command) outputText(ctx context.Context) (string, error) {
53+
builder := strings.Builder{}
54+
55+
if c.activationQueue > 0 {
56+
builder.WriteString(fmt.Sprintf("Activation queue: %d\n", c.activationQueue))
57+
}
58+
if c.exitQueue > 0 {
59+
builder.WriteString(fmt.Sprintf("Exit queue: %d\n", c.exitQueue))
60+
}
61+
62+
return strings.TrimSuffix(builder.String(), "\n"), nil
63+
}

cmd/chain/queues/process.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright © 2022 Weald Technology Trading.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package chainqueues
15+
16+
import (
17+
"context"
18+
"fmt"
19+
20+
eth2client "github.com/attestantio/go-eth2-client"
21+
"github.com/pkg/errors"
22+
standardchaintime "github.com/wealdtech/ethdo/services/chaintime/standard"
23+
"github.com/wealdtech/ethdo/util"
24+
)
25+
26+
func (c *command) process(ctx context.Context) error {
27+
// Obtain information we need to process.
28+
if err := c.setup(ctx); err != nil {
29+
return err
30+
}
31+
32+
epoch, err := util.ParseEpoch(ctx, c.chainTime, c.epoch)
33+
if err != nil {
34+
return err
35+
}
36+
37+
validators, err := c.validatorsProvider.Validators(ctx, fmt.Sprintf("%d", c.chainTime.FirstSlotOfEpoch(epoch)), nil)
38+
if err != nil {
39+
return errors.Wrap(err, "failed to obtain validators")
40+
}
41+
42+
for _, validator := range validators {
43+
if validator.Validator == nil {
44+
continue
45+
}
46+
if validator.Validator.ActivationEligibilityEpoch <= epoch && validator.Validator.ActivationEpoch > epoch {
47+
c.activationQueue++
48+
}
49+
if validator.Validator.ExitEpoch != 0xffffffffffffffff && validator.Validator.ExitEpoch > epoch {
50+
c.exitQueue++
51+
}
52+
}
53+
54+
return nil
55+
}
56+
57+
func (c *command) setup(ctx context.Context) error {
58+
var err error
59+
60+
// Connect to the client.
61+
c.eth2Client, err = util.ConnectToBeaconNode(ctx, c.connection, c.timeout, c.allowInsecureConnections)
62+
if err != nil {
63+
return errors.Wrap(err, "failed to connect to beacon node")
64+
}
65+
66+
c.chainTime, err = standardchaintime.New(ctx,
67+
standardchaintime.WithSpecProvider(c.eth2Client.(eth2client.SpecProvider)),
68+
standardchaintime.WithForkScheduleProvider(c.eth2Client.(eth2client.ForkScheduleProvider)),
69+
standardchaintime.WithGenesisTimeProvider(c.eth2Client.(eth2client.GenesisTimeProvider)),
70+
)
71+
if err != nil {
72+
return errors.Wrap(err, "failed to set up chaintime service")
73+
}
74+
75+
var isProvider bool
76+
c.validatorsProvider, isProvider = c.eth2Client.(eth2client.ValidatorsProvider)
77+
if !isProvider {
78+
return errors.New("connection does not provide validator information")
79+
}
80+
81+
return nil
82+
}

0 commit comments

Comments
 (0)