Skip to content

Commit

Permalink
feat: implement initial functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
0x416e746f6e committed Mar 5, 2024
1 parent 57d2f34 commit 4135fdc
Show file tree
Hide file tree
Showing 63 changed files with 4,535 additions and 0 deletions.
85 changes: 85 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: release

on:
workflow_dispatch:
push:
tags:
- "v*"

jobs:
release-backend:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4

- name: setup go dependencies
uses: actions/setup-go@v5
with:
go-version: "1.22"

- name: setup quemu
uses: docker/setup-qemu-action@v3

- name: setup docker buildx
uses: docker/setup-buildx-action@v3

- name: login to docker hub
uses: docker/login-action@v2
with:
username: ${{ secrets.FLASHBOTS_DOCKERHUB_USERNAME }}
password: ${{ secrets.FLASHBOTS_DOCKERHUB_TOKEN }}

- name: login to ghcr
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: build and publish backend release
uses: goreleaser/goreleaser-action@v5
with:
args: release --clean
distribution: goreleaser
workdir: ./backend
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

release-frontend:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4

- name: setup go dependencies
uses: actions/setup-go@v5
with:
go-version: "1.22"

- name: setup quemu
uses: docker/setup-qemu-action@v3

- name: setup docker buildx
uses: docker/setup-buildx-action@v3

- name: login to docker hub
uses: docker/login-action@v2
with:
username: ${{ secrets.FLASHBOTS_DOCKERHUB_USERNAME }}
password: ${{ secrets.FLASHBOTS_DOCKERHUB_TOKEN }}

- name: login to ghcr
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: build and publish frontend release
uses: docker/build-push-action@v5
with:
context: ./frontend
platforms: linux/amd64,linux/arm64
push: true
tags: flashbots/eth-faucet-frontend:${{ github.ref_name }},ghcr.io/flashbots/eth-faucet-frontend:${{ github.ref_name }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

.idea
.vscode
*.code-workspace

# temporary files

Expand Down
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2024 Flashbots

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
VERSION := $(shell git describe --tags --always --dirty="-dev" --match "v*.*.*" || echo "development" )
VERSION := $(VERSION:v%=%)

.PHONY: build-backend
build-backend:
@cd ./backend && CGO_ENABLED=0 go build \
-ldflags "-X main.version=${VERSION}" \
-o ./bin/eth-faucet \
github.com/flashbots/eth-faucet/cmd

.PHONY: release-backend
release-backend:
@cd ./backend && goreleaser release --snapshot --clean

.PHONY: build-frontend
build-frontend:
@cd ./frontend && yarn install && yarn build

.PHONY: docker-compose
docker-compose:
@docker compose down --remove-orphans
@docker compose up --build
1 change: 1 addition & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!include: .gitignore
4 changes: 4 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/dist

/bin/*
!/bin/.gitkeep
21 changes: 21 additions & 0 deletions backend/.golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
run:
timeout: 5m
skip-dirs:
- .github
- web

linters-settings:
misspell:
locale: US

linters:
disable-all: true
enable:
- gosimple
- govet
- ineffassign
- goconst
- goimports
- revive
- unconvert
- unused
56 changes: 56 additions & 0 deletions backend/.goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
env:
- CGO_ENABLED=0

builds:
- main: ./cmd
ldflags:
- -s
- -w
- -X main.version={{ .Version }}
targets:
- linux_amd64
- linux_arm64

archives:
- id: zip
format: zip
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
files:
- none*

checksum:
name_template: 'checksums.txt'

release:
prerelease: auto

dockers:
- dockerfile: Dockerfile.goreleaser
goarch: amd64
goos: linux
use: buildx
build_flag_templates:
- --platform=linux/amd64
image_templates:
- "flashbots/eth-faucet-backend:{{ .Tag }}-amd64"
- "ghcr.io/flashbots/eth-faucet-backend:{{ .Tag }}-amd64"

- dockerfile: Dockerfile.goreleaser
goarch: arm64
goos: linux
use: buildx
build_flag_templates:
- --platform=linux/arm64
image_templates:
- "flashbots/eth-faucet-backend:{{ .Tag }}-arm64"
- "ghcr.io/flashbots/eth-faucet-backend:{{ .Tag }}-arm64"

docker_manifests:
- name_template: "flashbots/eth-faucet-backend:{{ .Tag }}"
image_templates:
- "flashbots/eth-faucet-backend:{{ .Tag }}-amd64"
- "flashbots/eth-faucet-backend:{{ .Tag }}-arm64"
- name_template: "ghcr.io/flashbots/eth-faucet-backend:{{ .Tag }}"
image_templates:
- "ghcr.io/flashbots/eth-faucet-backend:{{ .Tag }}-amd64"
- "ghcr.io/flashbots/eth-faucet-backend:{{ .Tag }}-arm64"
26 changes: 26 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# stage: build ---------------------------------------------------------

FROM golang:1.22-alpine as build

RUN apk add --no-cache gcc musl-dev linux-headers

WORKDIR /go/src/github.com/flashbots/eth-faucet

COPY go.* ./
RUN go mod download

COPY . .

RUN go build -o bin/eth-faucet -ldflags "-s -w" github.com/flashbots/eth-faucet/cmd

# stage: run -----------------------------------------------------------

FROM alpine

RUN apk add --no-cache ca-certificates

WORKDIR /app

COPY --from=build /go/src/github.com/flashbots/eth-faucet/bin/eth-faucet ./eth-faucet

ENTRYPOINT ["/app/eth-faucet"]
9 changes: 9 additions & 0 deletions backend/Dockerfile.goreleaser
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# stage: run

FROM gcr.io/distroless/static-debian12 as runner

WORKDIR /app

COPY eth-faucet ./

ENTRYPOINT [ "./eth-faucet" ]
102 changes: 102 additions & 0 deletions backend/backoff/backoff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package backoff

import (
"context"
"errors"
"fmt"
"slices"
"time"

"github.com/flashbots/eth-faucet/logutils"
"github.com/google/uuid"
"go.uber.org/zap"
)

var (
ErrBackoffContextError = errors.New("context error")
ErrBackoffDownstreamOperationCancelled = errors.New("downstream canceled the operation")
ErrBackoffFunctionalError = errors.New("functional error")
ErrBackoffNonRetryableError = errors.New("non-retryable error")
ErrBackoffTotalTimeoutExpired = errors.New("total timeout expired")
)

func Backoff(
ctx context.Context,
params *Parameters,
payload func(ctx context.Context) error,
) error {
params = WithDefaults(params)
deadline := time.Now().Add(params.TotalTimeout)

l := logutils.LoggerFromContext(ctx)
if l != nil {
l = l.With(zap.String(
"operation_uuid", uuid.Must(uuid.NewUUID()).String(),
))
ctx = logutils.ContextWithLogger(ctx, l)
}

errs := make([]error, 0)
attempt := 1
timeout := params.BaseTimeout

for time.Now().Before(deadline) {
start := time.Now()
if l != nil {
l.Debug("Running backoff-wrapped operation...",
zap.Duration("timeout", timeout),
zap.Int("attempt", attempt),
)
}

if timeout > params.MaximumTimeout {
timeout = params.MaximumTimeout
}
_ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

err := payload(_ctx)
ctxErr := _ctx.Err()

switch {
case err == nil && ctxErr == nil:
// happy path
return nil
case err != nil:
// error during execution
errs = append(errs, err)

// operation encountered non-retryable error
if !IsRetryable(err) {
slices.Reverse(errs)
return fmt.Errorf("%w: attempt %d: error log:\n%w",
ErrBackoffNonRetryableError, attempt,
errors.Join(errs...),
)
}
case ctxErr != nil:
// no execution error, but something wrong with context
errs = append(errs, ctxErr)

// downstream canceled the operation
if errors.Is(ctxErr, context.Canceled) {
slices.Reverse(errs)
return fmt.Errorf("%w: attempt %d: error log:\n%w",
ErrBackoffDownstreamOperationCancelled, attempt,
errors.Join(errs...),
)
}
}

time.Sleep(timeout - time.Since(start))

timeout = time.Duration(params.Multiplier * float64(timeout))
attempt++
}

slices.Reverse(errs)
return fmt.Errorf("%w: error log:\n%w",
ErrBackoffTotalTimeoutExpired,
errors.Join(errs...),
)
}
Loading

0 comments on commit 4135fdc

Please sign in to comment.