From 59a80d18fd1e1a96de9b7c02d6b2acf644a98cd5 Mon Sep 17 00:00:00 2001
From: 0xe3b0c4 <0xe3b0c4@proton.me>
Date: Fri, 5 Aug 2022 10:51:42 +0800
Subject: [PATCH] add static link flag, update upstream ci.go
---
Dockerfile | 55 ++++++++-
Dockerfile.alltools | 54 ++++++++-
build/ci.go | 266 ++++++++++++++++++++++++++++++++-----------
docker-entrypoint.sh | 15 +++
4 files changed, 315 insertions(+), 75 deletions(-)
create mode 100755 docker-entrypoint.sh
diff --git a/Dockerfile b/Dockerfile
index 437fb2737..d79359a13 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,59 @@
+# Support setting various labels on the final image
+ARG COMMIT=""
+ARG VERSION=""
+ARG BUILDNUM=""
+
# Build Geth in a stock Go builder container
-FROM golang:1.16-alpine as builder
+FROM golang:1.17-alpine as builder
-RUN apk add --no-cache make gcc musl-dev linux-headers git bash
+RUN apk add --no-cache make gcc musl-dev libc6-compat linux-headers git bash
ADD . /go-ethereum
-RUN cd /go-ethereum && make geth
+RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
# Pull Geth into a second stage deploy alpine container
-FROM alpine:latest
+FROM alpine:3.16
+
+ARG BSC_USER=bsc
+ARG BSC_USER_UID=1000
+ARG BSC_USER_GID=1000
+
+ENV BSC_HOME=/bsc
+ENV HOME=${BSC_HOME}
+ENV DATA_DIR=/data
+
+ENV PACKAGES ca-certificates jq \
+ bash bind-tools tini \
+ grep curl sed
+
+RUN apk add --no-cache $PACKAGES \
+ && rm -rf /var/cache/apk/* \
+ && addgroup -g ${BSC_USER_GID} ${BSC_USER} \
+ && adduser -u ${BSC_USER_UID} -G ${BSC_USER} --shell /bin/bash --no-create-home -D ${BSC_USER} \
+ && addgroup ${BSC_USER} tty
+
+WORKDIR ${BSC_HOME}
-RUN apk add --no-cache ca-certificates curl jq tini
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
+COPY docker-entrypoint.sh ./
+
+RUN chmod +x docker-entrypoint.sh \
+ && mkdir -p ${DATA_DIR} \
+ && chown -R ${BSC_USER_UID}:${BSC_USER_GID} ${BSC_HOME} ${DATA_DIR}
+
+VOLUME ${DATA_DIR}
+
+USER ${BSC_USER_UID}:${BSC_USER_GID}
+
+# rpc ws graphql
EXPOSE 8545 8546 8547 30303 30303/udp
-ENTRYPOINT ["geth"]
\ No newline at end of file
+
+# Add some metadata labels to help programatic image consumption
+ARG COMMIT=""
+ARG VERSION=""
+ARG BUILDNUM=""
+
+LABEL commit="$COMMIT" version="$VERSION" buildnum="$BUILDNUM"
+
+ENTRYPOINT ["/sbin/tini", "--", "./docker-entrypoint.sh"]
diff --git a/Dockerfile.alltools b/Dockerfile.alltools
index 483afad8c..6d31b71bc 100644
--- a/Dockerfile.alltools
+++ b/Dockerfile.alltools
@@ -1,15 +1,59 @@
+# Support setting various labels on the final image
+ARG COMMIT=""
+ARG VERSION=""
+ARG BUILDNUM=""
+
# Build Geth in a stock Go builder container
-FROM golang:1.16-alpine as builder
+FROM golang:1.17-alpine as builder
-RUN apk add --no-cache make gcc musl-dev linux-headers git
+RUN apk add --no-cache gcc musl-dev libc6-compat linux-headers git bash
ADD . /go-ethereum
-RUN cd /go-ethereum && make all
+RUN cd /go-ethereum && go run build/ci.go install -static
# Pull all binaries into a second stage deploy alpine container
-FROM alpine:latest
+FROM alpine:3.16
+
+ARG BSC_USER=bsc
+ARG BSC_USER_UID=1000
+ARG BSC_USER_GID=1000
+
+ENV BSC_HOME=/bsc
+ENV HOME=${BSC_HOME}
+ENV DATA_DIR=/data
+
+ENV PACKAGES ca-certificates jq \
+ bash bind-tools tini \
+ grep curl sed
+
+RUN apk add --no-cache $PACKAGES \
+ && rm -rf /var/cache/apk/* \
+ && addgroup -g ${BSC_USER_GID} ${BSC_USER} \
+ && adduser -u ${BSC_USER_UID} -G ${BSC_USER} --shell /bin/bash --no-create-home -D ${BSC_USER} \
+ && addgroup ${BSC_USER} tty
+
+WORKDIR ${BSC_HOME}
-RUN apk add --no-cache ca-certificates
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
+COPY docker-entrypoint.sh ./
+
+RUN chmod +x docker-entrypoint.sh \
+ && mkdir -p ${DATA_DIR} \
+ && chown -R ${BSC_USER_UID}:${BSC_USER_GID} ${BSC_HOME} ${DATA_DIR}
+
+VOLUME ${DATA_DIR}
+
+USER ${BSC_USER_UID}:${BSC_USER_GID}
+
+# rpc ws graphql
EXPOSE 8545 8546 30303 30303/udp
+
+# Add some metadata labels to help programatic image consumption
+ARG COMMIT=""
+ARG VERSION=""
+ARG BUILDNUM=""
+
+LABEL commit="$COMMIT" version="$VERSION" buildnum="$BUILDNUM"
+
+ENTRYPOINT ["/sbin/tini", "--", "./docker-entrypoint.sh"]
diff --git a/build/ci.go b/build/ci.go
index df1cb50ab..06701bd07 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
+//go:build none
// +build none
/*
@@ -32,7 +33,6 @@ Available commands are:
nsis -- creates a Windows NSIS installer
aar [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive
xcode [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework
- xgo [ -alltools ] [ options ] -- cross builds according to options
purge [ -store blobstore ] [ -days threshold ] -- purges old archives from the blobstore
For all commands, -n prevents execution of external programs (dry run mode).
@@ -54,6 +54,7 @@ import (
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"time"
@@ -128,19 +129,13 @@ var (
// Distros for which packages are created.
// Note: vivid is unsupported because there is no golang-1.6 package for it.
- // Note: wily is unsupported because it was officially deprecated on Launchpad.
- // Note: yakkety is unsupported because it was officially deprecated on Launchpad.
- // Note: zesty is unsupported because it was officially deprecated on Launchpad.
- // Note: artful is unsupported because it was officially deprecated on Launchpad.
- // Note: cosmic is unsupported because it was officially deprecated on Launchpad.
- // Note: disco is unsupported because it was officially deprecated on Launchpad.
- // Note: eoan is unsupported because it was officially deprecated on Launchpad.
+ // Note: the following Ubuntu releases have been officially deprecated on Launchpad:
+ // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy
debDistroGoBoots = map[string]string{
"trusty": "golang-1.11",
"xenial": "golang-go",
"bionic": "golang-go",
"focal": "golang-go",
- "groovy": "golang-go",
"hirsute": "golang-go",
}
@@ -152,7 +147,7 @@ var (
// This is the version of go that will be downloaded by
//
// go run ci.go install -dlgo
- dlgoVersion = "1.16.3"
+ dlgoVersion = "1.17.5"
)
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@@ -182,6 +177,8 @@ func main() {
doLint(os.Args[2:])
case "archive":
doArchive(os.Args[2:])
+ case "docker":
+ doDocker(os.Args[2:])
case "debsrc":
doDebianSource(os.Args[2:])
case "nsis":
@@ -190,8 +187,6 @@ func main() {
doAndroidArchive(os.Args[2:])
case "xcode":
doXCodeFramework(os.Args[2:])
- case "xgo":
- doXgo(os.Args[2:])
case "purge":
doPurge(os.Args[2:])
default:
@@ -203,9 +198,10 @@ func main() {
func doInstall(cmdline []string) {
var (
- dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
- arch = flag.String("arch", "", "Architecture to cross build for")
- cc = flag.String("cc", "", "C compiler to cross build with")
+ dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
+ arch = flag.String("arch", "", "Architecture to cross build for")
+ cc = flag.String("cc", "", "C compiler to cross build with")
+ staticlink = flag.Bool("static", false, "Static link build with")
)
flag.CommandLine.Parse(cmdline)
@@ -218,7 +214,7 @@ func doInstall(cmdline []string) {
// Configure the build.
env := build.Env()
- gobuild := tc.Go("build", buildFlags(env)...)
+ gobuild := tc.Go("build", buildFlags(env, *staticlink)...)
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
// better disable it. This check isn't the best, it should probably
@@ -251,7 +247,7 @@ func doInstall(cmdline []string) {
}
// buildFlags returns the go tool flags for building.
-func buildFlags(env build.Environment) (flags []string) {
+func buildFlags(env build.Environment, staticlink bool) (flags []string) {
var ld []string
if env.Commit != "" {
ld = append(ld, "-X", "main.gitCommit="+env.Commit)
@@ -262,6 +258,16 @@ func buildFlags(env build.Environment) (flags []string) {
if runtime.GOOS == "darwin" {
ld = append(ld, "-s")
}
+ // Enforce the stacksize to 8M, which is the case on most platforms apart from
+ // alpine Linux.
+ if runtime.GOOS == "linux" {
+ staticlinkflag := ""
+ if staticlink {
+ staticlinkflag = "-static"
+ }
+ ld = append(ld, "-extldflags", fmt.Sprintf("' -Wl,-z,stack-size=0x800000 %s'", staticlinkflag))
+ }
+
if len(ld) > 0 {
flags = append(flags, "-ldflags", strings.Join(ld, " "))
}
@@ -280,6 +286,7 @@ func doTest(cmdline []string) {
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
verbose = flag.Bool("v", false, "Whether to log verbosely")
timeout = flag.String("timeout", "10m", `Timeout of runing tests`)
+ race = flag.Bool("race", false, "Execute the race detector")
)
flag.CommandLine.Parse(cmdline)
@@ -303,6 +310,9 @@ func doTest(cmdline []string) {
if *timeout != "" {
gotest.Args = append(gotest.Args, []string{"-timeout", *timeout}...)
}
+ if *race {
+ gotest.Args = append(gotest.Args, "-race")
+ }
packages := []string{"./accounts/...", "./common/...", "./consensus/...", "./console/...", "./core/...",
"./crypto/...", "./eth/...", "./ethclient/...", "./ethdb/...", "./event/...", "./graphql/...", "./les/...",
@@ -334,10 +344,14 @@ func doLint(cmdline []string) {
// downloadLinter downloads and unpacks golangci-lint.
func downloadLinter(cachedir string) string {
- const version = "1.39.0"
+ const version = "1.42.0"
csdb := build.MustLoadChecksums("build/checksums.txt")
- base := fmt.Sprintf("golangci-lint-%s-%s-%s", version, runtime.GOOS, runtime.GOARCH)
+ arch := runtime.GOARCH
+ if arch == "arm" {
+ arch += "v" + os.Getenv("GOARM")
+ }
+ base := fmt.Sprintf("golangci-lint-%s-%s-%s", version, runtime.GOOS, arch)
url := fmt.Sprintf("https://github.com/golangci/golangci-lint/releases/download/v%s/%s.tar.gz", version, base)
archivePath := filepath.Join(cachedir, base+".tar.gz")
if err := csdb.DownloadFile(url, archivePath); err != nil {
@@ -454,11 +468,177 @@ func maybeSkipArchive(env build.Environment) {
os.Exit(0)
}
if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") {
- log.Printf("skipping archive creation because branch %q, tag %q is not on the whitelist", env.Branch, env.Tag)
+ log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag)
os.Exit(0)
}
}
+// Builds the docker images and optionally uploads them to Docker Hub.
+func doDocker(cmdline []string) {
+ var (
+ image = flag.Bool("image", false, `Whether to build and push an arch specific docker image`)
+ manifest = flag.String("manifest", "", `Push a multi-arch docker image for the specified architectures (usually "amd64,arm64")`)
+ upload = flag.String("upload", "", `Where to upload the docker image (usually "ethereum/client-go")`)
+ )
+ flag.CommandLine.Parse(cmdline)
+
+ // Skip building and pushing docker images for PR builds
+ env := build.Env()
+ maybeSkipArchive(env)
+
+ // Retrieve the upload credentials and authenticate
+ user := getenvBase64("DOCKER_HUB_USERNAME")
+ pass := getenvBase64("DOCKER_HUB_PASSWORD")
+
+ if len(user) > 0 && len(pass) > 0 {
+ auther := exec.Command("docker", "login", "-u", string(user), "--password-stdin")
+ auther.Stdin = bytes.NewReader(pass)
+ build.MustRun(auther)
+ }
+ // Retrieve the version infos to build and push to the following paths:
+ // - ethereum/client-go:latest - Pushes to the master branch, Geth only
+ // - ethereum/client-go:stable - Version tag publish on GitHub, Geth only
+ // - ethereum/client-go:alltools-latest - Pushes to the master branch, Geth & tools
+ // - ethereum/client-go:alltools-stable - Version tag publish on GitHub, Geth & tools
+ // - ethereum/client-go:release-. - Version tag publish on GitHub, Geth only
+ // - ethereum/client-go:alltools-release-. - Version tag publish on GitHub, Geth & tools
+ // - ethereum/client-go:v.. - Version tag publish on GitHub, Geth only
+ // - ethereum/client-go:alltools-v.. - Version tag publish on GitHub, Geth & tools
+ var tags []string
+
+ switch {
+ case env.Branch == "master":
+ tags = []string{"latest"}
+ case strings.HasPrefix(env.Tag, "v1."):
+ tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version}
+ }
+ // If architecture specific image builds are requested, build and push them
+ if *image {
+ build.MustRunCommand("docker", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", fmt.Sprintf("%s:TAG", *upload), ".")
+ build.MustRunCommand("docker", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", fmt.Sprintf("%s:alltools-TAG", *upload), "-f", "Dockerfile.alltools", ".")
+
+ // Tag and upload the images to Docker Hub
+ for _, tag := range tags {
+ gethImage := fmt.Sprintf("%s:%s-%s", *upload, tag, runtime.GOARCH)
+ toolImage := fmt.Sprintf("%s:alltools-%s-%s", *upload, tag, runtime.GOARCH)
+
+ // If the image already exists (non version tag), check the build
+ // number to prevent overwriting a newer commit if concurrent builds
+ // are running. This is still a tiny bit racey if two published are
+ // done at the same time, but that's extremely unlikely even on the
+ // master branch.
+ for _, img := range []string{gethImage, toolImage} {
+ if exec.Command("docker", "pull", img).Run() != nil {
+ continue // Generally the only failure is a missing image, which is good
+ }
+ buildnum, err := exec.Command("docker", "inspect", "--format", "{{index .Config.Labels \"buildnum\"}}", img).CombinedOutput()
+ if err != nil {
+ log.Fatalf("Failed to inspect container: %v\nOutput: %s", err, string(buildnum))
+ }
+ buildnum = bytes.TrimSpace(buildnum)
+
+ if len(buildnum) > 0 && len(env.Buildnum) > 0 {
+ oldnum, err := strconv.Atoi(string(buildnum))
+ if err != nil {
+ log.Fatalf("Failed to parse old image build number: %v", err)
+ }
+ newnum, err := strconv.Atoi(env.Buildnum)
+ if err != nil {
+ log.Fatalf("Failed to parse current build number: %v", err)
+ }
+ if oldnum > newnum {
+ log.Fatalf("Current build number %d not newer than existing %d", newnum, oldnum)
+ } else {
+ log.Printf("Updating %s from build %d to %d", img, oldnum, newnum)
+ }
+ }
+ }
+ build.MustRunCommand("docker", "image", "tag", fmt.Sprintf("%s:TAG", *upload), gethImage)
+ build.MustRunCommand("docker", "image", "tag", fmt.Sprintf("%s:alltools-TAG", *upload), toolImage)
+ build.MustRunCommand("docker", "push", gethImage)
+ build.MustRunCommand("docker", "push", toolImage)
+ }
+ }
+ // If multi-arch image manifest push is requested, assemble it
+ if len(*manifest) != 0 {
+ // Since different architectures are pushed by different builders, wait
+ // until all required images are updated.
+ var mismatch bool
+ for i := 0; i < 2; i++ { // 2 attempts, second is race check
+ mismatch = false // hope there's no mismatch now
+
+ for _, tag := range tags {
+ for _, arch := range strings.Split(*manifest, ",") {
+ gethImage := fmt.Sprintf("%s:%s-%s", *upload, tag, arch)
+ toolImage := fmt.Sprintf("%s:alltools-%s-%s", *upload, tag, arch)
+
+ for _, img := range []string{gethImage, toolImage} {
+ if out, err := exec.Command("docker", "pull", img).CombinedOutput(); err != nil {
+ log.Printf("Required image %s unavailable: %v\nOutput: %s", img, err, out)
+ mismatch = true
+ break
+ }
+ buildnum, err := exec.Command("docker", "inspect", "--format", "{{index .Config.Labels \"buildnum\"}}", img).CombinedOutput()
+ if err != nil {
+ log.Fatalf("Failed to inspect container: %v\nOutput: %s", err, string(buildnum))
+ }
+ buildnum = bytes.TrimSpace(buildnum)
+
+ if string(buildnum) != env.Buildnum {
+ log.Printf("Build number mismatch on %s: want %s, have %s", img, env.Buildnum, buildnum)
+ mismatch = true
+ break
+ }
+ }
+ if mismatch {
+ break
+ }
+ }
+ if mismatch {
+ break
+ }
+ }
+ if mismatch {
+ // Build numbers mismatching, retry in a short time to
+ // avoid concurrent failes in both publisher images. If
+ // however the retry failed too, it means the concurrent
+ // builder is still crunching, let that do the publish.
+ if i == 0 {
+ time.Sleep(30 * time.Second)
+ }
+ continue
+ }
+ break
+ }
+ if mismatch {
+ log.Println("Relinquishing publish to other builder")
+ return
+ }
+ // Assemble and push the Geth manifest image
+ for _, tag := range tags {
+ gethImage := fmt.Sprintf("%s:%s", *upload, tag)
+
+ var gethSubImages []string
+ for _, arch := range strings.Split(*manifest, ",") {
+ gethSubImages = append(gethSubImages, gethImage+"-"+arch)
+ }
+ build.MustRunCommand("docker", append([]string{"manifest", "create", gethImage}, gethSubImages...)...)
+ build.MustRunCommand("docker", "manifest", "push", gethImage)
+ }
+ // Assemble and push the alltools manifest image
+ for _, tag := range tags {
+ toolImage := fmt.Sprintf("%s:alltools-%s", *upload, tag)
+
+ var toolSubImages []string
+ for _, arch := range strings.Split(*manifest, ",") {
+ toolSubImages = append(toolSubImages, toolImage+"-"+arch)
+ }
+ build.MustRunCommand("docker", append([]string{"manifest", "create", toolImage}, toolSubImages...)...)
+ build.MustRunCommand("docker", "manifest", "push", toolImage)
+ }
+ }
+}
+
// Debian Packaging
func doDebianSource(cmdline []string) {
var (
@@ -782,10 +962,10 @@ func doWindowsInstaller(cmdline []string) {
build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil)
build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil)
if err := cp.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll"); err != nil {
- log.Fatal("Failed to copy SimpleFC.dll: %v", err)
+ log.Fatalf("Failed to copy SimpleFC.dll: %v", err)
}
if err := cp.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING"); err != nil {
- log.Fatal("Failed to copy copyright note: %v", err)
+ log.Fatalf("Failed to copy copyright note: %v", err)
}
// Build the installer. This assumes that all the needed files have been previously
// built (don't mix building and packaging to keep cross compilation complexity to a
@@ -1043,48 +1223,6 @@ func newPodMetadata(env build.Environment, archive string) podMetadata {
}
}
-// Cross compilation
-
-func doXgo(cmdline []string) {
- var (
- alltools = flag.Bool("alltools", false, `Flag whether we're building all known tools, or only on in particular`)
- )
- flag.CommandLine.Parse(cmdline)
- env := build.Env()
- var tc build.GoToolchain
-
- // Make sure xgo is available for cross compilation
- build.MustRun(tc.Install(GOBIN, "github.com/karalabe/xgo@latest"))
-
- // If all tools building is requested, build everything the builder wants
- args := append(buildFlags(env), flag.Args()...)
-
- if *alltools {
- args = append(args, []string{"--dest", GOBIN}...)
- for _, res := range allToolsArchiveFiles {
- if strings.HasPrefix(res, GOBIN) {
- // Binary tool found, cross build it explicitly
- args = append(args, "./"+filepath.Join("cmd", filepath.Base(res)))
- build.MustRun(xgoTool(args))
- args = args[:len(args)-1]
- }
- }
- return
- }
-
- // Otherwise execute the explicit cross compilation
- path := args[len(args)-1]
- args = append(args[:len(args)-1], []string{"--dest", GOBIN, path}...)
- build.MustRun(xgoTool(args))
-}
-
-func xgoTool(args []string) *exec.Cmd {
- cmd := exec.Command(filepath.Join(GOBIN, "xgo"), args...)
- cmd.Env = os.Environ()
- cmd.Env = append(cmd.Env, []string{"GOBIN=" + GOBIN}...)
- return cmd
-}
-
// Binary distribution cleanups
func doPurge(cmdline []string) {
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
new file mode 100755
index 000000000..7e8dda87d
--- /dev/null
+++ b/docker-entrypoint.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -e
+
+BSC_CONFIG=${BSC_HOME}/config/config.toml
+BSC_GENESIS=${BSC_HOME}/config/genesis.json
+
+# Init genesis state if geth not exist
+DATA_DIR=$(cat ${BSC_CONFIG} | grep -A1 '\[Node\]' | grep -oP '\"\K.*?(?=\")')
+
+GETH_DIR=${DATA_DIR}/geth
+if [ ! -d "$GETH_DIR" ]; then
+ geth --datadir ${DATA_DIR} init ${BSC_GENESIS}
+fi
+
+exec "geth" "--config" ${BSC_CONFIG} "$@"