diff --git a/.gitignore b/.gitignore
index 1a85f2f558a2..3ee7e66bfe84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ build/_vendor/pkg
# used by the Makefile
/build/_workspace/
+/build/cache/
/build/bin/
/XDC*.zip
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 000000000000..3f8fb3078236
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,79 @@
+# This file configures github.com/golangci/golangci-lint.
+
+run:
+ timeout: 20m
+ tests: true
+
+linters:
+ disable-all: true
+ enable:
+ - goimports
+ - gosimple
+ - govet
+ - ineffassign
+ - misspell
+ - unconvert
+ - typecheck
+ - unused
+ - staticcheck
+ - bidichk
+ - durationcheck
+ - copyloopvar
+ - whitespace
+ - revive # only certain checks enabled
+ - durationcheck
+ - gocheckcompilerdirectives
+ - reassign
+ - mirror
+ - tenv
+ ### linters we tried and will not be using:
+ ###
+ # - structcheck # lots of false positives
+ # - errcheck #lot of false positives
+ # - contextcheck
+ # - errchkjson # lots of false positives
+ # - errorlint # this check crashes
+ # - exhaustive # silly check
+ # - makezero # false positives
+ # - nilerr # several intentional
+
+linters-settings:
+ gofmt:
+ simplify: true
+ revive:
+ enable-all-rules: false
+ # here we enable specific useful rules
+ # see https://golangci-lint.run/usage/linters/#revive for supported rules
+ rules:
+ - name: receiver-naming
+ severity: warning
+ disabled: false
+ exclude: [""]
+
+issues:
+ # default is true. Enables skipping of directories:
+ # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
+ exclude-dirs-use-default: true
+ exclude-files:
+ - core/genesis_alloc.go
+ exclude-rules:
+ - path: crypto/bn256/cloudflare/optate.go
+ linters:
+ - deadcode
+ - staticcheck
+ - path: crypto/bn256/
+ linters:
+ - revive
+ - path: cmd/utils/flags.go
+ text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
+ - path: cmd/utils/flags.go
+ text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
+ - path: internal/build/pgp.go
+ text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
+ - path: core/vm/contracts.go
+ text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.'
+ exclude:
+ - 'SA1019: event.TypeMux is deprecated: use Feed'
+ - 'SA1019: strings.Title is deprecated'
+ - 'SA1019: strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.'
+ - 'SA1029: should not use built-in type string as key for value'
diff --git a/Makefile b/Makefile
index 3bd726906ce2..e92835b952a0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,7 @@
+# This Makefile is meant to be used by people that do not usually work
+# with Go source code. If you know what GOPATH is then you probably
+# don't need to bother with make.
+
.PHONY: XDC XDC-cross evm all test clean
.PHONY: XDC-linux XDC-linux-386 XDC-linux-amd64 XDC-linux-mips64 XDC-linux-mips64le
.PHONY: XDC-darwin XDC-darwin-386 XDC-darwin-amd64
@@ -5,11 +9,12 @@
GOBIN = $(shell pwd)/build/bin
GOFMT = gofmt
GO ?= 1.22.10
+GORUN = go run
GO_PACKAGES = .
GO_FILES := $(shell find $(shell go list -f '{{.Dir}}' $(GO_PACKAGES)) -name \*.go)
-
GIT = git
+#? XDC: Build XDC.
XDC:
go run build/ci.go install ./cmd/XDC
@echo "Done building."
@@ -41,15 +46,26 @@ puppeth:
@echo "Done building."
@echo "Run \"$(GOBIN)/puppeth\" to launch puppeth."
+#? all: Build all packages and executables.
all:
go run build/ci.go install
+#? test: Run the tests.
test: all
go run build/ci.go test
+#? lint: Run certain pre-selected linters.
+lint: ## Run linters.
+ $(GORUN) build/ci.go lint
+
+#? clean: Clean go cache, built executables, and the auto generated folder.
clean:
rm -fr build/_workspace/pkg/ $(GOBIN)/*
+#? fmt: Ensure consistent code formatting.
+fmt:
+ gofmt -s -w $(shell find . -name "*.go")
+
# Cross Compilation Targets (xgo)
XDC-cross: XDC-windows-amd64 XDC-darwin-amd64 XDC-linux
diff --git a/build/checksums.txt b/build/checksums.txt
new file mode 100644
index 000000000000..1484e6499f65
--- /dev/null
+++ b/build/checksums.txt
@@ -0,0 +1,126 @@
+# This file contains sha256 checksums of optional build dependencies.
+
+# version:spec-tests 2.1.0
+# https://github.com/ethereum/execution-spec-tests/releases
+# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
+ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
+
+# version:golang 1.22.10
+# https://go.dev/dl/
+1e94fd48be750d1fafb4d9b3b6dd31a6e9d2735d339bf2462bc97b64ca4c1037 go1.22.10.src.tar.gz
+dd2c4ac3702658c2c20e3a8b394da1917d86156b2cb4312c9d2f657f80067874 go1.22.10.darwin-amd64.tar.gz
+9d37bf96bbdd1669f1ab771c98ac7695f1b49df3c5c2bf10b699950f0fc2f52b go1.22.10.darwin-amd64.pkg
+21cf49415ffe0755b45f2b63e75d136528a32f7bb7bdd0166f51d22a03eb0a3f go1.22.10.darwin-arm64.tar.gz
+746558a1e677a469b297ed885d94d0cdc3410d2153f49f0109c833f5283e1ad1 go1.22.10.darwin-arm64.pkg
+2ae9f00e9621489b75494fa2b8abfc5d09e0cae6effdd4c13867957ad2e4deba go1.22.10.linux-386.tar.gz
+736ce492a19d756a92719a6121226087ccd91b652ed5caec40ad6dbfb2252092 go1.22.10.linux-amd64.tar.gz
+5213c5e32fde3bd7da65516467b7ffbfe40d2bb5a5f58105e387eef450583eec go1.22.10.linux-arm64.tar.gz
+a7bbbc80fe736269820bbdf3555e91ada5d18a5cde2276aac3b559bc1d52fc70 go1.22.10.linux-armv6l.tar.gz
+20019b2e60dd0cdf63e4ec26852c1c015c1a27580b32a512b4be33a2539113ae go1.22.10.windows-386.zip
+d6f7c00af6d54f09bf5b137cda0b34f75b1ac6fb95abe5a948240110f99d8fad go1.22.10.windows-386.msi
+da66f107a0f4959f4615bede230c6bf145a6f01252c6d1ff2b107e293ba339df go1.22.10.windows-amd64.zip
+454c45de32d325f175dc9ccd262944aec0d24b12c47a8f6d4000adad9f271adc go1.22.10.windows-amd64.msi
+46af3f2506a8887ed1de0e38244730a2ba944cfed7804d6baa9773790d2a294d go1.22.10.aix-ppc64.tar.gz
+1684ae4c10c4d30e6f4950fbb71d9cc096d0541e5cf769b3195e91f475249d9a go1.22.10.dragonfly-amd64.tar.gz
+f82f5d194114963693e0f51fd56d55d8417ca556438062f2b0df608473b62837 go1.22.10.freebsd-386.tar.gz
+cce9da240870a4430c5cf1227bcf29d37575043ff16f7982a69f1139c6f564b5 go1.22.10.freebsd-amd64.tar.gz
+abae388d0d42563a242db0d405172cb73e09236f68000ff90c2a327ec8c5764c go1.22.10.freebsd-arm64.tar.gz
+7c9c8fe30cbabbb4fb597f0f0ad1279fd2b320bc70831eba4c207b55ad46931d go1.22.10.freebsd-arm.tar.gz
+d6f25fd79e17b84d1b61bec3e2fdffc47377b28b51a04b6bdbeac0199313e059 go1.22.10.freebsd-riscv64.tar.gz
+4a1121d8331208cb614c6f0474b0e4fa3c3023c5e8a88fb8d37f7e3454589aa2 go1.22.10.illumos-amd64.tar.gz
+0be34dbc69726b52414e0283736f997fee477379ebff66cebd7d8c35f4f64f9d go1.22.10.linux-loong64.tar.gz
+bb7d7e99db7ee70063cb57bb7395c392b8b5ed87f37d733a1c91de935c70bb91 go1.22.10.linux-mips.tar.gz
+c7f0571410297cb29e52d10fed7a2a21aeaeabb9539d0c04a6d778adf0fe7f1b go1.22.10.linux-mips64.tar.gz
+e66c440c03dd19bf8423034cbde7f6813321beb18d3fcf2ef234c13a25467952 go1.22.10.linux-mips64le.tar.gz
+b4e0061f62a9c1f874893aa4951a4883c19762a9dd64c5710554ec5a7aaf311a go1.22.10.linux-mipsle.tar.gz
+4192158cdedc6a124aa32a099cc6bebebabf1f4d380c46c5e36ea52c30a3888b go1.22.10.linux-ppc64.tar.gz
+db05b9838f69d741fb9a5301220b1a62014aee025b0baf341aba3d280087b981 go1.22.10.linux-ppc64le.tar.gz
+aef9b186c1b9b58c0472dbf54978f97682852a91b2e8d6bf354e59ba9c24438a go1.22.10.linux-riscv64.tar.gz
+4ab2286adb096576771801b5099760b1d625fd7b44080449151a4d9b21303672 go1.22.10.linux-s390x.tar.gz
+32e66f6ae2082cce98ccb557f54965ae5452e1b705470ae403446062938db1d5 go1.22.10.netbsd-386.tar.gz
+e876962e6032175d049259559978c10af578dce506ffb064ce61e60a5b5308cb go1.22.10.netbsd-amd64.tar.gz
+b95696f92afe5062d4e17c48cf0756699a7522fbfd1b034bfb1eb2b636d34163 go1.22.10.netbsd-arm64.tar.gz
+9d5e08939b95dca7d102eae7a832813ee12337187786f548848b10503ddc80cc go1.22.10.netbsd-arm.tar.gz
+5c4294fed0bf981f81b8be979e955516d0a78019990f2f7462246ef4bb3960e5 go1.22.10.openbsd-386.tar.gz
+c72b4d4f4cedce007e4d52a0e496169b0739b3bbe7fa13bc1322fe3b79d55221 go1.22.10.openbsd-amd64.tar.gz
+1a90e0fb2e6ca881b78692594f0e29834f738c593ea627a631f8e81cdddfdc32 go1.22.10.openbsd-arm64.tar.gz
+f6153ebd844ccc21ec8420fecccf9214dc0a7a572b28234ec1e00e04b0f438bb go1.22.10.openbsd-arm.tar.gz
+5fe1abee2805334404da9c4e2aedb93764b31d6de3fe9d3cb49a2fd844992f68 go1.22.10.openbsd-ppc64.tar.gz
+834fe42edf63a67b7b6c57fcfd1e8b159842f3615bfbc975b5ceed994db7e834 go1.22.10.plan9-386.tar.gz
+9fa2282fccb668ef9e3cdb1fa3f0128994224f95267f54640779049df3bb3a6c go1.22.10.plan9-amd64.tar.gz
+d66acc86e00ead41966bb599c26fda983a686232040996a307262e71b3576c48 go1.22.10.plan9-arm.tar.gz
+40779a36f3f78b2ac1f3da5e6336f4fa24996d2412d5ca5685077103c8d3bbe2 go1.22.10.solaris-amd64.tar.gz
+974656452fd7d104f34ee6e8ac92bb7431af84a1ce55226d9af485cb9ec23dd5 go1.22.10.windows-arm64.zip
+f62491c8bbc811ddbdd25ee34af5bbd200f3d6086c1a3ebb64e435ce3b346a97 go1.22.10.windows-arm64.msi
+de1fb78d98ebd054a6fce5b71d1dcd1d49a68db75e0b6fd3d98ae5818d81fdba go1.22.10.windows-arm.zip
+5523272bb157db06311a907289c92caf59347d4b6721d407486256e61c593dc9 go1.22.10.windows-arm.msi
+
+# version:golangci 1.63.4
+# https://github.com/golangci/golangci-lint/releases/
+# https://github.com/golangci/golangci-lint/releases/download/v1.63.4/
+878d017cc360e4fb19510d39852c8189852e3c48e7ce0337577df73507c97d68 golangci-lint-1.63.4-darwin-amd64.tar.gz
+a2b630c2ac8466393f0ccbbede4462387b6c190697a70bc2298c6d2123f21bbf golangci-lint-1.63.4-darwin-arm64.tar.gz
+8938b74aa92888e561a1c5a4c175110b92f84e7d24733703e6d9ebc39e9cd5f8 golangci-lint-1.63.4-freebsd-386.tar.gz
+054903339d620df2e760b978920100986e3b03bcb058f669d520a71dac9c34ed golangci-lint-1.63.4-freebsd-amd64.tar.gz
+a19d499f961a02608348e8b626537a88edfaab6e1b6534f1eff742b5d6d750e4 golangci-lint-1.63.4-freebsd-armv6.tar.gz
+00d616f0fb275b780ce4d26604bdd7fdbfe6bc9c63acd5a0b31498e1f7511108 golangci-lint-1.63.4-freebsd-armv7.tar.gz
+d453688e0eabded3c1a97ff5a2777bb0df5a18851efdaaaf6b472e3e5713c33e golangci-lint-1.63.4-illumos-amd64.tar.gz
+6b1bec847fc9f347d53712d05606a49d55d0e3b5c1bacadfed2393f3503de0e9 golangci-lint-1.63.4-linux-386.tar.gz
+01abb14a4df47b5ca585eff3c34b105023cba92ec34ff17212dbb83855581690 golangci-lint-1.63.4-linux-amd64.tar.gz
+51f0c79d19a92353e0465fb30a4901a0644a975d34e6f399ad2eebc0160bbb24 golangci-lint-1.63.4-linux-arm64.tar.gz
+8d0a43f41e8424fbae10f7aa2dc29999f98112817c6dba63d7dc76832940a673 golangci-lint-1.63.4-linux-armv6.tar.gz
+1045a047b31e9302c9160c7b0f199f4ac1bd02a1b221a2d9521bd3507f0cf671 golangci-lint-1.63.4-linux-armv7.tar.gz
+933fe10ab50ce3bb0806e15a4ae69fe20f0549abf91dea0161236000ca706e67 golangci-lint-1.63.4-linux-loong64.tar.gz
+45798630cbad5642862766051199fa862ef3c33d569cab12f01cac4f68e2ddd5 golangci-lint-1.63.4-linux-mips64.tar.gz
+86ae25335ddb24975d2c915c1af0c7fad70dce99d0b4614fa4bee392de714aa2 golangci-lint-1.63.4-linux-mips64le.tar.gz
+33dabd11aaba4b602938da98bcf49aabab55019557e0115cdc3dbcc3009768fa golangci-lint-1.63.4-linux-ppc64le.tar.gz
+4e7a81230a663bcdf30bba5689ce96040abc76994dbc2003dce32c8dca8c06f3 golangci-lint-1.63.4-linux-riscv64.tar.gz
+21370b49c7c47f4d9b8f982c952f940b01e65710174c3b4dad7b6452d58f92ec golangci-lint-1.63.4-linux-s390x.tar.gz
+255866a6464c7e11bb7edd8e6e6ad54f11e1f01b82ba9ca229698ac788cd9724 golangci-lint-1.63.4-netbsd-386.tar.gz
+2798c040ac658bda97224f204795199c81ac97bb207b21c02b664aaed380d5d2 golangci-lint-1.63.4-netbsd-amd64.tar.gz
+b910eecffd0064103837e7e1abe870deb8ade22331e6dffe319f430d49399c8e golangci-lint-1.63.4-netbsd-arm64.tar.gz
+df2693ef37147b457c3e2089614537dd2ae2e18e53641e756a5b404f4c72d3fa golangci-lint-1.63.4-netbsd-armv6.tar.gz
+a28a533366974bd7834c4516cd6075bff3419a508d1ed7aa63ae8182768b352e golangci-lint-1.63.4-netbsd-armv7.tar.gz
+368932775fb5c620b324dabf018155f3365f5e33c5af5b26e9321db373f96eea golangci-lint-1.63.4-windows-386.zip
+184d13c2b8f5441576bec2a0d8ba7b2d45445595cf796b879a73bcc98c39f8c1 golangci-lint-1.63.4-windows-amd64.zip
+4fabf175d5b05ef0858ded49527948eebac50e9093814979fd84555a75fb80a6 golangci-lint-1.63.4-windows-arm64.zip
+e92be3f3ff30d4a849fb4b9a4c8d56837dee45269cb405a3ecad52fa034c781b golangci-lint-1.63.4-windows-armv6.zip
+c71d348653b8f7fbb109bb10c1a481722bc6b0b2b6e731b897f99ac869f7653e golangci-lint-1.63.4-windows-armv7.zip
+
+# This is the builder on PPA that will build Go itself (inception-y), don't modify!
+#
+# This version is fine to be old and full of security holes, we just use it
+# to build the latest Go. Don't change it.
+#
+# version:ppa-builder-1 1.19.6
+# https://go.dev/dl/
+d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
+
+# version:ppa-builder-2 1.21.9
+# https://go.dev/dl/
+58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz
+
+# version:protoc 27.1
+# https://github.com/protocolbuffers/protobuf/releases/
+# https://github.com/protocolbuffers/protobuf/releases/download/v27.1/
+8809c2ec85368c6b6e9af161b6771a153aa92670a24adbe46dd34fa02a04df2f protoc-27.1-linux-aarch_64.zip
+5d21979a6d27475e810b76b88863d1e784fa01ffb15e511a3ec5bd1924d89426 protoc-27.1-linux-ppcle_64.zip
+84d8852750ed186dc4a057a1a86bcac409be5362d6af04770f42367fee6b7bc1 protoc-27.1-linux-s390_64.zip
+2f028796ff5741691650e0eea290e61ff2f1c0d87f8d31fe45ef47fd967cef0c protoc-27.1-linux-x86_32.zip
+8970e3d8bbd67d53768fe8c2e3971bdd71e51cfe2001ca06dacad17258a7dae3 protoc-27.1-linux-x86_64.zip
+03b7af1bf469e7285dc51976ee5fa99412704dbd1c017105114852a37b165c12 protoc-27.1-osx-aarch_64.zip
+f14d3973cf13283d07c520ed6f4c12405ad41b9efd18089a1c74897037d742b5 protoc-27.1-osx-universal_binary.zip
+8520d944f3a3890fa296a3b3b0d4bb18337337e2526bbbf1b507eeea3c2a1ec4 protoc-27.1-osx-x86_64.zip
+6263718ff96547b8392a079f6fdf02a4156f2e8d13cd51649a0d03fb7afa2de8 protoc-27.1-win32.zip
+da531c51ccd1290d8d34821f0ce4e219c7fbaa6f9825f5a3fb092a9d03fe6206 protoc-27.1-win64.zip
+
+# version:protoc-gen-go 1.34.2
+# https://github.com/protocolbuffers/protobuf-go/releases/
+# https://github.com/protocolbuffers/protobuf-go/releases/download/v1.34.2/
+9b48d8f90add02e8e94e14962fed74e7ce2b2d6bda4dd42f1f4fbccf0f766f1a protoc-gen-go.v1.34.2.darwin.amd64.tar.gz
+17aca7f948dbb624049030cf841e35895cf34183ba006e721247fdeb95ff2780 protoc-gen-go.v1.34.2.darwin.arm64.tar.gz
+a191849433fd489f1d44f37788d762658f3f5fb225f3a85d4ce6ba32666703ed protoc-gen-go.v1.34.2.linux.386.tar.gz
+b87bc134dee55576a842141bf0ed27761c635d746780fce5dee038c6dd16554f protoc-gen-go.v1.34.2.linux.amd64.tar.gz
+63d400167e75ab9f6690688f6fdc6a9455aa20bc1faa71e32149dbd322f7f198 protoc-gen-go.v1.34.2.linux.arm64.tar.gz
+56e7675816db6e62be4f833a51544d5716b8420c462515579e05ca8444ab06ed protoc-gen-go.v1.34.2.windows.386.zip
+abafd39612177dd4e9a65207cadd5374a9352d8611e8e040f8462fcfa3010daf protoc-gen-go.v1.34.2.windows.amd64.zip
diff --git a/build/ci.go b/build/ci.go
index ff3ea89d10f6..3bdb52a7a32e 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -246,37 +246,52 @@ func doTest(cmdline []string) {
build.MustRun(gotest)
}
+// doLint runs golangci-lint on requested packages.
func doLint(cmdline []string) {
+ var (
+ cachedir = flag.String("cachedir", "./build/cache", "directory for caching golangci-lint binary.")
+ )
flag.CommandLine.Parse(cmdline)
-
packages := []string{"./..."}
if len(flag.CommandLine.Args()) > 0 {
packages = flag.CommandLine.Args()
}
- // Get golangci-lint and install all supported linters
- build.MustRun(goTool("get", "github.com/golangci/golangci-lint/cmd/golangci-lint@v1.18.0"))
-
- // Run fast linters batched together
- configs := []string{
- "run",
- "--disable-all",
- "--enable=vet",
- "--enable=gofmt",
- "--enable=misspell",
- "--enable=goconst",
- "--min-occurrences=6", // for goconst
+
+ linter := downloadLinter(*cachedir)
+ lflags := []string{"run", "--config", ".golangci.yml"}
+ build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
+ fmt.Println("You have achieved perfection.")
+}
+
+// downloadLinter downloads and unpacks golangci-lint.
+func downloadLinter(cachedir string) string {
+ csdb := build.MustLoadChecksums("build/checksums.txt")
+ version, err := build.Version(csdb, "golangci")
+ if err != nil {
+ log.Fatal(err)
}
- build.MustRunCommand(filepath.Join(GOBIN, "golangci-lint"), append(configs, packages...)...)
+ arch := runtime.GOARCH
+ ext := ".tar.gz"
- // Run slow linters one by one
- for _, linter := range []string{"unconvert", "gosimple"} {
- configs = []string{"--vendor", "--deadline=10m", "--disable-all", "--enable=" + linter}
- build.MustRunCommand(filepath.Join(GOBIN, "golangci-lint"), append(configs, packages...)...)
+ if runtime.GOOS == "windows" {
+ ext = ".zip"
+ }
+ 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%s", version, base, ext)
+ archivePath := filepath.Join(cachedir, base+ext)
+ if err := csdb.DownloadFile(url, archivePath); err != nil {
+ log.Fatal(err)
}
+ if err := build.ExtractArchive(archivePath, cachedir); err != nil {
+ log.Fatal(err)
+ }
+ return filepath.Join(cachedir, base, "golangci-lint")
}
// 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`)
diff --git a/go.mod b/go.mod
index 3b58b4c90cdc..9b6faf749c1b 100644
--- a/go.mod
+++ b/go.mod
@@ -2,6 +2,8 @@ module github.com/XinFinOrg/XDPoSChain
go 1.22
+toolchain go1.22.0
+
require (
github.com/VictoriaMetrics/fastcache v1.12.2
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6
diff --git a/internal/build/archive.go b/internal/build/archive.go
new file mode 100644
index 000000000000..645921c690a7
--- /dev/null
+++ b/internal/build/archive.go
@@ -0,0 +1,296 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package build
+
+import (
+ "archive/tar"
+ "archive/zip"
+ "compress/gzip"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+type Archive interface {
+ // Directory adds a new directory entry to the archive and sets the
+ // directory for subsequent calls to Header.
+ Directory(name string) error
+
+ // Header adds a new file to the archive. The file is added to the directory
+ // set by Directory. The content of the file must be written to the returned
+ // writer.
+ Header(os.FileInfo) (io.Writer, error)
+
+ // Close flushes the archive and closes the underlying file.
+ Close() error
+}
+
+func NewArchive(file *os.File) (Archive, string) {
+ switch {
+ case strings.HasSuffix(file.Name(), ".zip"):
+ return NewZipArchive(file), strings.TrimSuffix(file.Name(), ".zip")
+ case strings.HasSuffix(file.Name(), ".tar.gz"):
+ return NewTarballArchive(file), strings.TrimSuffix(file.Name(), ".tar.gz")
+ default:
+ return nil, ""
+ }
+}
+
+// AddFile appends an existing file to an archive.
+func AddFile(a Archive, file string) error {
+ fd, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+ fi, err := fd.Stat()
+ if err != nil {
+ return err
+ }
+ w, err := a.Header(fi)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(w, fd); err != nil {
+ return err
+ }
+ return nil
+}
+
+// WriteArchive creates an archive containing the given files.
+func WriteArchive(name string, files []string) (err error) {
+ archfd, err := os.Create(name)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ archfd.Close()
+ // Remove the half-written archive on failure.
+ if err != nil {
+ os.Remove(name)
+ }
+ }()
+ archive, basename := NewArchive(archfd)
+ if archive == nil {
+ return errors.New("unknown archive extension")
+ }
+ fmt.Println(name)
+ if err := archive.Directory(basename); err != nil {
+ return err
+ }
+ for _, file := range files {
+ fmt.Println(" +", filepath.Base(file))
+ if err := AddFile(archive, file); err != nil {
+ return err
+ }
+ }
+ return archive.Close()
+}
+
+type ZipArchive struct {
+ dir string
+ zipw *zip.Writer
+ file io.Closer
+}
+
+func NewZipArchive(w io.WriteCloser) Archive {
+ return &ZipArchive{"", zip.NewWriter(w), w}
+}
+
+func (a *ZipArchive) Directory(name string) error {
+ a.dir = name + "/"
+ return nil
+}
+
+func (a *ZipArchive) Header(fi os.FileInfo) (io.Writer, error) {
+ head, err := zip.FileInfoHeader(fi)
+ if err != nil {
+ return nil, fmt.Errorf("can't make zip header: %v", err)
+ }
+ head.Name = a.dir + head.Name
+ head.Method = zip.Deflate
+ w, err := a.zipw.CreateHeader(head)
+ if err != nil {
+ return nil, fmt.Errorf("can't add zip header: %v", err)
+ }
+ return w, nil
+}
+
+func (a *ZipArchive) Close() error {
+ if err := a.zipw.Close(); err != nil {
+ return err
+ }
+ return a.file.Close()
+}
+
+type TarballArchive struct {
+ dir string
+ tarw *tar.Writer
+ gzw *gzip.Writer
+ file io.Closer
+}
+
+func NewTarballArchive(w io.WriteCloser) Archive {
+ gzw := gzip.NewWriter(w)
+ tarw := tar.NewWriter(gzw)
+ return &TarballArchive{"", tarw, gzw, w}
+}
+
+func (a *TarballArchive) Directory(name string) error {
+ a.dir = name + "/"
+ return a.tarw.WriteHeader(&tar.Header{
+ Name: a.dir,
+ Mode: 0755,
+ Typeflag: tar.TypeDir,
+ ModTime: time.Now(),
+ })
+}
+
+func (a *TarballArchive) Header(fi os.FileInfo) (io.Writer, error) {
+ head, err := tar.FileInfoHeader(fi, "")
+ if err != nil {
+ return nil, fmt.Errorf("can't make tar header: %v", err)
+ }
+ head.Name = a.dir + head.Name
+ if err := a.tarw.WriteHeader(head); err != nil {
+ return nil, fmt.Errorf("can't add tar header: %v", err)
+ }
+ return a.tarw, nil
+}
+
+func (a *TarballArchive) Close() error {
+ if err := a.tarw.Close(); err != nil {
+ return err
+ }
+ if err := a.gzw.Close(); err != nil {
+ return err
+ }
+ return a.file.Close()
+}
+
+// ExtractArchive unpacks a .zip or .tar.gz archive to the destination directory.
+func ExtractArchive(archive string, dest string) error {
+ ar, err := os.Open(archive)
+ if err != nil {
+ return err
+ }
+ defer ar.Close()
+
+ switch {
+ case strings.HasSuffix(archive, ".tar.gz"):
+ return extractTarball(ar, dest)
+ case strings.HasSuffix(archive, ".zip"):
+ return extractZip(ar, dest)
+ default:
+ return fmt.Errorf("unhandled archive type %s", archive)
+ }
+}
+
+// extractTarball unpacks a .tar.gz file.
+func extractTarball(ar io.Reader, dest string) error {
+ gzr, err := gzip.NewReader(ar)
+ if err != nil {
+ return err
+ }
+ defer gzr.Close()
+
+ tr := tar.NewReader(gzr)
+ for {
+ // Move to the next file header.
+ header, err := tr.Next()
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ // We only care about regular files, directory modes
+ // and special file types are not supported.
+ if header.Typeflag == tar.TypeReg {
+ armode := header.FileInfo().Mode()
+ err := extractFile(header.Name, armode, tr, dest)
+ if err != nil {
+ return fmt.Errorf("extract %s: %v", header.Name, err)
+ }
+ }
+ }
+}
+
+// extractZip unpacks the given .zip file.
+func extractZip(ar *os.File, dest string) error {
+ info, err := ar.Stat()
+ if err != nil {
+ return err
+ }
+ zr, err := zip.NewReader(ar, info.Size())
+ if err != nil {
+ return err
+ }
+
+ for _, zf := range zr.File {
+ if !zf.Mode().IsRegular() {
+ continue
+ }
+
+ data, err := zf.Open()
+ if err != nil {
+ return err
+ }
+ err = extractFile(zf.Name, zf.Mode(), data, dest)
+ data.Close()
+ if err != nil {
+ return fmt.Errorf("extract %s: %v", zf.Name, err)
+ }
+ }
+ return nil
+}
+
+// extractFile extracts a single file from an archive.
+func extractFile(arpath string, armode os.FileMode, data io.Reader, dest string) error {
+ // Check that path is inside destination directory.
+ target := filepath.Join(dest, filepath.FromSlash(arpath))
+ if !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) {
+ return fmt.Errorf("path %q escapes archive destination", target)
+ }
+
+ // Remove the preivously-extracted file if it exists
+ if err := os.RemoveAll(target); err != nil {
+ return err
+ }
+
+ // Recreate the destination directory
+ if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
+ return err
+ }
+
+ // Copy file data.
+ file, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY, armode)
+ if err != nil {
+ return err
+ }
+ if _, err = io.Copy(file, data); err != nil {
+ file.Close()
+ os.Remove(target)
+ return err
+ }
+ return file.Close()
+}
diff --git a/internal/build/download.go b/internal/build/download.go
new file mode 100644
index 000000000000..50268227a501
--- /dev/null
+++ b/internal/build/download.go
@@ -0,0 +1,151 @@
+// Copyright 2019 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package build
+
+import (
+ "bufio"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// ChecksumDB keeps file checksums.
+type ChecksumDB struct {
+ allChecksums []string
+}
+
+// MustLoadChecksums loads a file containing checksums.
+func MustLoadChecksums(file string) *ChecksumDB {
+ content, err := os.ReadFile(file)
+ if err != nil {
+ log.Fatal("can't load checksum file: " + err.Error())
+ }
+ return &ChecksumDB{strings.Split(strings.ReplaceAll(string(content), "\r\n", "\n"), "\n")}
+}
+
+// Verify checks whether the given file is valid according to the checksum database.
+func (db *ChecksumDB) Verify(path string) error {
+ fd, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+
+ h := sha256.New()
+ if _, err := io.Copy(h, bufio.NewReader(fd)); err != nil {
+ return err
+ }
+ fileHash := hex.EncodeToString(h.Sum(nil))
+ if !db.findHash(filepath.Base(path), fileHash) {
+ return fmt.Errorf("invalid file hash: %s %s", fileHash, filepath.Base(path))
+ }
+ return nil
+}
+
+func (db *ChecksumDB) findHash(basename, hash string) bool {
+ want := hash + " " + basename
+ for _, line := range db.allChecksums {
+ if strings.TrimSpace(line) == want {
+ return true
+ }
+ }
+ return false
+}
+
+// DownloadFile downloads a file and verifies its checksum.
+func (db *ChecksumDB) DownloadFile(url, dstPath string) error {
+ if err := db.Verify(dstPath); err == nil {
+ fmt.Printf("%s is up-to-date\n", dstPath)
+ return nil
+ }
+ fmt.Printf("%s is stale\n", dstPath)
+ fmt.Printf("downloading from %s\n", url)
+
+ resp, err := http.Get(url)
+ if err != nil {
+ return fmt.Errorf("download error: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("download error: status %d", resp.StatusCode)
+ }
+ if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil {
+ return err
+ }
+ fd, err := os.OpenFile(dstPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
+ if err != nil {
+ return err
+ }
+ dst := newDownloadWriter(fd, resp.ContentLength)
+ _, err = io.Copy(dst, resp.Body)
+ dst.Close()
+ if err != nil {
+ return err
+ }
+ return db.Verify(dstPath)
+}
+
+type downloadWriter struct {
+ file *os.File
+ dstBuf *bufio.Writer
+ size int64
+ written int64
+ lastpct int64
+}
+
+func newDownloadWriter(dst *os.File, size int64) *downloadWriter {
+ return &downloadWriter{
+ file: dst,
+ dstBuf: bufio.NewWriter(dst),
+ size: size,
+ }
+}
+
+func (w *downloadWriter) Write(buf []byte) (int, error) {
+ n, err := w.dstBuf.Write(buf)
+
+ // Report progress.
+ w.written += int64(n)
+ pct := w.written * 10 / w.size * 10
+ if pct != w.lastpct {
+ if w.lastpct != 0 {
+ fmt.Print("...")
+ }
+ fmt.Print(pct, "%")
+ w.lastpct = pct
+ }
+ return n, err
+}
+
+func (w *downloadWriter) Close() error {
+ if w.lastpct > 0 {
+ fmt.Println() // Finish the progress line.
+ }
+ flushErr := w.dstBuf.Flush()
+ closeErr := w.file.Close()
+ if flushErr != nil {
+ return flushErr
+ }
+ return closeErr
+}
diff --git a/internal/build/gotool.go b/internal/build/gotool.go
new file mode 100644
index 000000000000..2a474604183f
--- /dev/null
+++ b/internal/build/gotool.go
@@ -0,0 +1,180 @@
+// Copyright 2021 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package build
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+type GoToolchain struct {
+ Root string // GOROOT
+
+ // Cross-compilation variables. These are set when running the go tool.
+ GOARCH string
+ GOOS string
+ CC string
+}
+
+// Go creates an invocation of the go command.
+func (g *GoToolchain) Go(command string, args ...string) *exec.Cmd {
+ tool := g.goTool(command, args...)
+
+ // Configure environment for cross build.
+ if g.GOARCH != "" && g.GOARCH != runtime.GOARCH {
+ tool.Env = append(tool.Env, "CGO_ENABLED=1")
+ tool.Env = append(tool.Env, "GOARCH="+g.GOARCH)
+ }
+ if g.GOOS != "" && g.GOOS != runtime.GOOS {
+ tool.Env = append(tool.Env, "GOOS="+g.GOOS)
+ }
+ // Configure C compiler.
+ if g.CC != "" {
+ tool.Env = append(tool.Env, "CC="+g.CC)
+ } else if os.Getenv("CC") != "" {
+ tool.Env = append(tool.Env, "CC="+os.Getenv("CC"))
+ }
+ // CKZG by default is not portable, append the necessary build flags to make
+ // it not rely on modern CPU instructions and enable linking against.
+ tool.Env = append(tool.Env, "CGO_CFLAGS=-O2 -g -D__BLST_PORTABLE__")
+
+ return tool
+}
+
+func (g *GoToolchain) goTool(command string, args ...string) *exec.Cmd {
+ if g.Root == "" {
+ g.Root = runtime.GOROOT()
+ }
+ tool := exec.Command(filepath.Join(g.Root, "bin", "go"), command) // nolint: gosec
+ tool.Args = append(tool.Args, args...)
+ tool.Env = append(tool.Env, "GOROOT="+g.Root)
+
+ // Forward environment variables to the tool, but skip compiler target settings.
+ // TODO: what about GOARM?
+ skip := map[string]struct{}{"GOROOT": {}, "GOARCH": {}, "GOOS": {}, "GOBIN": {}, "CC": {}}
+ for _, e := range os.Environ() {
+ if i := strings.IndexByte(e, '='); i >= 0 {
+ if _, ok := skip[e[:i]]; ok {
+ continue
+ }
+ }
+ tool.Env = append(tool.Env, e)
+ }
+ return tool
+}
+
+// DownloadGo downloads the Go binary distribution and unpacks it into a temporary
+// directory. It returns the GOROOT of the unpacked toolchain.
+func DownloadGo(csdb *ChecksumDB) string {
+ version, err := Version(csdb, "golang")
+ if err != nil {
+ log.Fatal(err)
+ }
+ // Shortcut: if the Go version that runs this script matches the
+ // requested version exactly, there is no need to download anything.
+ activeGo := strings.TrimPrefix(runtime.Version(), "go")
+ if activeGo == version {
+ log.Printf("-dlgo version matches active Go version %s, skipping download.", activeGo)
+ return runtime.GOROOT()
+ }
+
+ ucache, err := os.UserCacheDir()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // For Arm architecture, GOARCH includes ISA version.
+ os := runtime.GOOS
+ arch := runtime.GOARCH
+ if arch == "arm" {
+ arch = "armv6l"
+ }
+ file := fmt.Sprintf("go%s.%s-%s", version, os, arch)
+ if os == "windows" {
+ file += ".zip"
+ } else {
+ file += ".tar.gz"
+ }
+ url := "https://golang.org/dl/" + file
+ dst := filepath.Join(ucache, file)
+ if err := csdb.DownloadFile(url, dst); err != nil {
+ log.Fatal(err)
+ }
+
+ godir := filepath.Join(ucache, fmt.Sprintf("geth-go-%s-%s-%s", version, os, arch))
+ if err := ExtractArchive(dst, godir); err != nil {
+ log.Fatal(err)
+ }
+ goroot, err := filepath.Abs(filepath.Join(godir, "go"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ return goroot
+}
+
+// Version returns the versions defined in the checksumdb.
+func Version(csdb *ChecksumDB, version string) (string, error) {
+ for _, l := range csdb.allChecksums {
+ if !strings.HasPrefix(l, "# version:") {
+ continue
+ }
+ v := strings.Split(l, ":")[1]
+ parts := strings.Split(v, " ")
+ if len(parts) != 2 {
+ log.Print("Erroneous version-string", "v", l)
+ continue
+ }
+ if parts[0] == version {
+ return parts[1], nil
+ }
+ }
+ return "", fmt.Errorf("no version found for '%v'", version)
+}
+
+// DownloadAndVerifyChecksums downloads all files and checks that they match
+// the checksum given in checksums.txt.
+// This task can be used to sanity-check new checksums.
+func DownloadAndVerifyChecksums(csdb *ChecksumDB) {
+ var (
+ base = ""
+ ucache = os.TempDir()
+ )
+ for _, l := range csdb.allChecksums {
+ if strings.HasPrefix(l, "# https://") {
+ base = l[2:]
+ continue
+ }
+ if strings.HasPrefix(l, "#") {
+ continue
+ }
+ hashFile := strings.Split(l, " ")
+ if len(hashFile) != 2 {
+ continue
+ }
+ file := hashFile[1]
+ url := base + file
+ dst := filepath.Join(ucache, file)
+ if err := csdb.DownloadFile(url, dst); err != nil {
+ log.Print(err)
+ }
+ }
+}
diff --git a/internal/build/util.go b/internal/build/util.go
index 3fcb411c70de..42f57a468181 100644
--- a/internal/build/util.go
+++ b/internal/build/util.go
@@ -26,7 +26,9 @@ import (
"path"
"path/filepath"
"runtime"
+ "strconv"
"strings"
+ "time"
)
var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
@@ -34,7 +36,7 @@ var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
// MustRun executes the given command and exits the host process for
// any error.
func MustRun(cmd *exec.Cmd) {
- fmt.Println(">>>", strings.Join(cmd.Args, " "))
+ fmt.Println(">>>", printArgs(cmd.Args))
if !*DryRunFlag {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
@@ -44,10 +46,45 @@ func MustRun(cmd *exec.Cmd) {
}
}
+func printArgs(args []string) string {
+ var s strings.Builder
+ for i, arg := range args {
+ if i > 0 {
+ s.WriteByte(' ')
+ }
+ if strings.IndexByte(arg, ' ') >= 0 {
+ arg = strconv.QuoteToASCII(arg)
+ }
+ s.WriteString(arg)
+ }
+ return s.String()
+}
+
func MustRunCommand(cmd string, args ...string) {
MustRun(exec.Command(cmd, args...))
}
+// MustRunCommandWithOutput runs the given command, and ensures that some output will be
+// printed while it runs. This is useful for CI builds where the process will be stopped
+// when there is no output.
+func MustRunCommandWithOutput(cmd string, args ...string) {
+ interval := time.NewTicker(time.Minute)
+ done := make(chan struct{})
+ defer interval.Stop()
+ defer close(done)
+ go func() {
+ for {
+ select {
+ case <-interval.C:
+ fmt.Printf("Waiting for command %q\n", cmd)
+ case <-done:
+ return
+ }
+ }
+ }()
+ MustRun(exec.Command(cmd, args...))
+}
+
// GOPATH returns the value that the GOPATH environment
// variable should be set to.
func GOPATH() string {