Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: update v0.17 branch with latest code for release #2528

Merged
merged 10 commits into from
Aug 9, 2023
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
# Config options can be found in README here: https://github.com/golangci/golangci-lint-action
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/govulncheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
- run: govulncheck -show=stacks -test ./...
2 changes: 1 addition & 1 deletion .github/workflows/nightly-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- uses: actions/cache@v3
with:
path: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/setup-python@v2
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- uses: pre-commit/[email protected]

- name: notify failure
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
fetch-depth: 0 # Disable shallow checkout
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- run: go run . --help > cli-reference.txt
- run: go run testutil/genchangelog/main.go
- uses: softprops/action-gh-release@v1
Expand Down
33 changes: 30 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- uses: actions/cache@v3
with:
path: |
Expand All @@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- uses: actions/cache@v3
with:
path: |
Expand All @@ -51,7 +51,7 @@ jobs:
- uses: docker/setup-buildx-action@v2 # For compose to build images
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'
- uses: actions/cache@v3
with:
path: |
Expand All @@ -71,6 +71,33 @@ jobs:
path: testutil/compose/smoke/*.log
retention-days: 3

fuzz_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-buildx-action@v2 # For compose to build images
- uses: actions/setup-go@v4
with:
go-version: '1.20.7'
- uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- run: |
echo "CHARON_REPO=$(pwd)" >> $GITHUB_ENV
echo "DOCKER_BUILDKIT=1" >> $GITHUB_ENV
- run: go test -race github.com/obolnetwork/charon/testutil/compose/fuzz -v -fuzzer -sudo-perms -timeout=45m -log-dir=.
- uses: actions/upload-artifact@v3
if: always()
with:
name: fuzz-test-logs
path: testutil/compose/fuzz/*.log
retention-days: 3

notify_failure:
runs-on: ubuntu-latest
needs: [ unit_tests, integration_tests, compose_tests ]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/track-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'

- name: "Track PR"
run: go run github.com/obolnetwork/charon/testutil/trackpr
2 changes: 1 addition & 1 deletion .github/workflows/verify-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20.6'
go-version: '1.20.7'

- name: "Verify PR"
run: go run github.com/obolnetwork/charon/testutil/verifypr
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
run:
timeout: 5m
go: "1.20.6"
go: "1.20.7"
linters-settings:
cyclop:
max-complexity: 15
Expand Down Expand Up @@ -89,7 +89,7 @@ linters-settings:
- "github.com/gogo/protobuf/proto" # Prefer google.golang.org/protobuf
- "github.com/prometheus/client_golang/prometheus/promauto" # Prefer ./app/promauto
staticcheck:
go: "1.20.6"
go: "1.20.7"
checks:
- "all"
- "-SA1019" # Ignoring since github.com/drand/kyber/sign/bls uses Proof Of Possession as does Ethereum.
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Container for building Go binary.
FROM golang:1.20.6-bullseye AS builder
FROM golang:1.20.7-bullseye AS builder
# Install dependencies
RUN apt-get update && apt-get install -y build-essential git
# Prep and copy source
Expand Down
6 changes: 3 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ func wireCoreWorkflow(ctx context.Context, life *lifecycle.Manager, conf Config,
return err
}

if err := wireVAPIRouter(life, conf.ValidatorAPIAddr, eth2Cl, vapi, vapiCalls); err != nil {
if err := wireVAPIRouter(ctx, life, conf.ValidatorAPIAddr, eth2Cl, vapi, vapiCalls); err != nil {
return err
}

Expand Down Expand Up @@ -889,10 +889,10 @@ func createMockValidators(pubkeys []eth2p0.BLSPubKey) beaconmock.ValidatorSet {
}

// wireVAPIRouter constructs the validator API router and registers it with the life cycle manager.
func wireVAPIRouter(life *lifecycle.Manager, vapiAddr string, eth2Cl eth2wrap.Client,
func wireVAPIRouter(ctx context.Context, life *lifecycle.Manager, vapiAddr string, eth2Cl eth2wrap.Client,
handler validatorapi.Handler, vapiCalls func(),
) error {
vrouter, err := validatorapi.NewRouter(handler, eth2Cl)
vrouter, err := validatorapi.NewRouter(ctx, handler, eth2Cl)
if err != nil {
return errors.Wrap(err, "new monitoring server")
}
Expand Down
55 changes: 42 additions & 13 deletions app/obolapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package obolapi
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"net/url"
Expand All @@ -15,46 +16,74 @@ import (
"github.com/obolnetwork/charon/cluster"
)

const (
// launchpadReturnPathFmt is the URL path format string at which one can find details for a given cluster lock hash.
launchpadReturnPathFmt = "/lock/0x%X/launchpad"
)

// New returns a new Client.
func New(url string) Client {
return Client{
baseURL: url,
func New(urlStr string) (Client, error) {
_, err := url.ParseRequestURI(urlStr) // check that urlStr is valid
if err != nil {
return Client{}, errors.Wrap(err, "could not parse Obol API URL")
}

return Client{
baseURL: urlStr,
}, nil
}

// Client is the REST client for obol-api requests.
type Client struct {
baseURL string // Base obol-api URL
}

// url returns a *url.URL from the baseURL stored in c.
// Will panic if somehow c.baseURL got corrupted, and it's not a valid URL anymore.
func (c Client) url() *url.URL {
baseURL, err := url.ParseRequestURI(c.baseURL)
if err != nil {
panic(errors.Wrap(err, "could not parse Obol API URL, this should never happen"))
}

return baseURL
}

// PublishLock posts the lockfile to obol-api.
func (c Client) PublishLock(ctx context.Context, lock cluster.Lock) error {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

addr, err := url.JoinPath(c.baseURL, "lock")
if err != nil {
return errors.Wrap(err, "invalid address")
}

url, err := url.Parse(addr)
if err != nil {
return errors.Wrap(err, "invalid endpoint")
}
addr := c.url()
addr.Path = "lock"

b, err := lock.MarshalJSON()
if err != nil {
return errors.Wrap(err, "marshal lock")
}

err = httpPost(ctx, url, b)
err = httpPost(ctx, addr, b)
if err != nil {
return err
}

return nil
}

// LaunchpadURLForLock returns the Launchpad cluster dashboard page for a given lock, on the given
// Obol API client.
func (c Client) LaunchpadURLForLock(lock cluster.Lock) string {
lURL := c.url()

lURL.Path = launchpadURLPath(lock)

return lURL.String()
}

func launchpadURLPath(lock cluster.Lock) string {
return fmt.Sprintf(launchpadReturnPathFmt, lock.LockHash)
}

func httpPost(ctx context.Context, url *url.URL, b []byte) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url.String(), bytes.NewReader(b))
if err != nil {
Expand Down
49 changes: 47 additions & 2 deletions app/obolapi/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
package obolapi_test

import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"net/url"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -45,8 +47,51 @@ func TestLockPublish(t *testing.T) {

lock, _, _ := cluster.NewForT(t, 3, 3, 4, 0, opts...)

cl := obolapi.New(srv.URL)
err := cl.PublishLock(ctx, lock)
cl, err := obolapi.New(srv.URL)
require.NoError(t, err)
err = cl.PublishLock(ctx, lock)
require.NoError(t, err)
})
}

func TestURLParsing(t *testing.T) {
t.Run("invalid url", func(t *testing.T) {
cl, err := obolapi.New("badURL")
require.Error(t, err)
require.Empty(t, cl)
})

t.Run("http url", func(t *testing.T) {
cl, err := obolapi.New("http://unsafe.today")
require.NoError(t, err)
require.NotEmpty(t, cl)
})

t.Run("https url", func(t *testing.T) {
cl, err := obolapi.New("https://safe.today")
require.NoError(t, err)
require.NotEmpty(t, cl)
})
}

func TestLaunchpadDashURL(t *testing.T) {
t.Run("produced url is what we expect", func(t *testing.T) {
cl, err := obolapi.New("https://safe.today")
require.NoError(t, err)
require.NotEmpty(t, cl)

result := cl.LaunchpadURLForLock(cluster.Lock{LockHash: bytes.Repeat([]byte{0x42}, 32)})

require.NotEmpty(t, result)

parsedRes, err := url.ParseRequestURI(result)
require.NoError(t, err)

require.Equal(t, "safe.today", parsedRes.Host)
require.Equal(
t,
"/lock/0x4242424242424242424242424242424242424242424242424242424242424242/launchpad",
parsedRes.Path,
)
})
}
30 changes: 23 additions & 7 deletions cmd/createcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,14 @@ func runCreateCluster(ctx context.Context, w io.Writer, conf clusterConfig) erro
lock.NodeSignatures = append(lock.NodeSignatures, nodeSig)
}

// dashboardURL is the Launchpad dashboard url for a given lock file.
// If empty, either conf.Publish wasn't specified or there was a processing error in publishing
// the generated lock file.
var dashboardURL string

// Write cluster-lock file
if conf.Publish {
if err = writeLockToAPI(ctx, conf.PublishAddr, lock); err != nil {
if dashboardURL, err = writeLockToAPI(ctx, conf.PublishAddr, lock); err != nil {
log.Warn(ctx, "Couldn't publish lock file to Obol API", err)
}
}
Expand All @@ -272,7 +277,15 @@ func runCreateCluster(ctx context.Context, w io.Writer, conf clusterConfig) erro
writeWarning(w)
}

return writeOutput(w, conf.SplitKeys, conf.ClusterDir, numNodes, keysToDisk)
if err := writeOutput(w, conf.SplitKeys, conf.ClusterDir, numNodes, keysToDisk); err != nil {
return err
}

if dashboardURL != "" {
log.Info(ctx, fmt.Sprintf("You can find your newly-created cluster dashboard here: %s", dashboardURL))
}

return nil
}

// validateCreateConfig returns an error if any of the provided config parameters are invalid.
Expand Down Expand Up @@ -943,17 +956,20 @@ func randomHex64() (string, error) {
return hex.EncodeToString(b), nil
}

// writeLockToAPI posts the lock file to obol-api.
func writeLockToAPI(ctx context.Context, publishAddr string, lock cluster.Lock) error {
cl := obolapi.New(publishAddr)
// writeLockToAPI posts the lock file to obol-api and returns the Launchpad dashboard URL.
func writeLockToAPI(ctx context.Context, publishAddr string, lock cluster.Lock) (string, error) {
cl, err := obolapi.New(publishAddr)
if err != nil {
return "", err
}

if err := cl.PublishLock(ctx, lock); err != nil {
return err
return "", err
}

log.Info(ctx, "Published lock file", z.Str("addr", publishAddr))

return nil
return cl.LaunchpadURLForLock(lock), nil
}

// validateAddresses checks if we have sufficient addresses. It also fills addresses slices if only one is provided.
Expand Down
Loading