mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
Compare commits
5 Commits
v6.1.2-rc.
...
hashtree-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b00cacef4 | ||
|
|
6f89cb5330 | ||
|
|
e315f78b97 | ||
|
|
536df4b682 | ||
|
|
1b98d8c202 |
31
BUILD.bazel
31
BUILD.bazel
@@ -1,8 +1,9 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@bazel_gazelle//:def.bzl", "gazelle")
|
||||
load("@com_github_atlassian_bazel_tools//gometalinter:def.bzl", "gometalinter")
|
||||
load("@com_github_atlassian_bazel_tools//goimports:def.bzl", "goimports")
|
||||
load("@io_kubernetes_build//defs:run_in_workspace.bzl", "workspace_binary")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "nogo")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "nogo")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "string_setting")
|
||||
load("@prysm//tools/nogo_config:def.bzl", "nogo_config_exclude")
|
||||
|
||||
@@ -282,3 +283,31 @@ sh_binary(
|
||||
srcs = ["prysm.sh"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"compare_states.go",
|
||||
"reproduce_bug.go",
|
||||
"verify_fix.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v6",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "v6",
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -415,6 +415,10 @@ load("@prysm//third_party/herumi:herumi.bzl", "bls_dependencies")
|
||||
|
||||
bls_dependencies()
|
||||
|
||||
load("@prysm//third_party/hashtree:hashtree.bzl", "hashtree_dependencies")
|
||||
|
||||
hashtree_dependencies()
|
||||
|
||||
load("@prysm//testing/endtoend:deps.bzl", "e2e_deps")
|
||||
|
||||
e2e_deps()
|
||||
|
||||
2
changelog/potuz_add_hashtree.md
Normal file
2
changelog/potuz_add_hashtree.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Added
|
||||
- Add optional `--use-hashtree` flag to beacon-chain and validator clients for using the hashtree library instead of gohashtree for vectorized SHA-256 merkle tree hashing. The hashtree library provides optimized assembly implementations for x86_64 and ARM64 architectures without CGO overhead.
|
||||
@@ -14,6 +14,7 @@ go_library(
|
||||
"//cmd:go_default_library",
|
||||
"//cmd/beacon-chain/sync/backfill/flags:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/hash/htr:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/cmd"
|
||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||
"github.com/OffchainLabs/prysm/v6/crypto/hash/htr"
|
||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -275,6 +276,13 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
cfg.ForceHead = ctx.String(forceHeadFlag.Name)
|
||||
}
|
||||
|
||||
if ctx.Bool(UseHashtreeFlag.Name) {
|
||||
logEnabled(UseHashtreeFlag)
|
||||
htr.SetUseHashtree(true)
|
||||
} else {
|
||||
log.Info("Using gohashtree library for vectorized SHA-256 hashing")
|
||||
}
|
||||
|
||||
if ctx.IsSet(blacklistRoots.Name) {
|
||||
logEnabled(blacklistRoots)
|
||||
cfg.BlacklistedRoots = parseBlacklistedRoots(ctx.StringSlice(blacklistRoots.Name))
|
||||
@@ -331,6 +339,12 @@ func ConfigureValidator(ctx *cli.Context) error {
|
||||
logEnabled(EnableBeaconRESTApi)
|
||||
cfg.EnableBeaconRESTApi = true
|
||||
}
|
||||
if ctx.Bool(UseHashtreeFlag.Name) {
|
||||
logEnabled(UseHashtreeFlag)
|
||||
htr.SetUseHashtree(true)
|
||||
} else {
|
||||
log.Info("Using gohashtree library for vectorized SHA-256 hashing")
|
||||
}
|
||||
if ctx.Bool(DisableDutiesV2.Name) {
|
||||
logEnabled(DisableDutiesV2)
|
||||
cfg.DisableDutiesV2 = true
|
||||
|
||||
@@ -197,6 +197,13 @@ var (
|
||||
Usage: "(Work in progress): Enables the web portal for the validator client.",
|
||||
Value: false,
|
||||
}
|
||||
|
||||
// UseHashtreeFlag enables using the hashtree library instead of gohashtree for vectorized hashing.
|
||||
UseHashtreeFlag = &cli.BoolFlag{
|
||||
Name: "use-hashtree",
|
||||
Usage: "Uses the hashtree library instead of gohashtree for vectorized SHA-256 merkle tree hashing.",
|
||||
Value: false,
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
@@ -219,6 +226,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
||||
EnableBeaconRESTApi,
|
||||
DisableDutiesV2,
|
||||
EnableWebFlag,
|
||||
UseHashtreeFlag,
|
||||
}...)
|
||||
|
||||
// E2EValidatorFlags contains a list of the validator feature flags to be tested in E2E.
|
||||
@@ -257,6 +265,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
|
||||
enableExperimentalAttestationPool,
|
||||
forceHeadFlag,
|
||||
blacklistRoots,
|
||||
UseHashtreeFlag,
|
||||
}, deprecatedBeaconFlags, deprecatedFlags, upcomingDeprecation)
|
||||
|
||||
func combinedFlags(flags ...[]cli.Flag) []cli.Flag {
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
# gazelle:resolve go github.com/prysmaticlabs/hashtree //third_party/hashtree:go_default_library
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["hashtree.go"],
|
||||
importpath = "github.com/OffchainLabs/prysm/v6/crypto/hash/htr",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@com_github_prysmaticlabs_gohashtree//:go_default_library"],
|
||||
deps = [
|
||||
"//third_party/hashtree:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
|
||||
@@ -5,27 +5,52 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
hashtreelib "github.com/prysmaticlabs/hashtree"
|
||||
)
|
||||
|
||||
const minSliceSizeToParallelize = 5000
|
||||
|
||||
// HashFunc defines the interface for vectorized hash implementations
|
||||
type HashFunc func(output [][32]byte, input [][32]byte) error
|
||||
|
||||
var (
|
||||
// currentHashFunc holds the active hash implementation
|
||||
currentHashFunc HashFunc = gohashtree.Hash
|
||||
|
||||
// useHashtree flag determines which implementation to use
|
||||
useHashtree bool = false
|
||||
)
|
||||
|
||||
// SetUseHashtree configures whether to use the hashtree library (true) or gohashtree (false)
|
||||
func SetUseHashtree(use bool) {
|
||||
useHashtree = use
|
||||
if use {
|
||||
currentHashFunc = hashtreelib.Hash
|
||||
} else {
|
||||
currentHashFunc = gohashtree.Hash
|
||||
}
|
||||
}
|
||||
|
||||
// GetUseHashtree returns the current hashtree usage setting
|
||||
func GetUseHashtree() bool {
|
||||
return useHashtree
|
||||
}
|
||||
|
||||
func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
err := gohashtree.Hash(outputList, inputList)
|
||||
err := currentHashFunc(outputList, inputList)
|
||||
if err != nil {
|
||||
panic(err) // lint:nopanic -- This should never panic.
|
||||
}
|
||||
}
|
||||
|
||||
// VectorizedSha256 takes a list of roots and hashes them using CPU
|
||||
// specific vector instructions. Depending on host machine's specific
|
||||
// hardware configuration, using this routine can lead to a significant
|
||||
// performance improvement compared to the default method of hashing
|
||||
// lists.
|
||||
// specific vector instructions. Uses either gohashtree or hashtree
|
||||
// implementation based on the current configuration.
|
||||
func VectorizedSha256(inputList [][32]byte) [][32]byte {
|
||||
outputList := make([][32]byte, len(inputList)/2)
|
||||
if len(inputList) < minSliceSizeToParallelize {
|
||||
err := gohashtree.Hash(outputList, inputList)
|
||||
err := currentHashFunc(outputList, inputList)
|
||||
if err != nil {
|
||||
panic(err) // lint:nopanic -- This should never panic.
|
||||
}
|
||||
@@ -38,7 +63,7 @@ func VectorizedSha256(inputList [][32]byte) [][32]byte {
|
||||
for j := 0; j < n; j++ {
|
||||
go hashParallel(inputList[j*2*groupSize:(j+1)*2*groupSize], outputList[j*groupSize:], &wg)
|
||||
}
|
||||
err := gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
err := currentHashFunc(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
if err != nil {
|
||||
panic(err) // lint:nopanic -- This should never panic.
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package htr
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -25,3 +26,247 @@ func Test_VectorizedSha256(t *testing.T) {
|
||||
require.Equal(t, r, hash2[i])
|
||||
}
|
||||
}
|
||||
|
||||
// generateTestData creates random test data for hashing tests
|
||||
func generateTestData(size int) [][32]byte {
|
||||
data := make([][32]byte, size)
|
||||
for i := range data {
|
||||
_, err := rand.Read(data[i][:])
|
||||
if err != nil {
|
||||
panic(err) // This should never happen in tests
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// Test_GohashtreeVsHashtree verifies both implementations produce identical results
|
||||
func Test_GohashtreeVsHashtree(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
size int
|
||||
}{
|
||||
{"small", 100},
|
||||
{"medium", 1000},
|
||||
{"large", 10000},
|
||||
{"very_large", 50000},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Generate test data (must be even number for hash pairs)
|
||||
input := generateTestData(tt.size * 2)
|
||||
|
||||
// Test with gohashtree (default)
|
||||
SetUseHashtree(false)
|
||||
gohashtreeResult := VectorizedSha256(input)
|
||||
|
||||
// Test with hashtree
|
||||
SetUseHashtree(true)
|
||||
hashtreeResult := VectorizedSha256(input)
|
||||
|
||||
// Reset to default
|
||||
SetUseHashtree(false)
|
||||
|
||||
// Results should be identical
|
||||
require.Equal(t, len(gohashtreeResult), len(hashtreeResult), "Result lengths should match")
|
||||
for i := range gohashtreeResult {
|
||||
require.Equal(t, gohashtreeResult[i], hashtreeResult[i], "Hash results should be identical at index %d", i)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test_GohashtreeImplementation tests gohashtree specifically
|
||||
func Test_GohashtreeImplementation(t *testing.T) {
|
||||
// Force gohashtree
|
||||
SetUseHashtree(false)
|
||||
defer SetUseHashtree(false) // Reset after test
|
||||
|
||||
require.Equal(t, false, GetUseHashtree(), "Should be using gohashtree")
|
||||
|
||||
// Test small input (non-parallel path)
|
||||
smallInput := generateTestData(10)
|
||||
smallResult := VectorizedSha256(smallInput)
|
||||
require.Equal(t, 5, len(smallResult), "Small input should produce correct number of hashes")
|
||||
|
||||
// Test large input (parallel path)
|
||||
largeInput := generateTestData(minSliceSizeToParallelize + 100)
|
||||
largeResult := VectorizedSha256(largeInput)
|
||||
expectedLen := (minSliceSizeToParallelize + 100) / 2
|
||||
require.Equal(t, expectedLen, len(largeResult), "Large input should produce correct number of hashes")
|
||||
}
|
||||
|
||||
// Test_HashtreeImplementation tests hashtree specifically
|
||||
func Test_HashtreeImplementation(t *testing.T) {
|
||||
// Force hashtree
|
||||
SetUseHashtree(true)
|
||||
defer SetUseHashtree(false) // Reset after test
|
||||
|
||||
require.Equal(t, true, GetUseHashtree(), "Should be using hashtree")
|
||||
|
||||
// Test small input
|
||||
smallInput := generateTestData(10)
|
||||
smallResult := VectorizedSha256(smallInput)
|
||||
require.Equal(t, 5, len(smallResult), "Small input should produce correct number of hashes")
|
||||
|
||||
// Test large input
|
||||
largeInput := generateTestData(minSliceSizeToParallelize + 100)
|
||||
largeResult := VectorizedSha256(largeInput)
|
||||
expectedLen := (minSliceSizeToParallelize + 100) / 2
|
||||
require.Equal(t, expectedLen, len(largeResult), "Large input should produce correct number of hashes")
|
||||
}
|
||||
|
||||
// Test_ThreadSafety verifies both implementations work correctly with concurrent access
|
||||
func Test_ThreadSafety(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
useHashtree bool
|
||||
}{
|
||||
{"gohashtree_concurrent", false},
|
||||
{"hashtree_concurrent", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
SetUseHashtree(tt.useHashtree)
|
||||
defer SetUseHashtree(false)
|
||||
|
||||
const numGoroutines = 10
|
||||
const inputSize = 1000
|
||||
|
||||
results := make([][][32]byte, numGoroutines)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
// Run concurrent hashing
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(index int) {
|
||||
defer wg.Done()
|
||||
input := generateTestData(inputSize)
|
||||
results[index] = VectorizedSha256(input)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// Verify all results have correct length
|
||||
expectedLen := inputSize / 2
|
||||
for i, result := range results {
|
||||
require.Equal(t, expectedLen, len(result), "Result %d should have correct length", i)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_GohashtreeSmall benchmarks gohashtree with small input
|
||||
func Benchmark_GohashtreeSmall(b *testing.B) {
|
||||
SetUseHashtree(false)
|
||||
input := generateTestData(100)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_HashtreeSmall benchmarks hashtree with small input
|
||||
func Benchmark_HashtreeSmall(b *testing.B) {
|
||||
SetUseHashtree(true)
|
||||
defer SetUseHashtree(false)
|
||||
input := generateTestData(100)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_GohashtreeMedium benchmarks gohashtree with medium input
|
||||
func Benchmark_GohashtreeMedium(b *testing.B) {
|
||||
SetUseHashtree(false)
|
||||
input := generateTestData(2000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_HashtreeMedium benchmarks hashtree with medium input
|
||||
func Benchmark_HashtreeMedium(b *testing.B) {
|
||||
SetUseHashtree(true)
|
||||
defer SetUseHashtree(false)
|
||||
input := generateTestData(2000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_GohashtreeLarge benchmarks gohashtree with large input (parallel path)
|
||||
func Benchmark_GohashtreeLarge(b *testing.B) {
|
||||
SetUseHashtree(false)
|
||||
input := generateTestData(minSliceSizeToParallelize + 1000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_HashtreeLarge benchmarks hashtree with large input (parallel path)
|
||||
func Benchmark_HashtreeLarge(b *testing.B) {
|
||||
SetUseHashtree(true)
|
||||
defer SetUseHashtree(false)
|
||||
input := generateTestData(minSliceSizeToParallelize + 1000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_GohashtreeVeryLarge benchmarks gohashtree with very large input
|
||||
func Benchmark_GohashtreeVeryLarge(b *testing.B) {
|
||||
SetUseHashtree(false)
|
||||
input := generateTestData(50000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_HashtreeVeryLarge benchmarks hashtree with very large input
|
||||
func Benchmark_HashtreeVeryLarge(b *testing.B) {
|
||||
SetUseHashtree(true)
|
||||
defer SetUseHashtree(false)
|
||||
input := generateTestData(50000)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_Comparison runs both implementations side by side for direct comparison
|
||||
func Benchmark_Comparison(b *testing.B) {
|
||||
input := generateTestData(10000)
|
||||
|
||||
b.Run("gohashtree", func(b *testing.B) {
|
||||
SetUseHashtree(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("hashtree", func(b *testing.B) {
|
||||
SetUseHashtree(true)
|
||||
defer SetUseHashtree(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = VectorizedSha256(input)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
1
go.mod
1
go.mod
@@ -61,6 +61,7 @@ require (
|
||||
github.com/prometheus/prom2json v1.3.0
|
||||
github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e
|
||||
github.com/prysmaticlabs/hashtree v0.2.0
|
||||
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c
|
||||
github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294
|
||||
github.com/r3labs/sse/v2 v2.10.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -902,6 +902,8 @@ github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e h1:ATgOe
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
|
||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b h1:VK7thFOnhxAZ/5aolr5Os4beiubuD08WiuiHyRqgwks=
|
||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b/go.mod h1:HRuvtXLZ4WkaB1MItToVH2e8ZwKwZPY5/Rcby+CvvLY=
|
||||
github.com/prysmaticlabs/hashtree v0.2.0 h1:vMBmqDmW9G7RYEc/Fv7OYnt9vCl8SYgDB2qQlm8Uj+k=
|
||||
github.com/prysmaticlabs/hashtree v0.2.0/go.mod h1:8eJvdNI+eWfxzaCYVQ6EEMuBGx+kn3rMTaUI7aAVlCY=
|
||||
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU=
|
||||
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c/go.mod h1:ZRws458tYHS/Zs936OQ6oCrL+Ict5O4Xpwve1UQ6C9M=
|
||||
github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h1:q9wE0ZZRdTUAAeyFP/w0SwBEnCqlVy2+on6X2/e+eAU=
|
||||
|
||||
12
third_party/hashtree/BUILD.bazel
vendored
Normal file
12
third_party/hashtree/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Alias to the hashtree library from the external repository
|
||||
alias(
|
||||
name = "hashtree",
|
||||
actual = "@offchainlabs_hashtree//:hashtree",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "go_default_library",
|
||||
actual = "@offchainlabs_hashtree//:hashtree",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
22
third_party/hashtree/hashtree.bzl
vendored
Normal file
22
third_party/hashtree/hashtree.bzl
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
"""
|
||||
OffchainLabs hashtree library for fast merkle tree hashing.
|
||||
Uses native Go bindings with syso files, no CGO overhead.
|
||||
"""
|
||||
|
||||
def hashtree_dependencies():
|
||||
_maybe(
|
||||
http_archive,
|
||||
name = "offchainlabs_hashtree",
|
||||
strip_prefix = "hashtree-main",
|
||||
urls = [
|
||||
"https://github.com/OffchainLabs/hashtree/archive/main.tar.gz",
|
||||
],
|
||||
build_file = "@prysm//third_party/hashtree:hashtree_source.BUILD",
|
||||
integrity = "sha256-FLfalJ7at89Tgm/XnZ90zRxjYqkBmv2dD418uhfVvYc=",
|
||||
)
|
||||
|
||||
def _maybe(repo_rule, name, **kwargs):
|
||||
if name not in native.existing_rules():
|
||||
repo_rule(name = name, **kwargs)
|
||||
203
third_party/hashtree/hashtree_source.BUILD
vendored
Normal file
203
third_party/hashtree/hashtree_source.BUILD
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
# BUILD file for building hashtree from source with proper cross-compilation support
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
# Config settings for platform detection
|
||||
config_setting(
|
||||
name = "windows_amd64",
|
||||
constraint_values = [
|
||||
"@platforms//os:windows",
|
||||
"@platforms//cpu:x86_64",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
# Build hashtree library for AMD64 - only build when targeting x86_64
|
||||
genrule(
|
||||
name = "build_hashtree_amd64",
|
||||
srcs = [
|
||||
"src/hashtree.c",
|
||||
"src/hashtree.h",
|
||||
"src/sha256_generic.c",
|
||||
"src/sha256_shani.S",
|
||||
"src/sha256_avx_x16.S",
|
||||
"src/sha256_avx_x8.S",
|
||||
"src/sha256_avx_x4.S",
|
||||
"src/sha256_avx_x1.S",
|
||||
"src/sha256_sse_x1.S",
|
||||
],
|
||||
outs = ["hashtree_amd64.syso"],
|
||||
cmd = """
|
||||
# Create build directories
|
||||
mkdir -p build/obj build/lib
|
||||
|
||||
# Use Bazel's toolchain - CC and AR are set by the toolchain
|
||||
COMPILER="$${CC:-gcc}"
|
||||
ARCHIVER="$${AR:-ar}"
|
||||
|
||||
# Add debugging output
|
||||
echo "Building hashtree with compiler: $$COMPILER"
|
||||
echo "Building hashtree with archiver: $$ARCHIVER"
|
||||
echo "Target architecture: $${GOARCH:-unknown}"
|
||||
|
||||
# Compile assembly files (handles Intel syntax)
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_shani.S) -o build/obj/sha256_shani.o
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_avx_x16.S) -o build/obj/sha256_avx_x16.o
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_avx_x8.S) -o build/obj/sha256_avx_x8.o
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_avx_x4.S) -o build/obj/sha256_avx_x4.o
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_avx_x1.S) -o build/obj/sha256_avx_x1.o
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_sse_x1.S) -o build/obj/sha256_sse_x1.o
|
||||
|
||||
# Compile C files
|
||||
$$COMPILER -g -Wall -Werror -O3 -c $(location src/sha256_generic.c) -o build/obj/sha256_generic.o
|
||||
$$COMPILER -g -Wall -Werror -O3 -c $(location src/hashtree.c) -I. -o build/obj/hashtree.o
|
||||
|
||||
# Create static library
|
||||
$$ARCHIVER rcs build/lib/libhashtree.a build/obj/*.o
|
||||
|
||||
# Copy to syso file
|
||||
cp build/lib/libhashtree.a $@
|
||||
""",
|
||||
target_compatible_with = ["@platforms//cpu:x86_64"],
|
||||
tags = ["requires-network"],
|
||||
)
|
||||
|
||||
# Build hashtree library for ARM64 - only build when targeting ARM64
|
||||
genrule(
|
||||
name = "build_hashtree_arm64",
|
||||
srcs = [
|
||||
"src/hashtree.c",
|
||||
"src/hashtree.h",
|
||||
"src/sha256_generic.c",
|
||||
"src/sha256_armv8_neon_x4.S",
|
||||
"src/sha256_armv8_neon_x1.S",
|
||||
"src/sha256_armv8_crypto.S",
|
||||
],
|
||||
outs = ["hashtree_arm64.syso"],
|
||||
cmd = """
|
||||
# Create build directories
|
||||
mkdir -p build/obj build/lib
|
||||
|
||||
# Try to use proper cross-compilation compiler
|
||||
if command -v clang >/dev/null 2>&1; then
|
||||
# CI environment with clang - use ARM64 cross-compilation
|
||||
COMPILER="clang --target=aarch64-linux-gnu"
|
||||
ARCHIVER="llvm-ar"
|
||||
echo "Using clang cross-compiler for ARM64"
|
||||
elif command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
|
||||
# Local environment with ARM64 GCC cross-compiler
|
||||
COMPILER="aarch64-linux-gnu-gcc"
|
||||
ARCHIVER="aarch64-linux-gnu-ar"
|
||||
echo "Using GCC cross-compiler for ARM64"
|
||||
else
|
||||
# Fallback: use system compiler (will fail for cross-compilation)
|
||||
COMPILER="gcc"
|
||||
ARCHIVER="ar"
|
||||
echo "WARNING: Using system compiler - cross-compilation may fail"
|
||||
fi
|
||||
|
||||
echo "Building hashtree with compiler: $$COMPILER"
|
||||
echo "Building hashtree with archiver: $$ARCHIVER"
|
||||
|
||||
# Compile assembly files with ARM64 target
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_armv8_neon_x4.S) -o build/obj/sha256_armv8_neon_x4.o || echo "Failed to compile neon_x4"
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_armv8_neon_x1.S) -o build/obj/sha256_armv8_neon_x1.o || echo "Failed to compile neon_x1"
|
||||
$$COMPILER -g -fpic -c $(location src/sha256_armv8_crypto.S) -o build/obj/sha256_armv8_crypto.o || echo "Failed to compile crypto"
|
||||
|
||||
# Compile C files with ARM64 target
|
||||
$$COMPILER -g -Wall -Werror -O3 -c $(location src/sha256_generic.c) -o build/obj/sha256_generic.o || echo "Failed to compile generic"
|
||||
$$COMPILER -g -Wall -Werror -O3 -c $(location src/hashtree.c) -I. -o build/obj/hashtree.o || echo "Failed to compile hashtree"
|
||||
|
||||
# Create static library
|
||||
$$ARCHIVER rcs build/lib/libhashtree.a build/obj/*.o || echo "Failed to create archive"
|
||||
|
||||
# Copy to syso file
|
||||
cp build/lib/libhashtree.a $@
|
||||
""",
|
||||
target_compatible_with = ["@platforms//cpu:aarch64"],
|
||||
tags = ["requires-network"],
|
||||
)
|
||||
|
||||
# Build hashtree library for Windows AMD64 - compile from source
|
||||
genrule(
|
||||
name = "build_hashtree_windows_amd64",
|
||||
srcs = [
|
||||
"src/hashtree.c",
|
||||
"src/hashtree.h",
|
||||
"src/sha256_generic.c",
|
||||
"src/sha256_shani.S",
|
||||
"src/sha256_avx_x16.S",
|
||||
"src/sha256_avx_x8.S",
|
||||
"src/sha256_avx_x4.S",
|
||||
"src/sha256_avx_x1.S",
|
||||
"src/sha256_sse_x1.S",
|
||||
],
|
||||
outs = ["hashtree_windows_amd64.syso"],
|
||||
cmd = """
|
||||
# Create build directories
|
||||
mkdir -p build/obj build/lib
|
||||
|
||||
# Use Bazel's Windows cross-compilation toolchain
|
||||
COMPILER="$${CC:-x86_64-w64-mingw32-gcc}"
|
||||
ARCHIVER="$${AR:-x86_64-w64-mingw32-ar}"
|
||||
|
||||
# Add debugging output
|
||||
echo "Building hashtree for Windows with compiler: $$COMPILER"
|
||||
echo "Building hashtree for Windows with archiver: $$ARCHIVER"
|
||||
|
||||
# Compile assembly files for Windows (Intel syntax)
|
||||
$$COMPILER -g -c $(location src/sha256_shani.S) -o build/obj/sha256_shani.o
|
||||
$$COMPILER -g -c $(location src/sha256_avx_x16.S) -o build/obj/sha256_avx_x16.o
|
||||
$$COMPILER -g -c $(location src/sha256_avx_x8.S) -o build/obj/sha256_avx_x8.o
|
||||
$$COMPILER -g -c $(location src/sha256_avx_x4.S) -o build/obj/sha256_avx_x4.o
|
||||
$$COMPILER -g -c $(location src/sha256_avx_x1.S) -o build/obj/sha256_avx_x1.o
|
||||
$$COMPILER -g -c $(location src/sha256_sse_x1.S) -o build/obj/sha256_sse_x1.o
|
||||
|
||||
# Compile C files for Windows
|
||||
$$COMPILER -g -Wall -Werror -O3 -c $(location src/sha256_generic.c) -o build/obj/sha256_generic.o
|
||||
$$COMPILER -g -Wall -Werror -O3 -c $(location src/hashtree.c) -I. -o build/obj/hashtree.o
|
||||
|
||||
# Create static library (Windows uses .lib extension but we create .a for compatibility)
|
||||
$$ARCHIVER rcs build/lib/libhashtree.a build/obj/*.o
|
||||
|
||||
# Copy to syso file
|
||||
cp build/lib/libhashtree.a $@
|
||||
""",
|
||||
target_compatible_with = [
|
||||
"@platforms//os:windows",
|
||||
"@platforms//cpu:x86_64",
|
||||
],
|
||||
tags = ["requires-network"],
|
||||
)
|
||||
|
||||
# Empty syso file for platforms where hashtree is not available
|
||||
genrule(
|
||||
name = "build_hashtree_generic",
|
||||
outs = ["hashtree_generic.syso"],
|
||||
cmd = "touch $@",
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
# Go library with architecture-specific syso files
|
||||
go_library(
|
||||
name = "hashtree",
|
||||
srcs = [
|
||||
"bindings.go",
|
||||
"bindings_amd64.go",
|
||||
"bindings_arm64.go",
|
||||
"sha256_1_generic.go",
|
||||
"wrapper_linux_amd64.s",
|
||||
"wrapper_arm64.s",
|
||||
"wrapper_windows_amd64.s",
|
||||
] + select({
|
||||
":windows_amd64": [":build_hashtree_windows_amd64"],
|
||||
"@platforms//cpu:x86_64": [":build_hashtree_amd64"],
|
||||
"@platforms//cpu:aarch64": [":build_hashtree_arm64"],
|
||||
"//conditions:default": [":build_hashtree_generic"],
|
||||
}),
|
||||
cgo = False,
|
||||
importpath = "github.com/prysmaticlabs/hashtree",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@com_github_klauspost_cpuid_v2//:go_default_library"],
|
||||
)
|
||||
Reference in New Issue
Block a user