mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-31 08:08:18 -05:00
Compare commits
1 Commits
e2e-debugg
...
singleSlic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1270b6b81 |
@@ -20,7 +20,7 @@ var (
|
|||||||
type FieldTrie struct {
|
type FieldTrie struct {
|
||||||
*sync.RWMutex
|
*sync.RWMutex
|
||||||
reference *stateutil.Reference
|
reference *stateutil.Reference
|
||||||
fieldLayers [][]*[32]byte
|
fieldLayers [][]byte
|
||||||
field types.FieldIndex
|
field types.FieldIndex
|
||||||
dataType types.DataType
|
dataType types.DataType
|
||||||
length uint64
|
length uint64
|
||||||
@@ -162,9 +162,9 @@ func (f *FieldTrie) CopyTrie() *FieldTrie {
|
|||||||
numOfElems: f.numOfElems,
|
numOfElems: f.numOfElems,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dstFieldTrie := make([][]*[32]byte, len(f.fieldLayers))
|
dstFieldTrie := make([][]byte, len(f.fieldLayers))
|
||||||
for i, layer := range f.fieldLayers {
|
for i, layer := range f.fieldLayers {
|
||||||
dstFieldTrie[i] = make([]*[32]byte, len(layer))
|
dstFieldTrie[i] = make([]byte, len(layer))
|
||||||
copy(dstFieldTrie[i], layer)
|
copy(dstFieldTrie[i], layer)
|
||||||
}
|
}
|
||||||
return &FieldTrie{
|
return &FieldTrie{
|
||||||
@@ -252,6 +252,6 @@ func (f *FieldTrie) Empty() bool {
|
|||||||
// InsertFieldLayer manually inserts a field layer. This method
|
// InsertFieldLayer manually inserts a field layer. This method
|
||||||
// bypasses the normal method of field computation, it is only
|
// bypasses the normal method of field computation, it is only
|
||||||
// meant to be used in tests.
|
// meant to be used in tests.
|
||||||
func (f *FieldTrie) InsertFieldLayer(layer [][]*[32]byte) {
|
func (f *FieldTrie) InsertFieldLayer(layer [][]byte) {
|
||||||
f.fieldLayers = layer
|
f.fieldLayers = layer
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func optimizedValidatorRoots(validators []*ethpb.Validator) ([][32]byte, error)
|
|||||||
if len(validators) == 0 {
|
if len(validators) == 0 {
|
||||||
return [][32]byte{}, nil
|
return [][32]byte{}, nil
|
||||||
}
|
}
|
||||||
roots := make([][32]byte, 0, len(validators)*validatorFieldRoots)
|
roots := make([]byte, 0, len(validators)*validatorFieldRoots)
|
||||||
for i := 0; i < len(validators); i++ {
|
for i := 0; i < len(validators); i++ {
|
||||||
fRoots, err := ValidatorFieldRoots(validators[i])
|
fRoots, err := ValidatorFieldRoots(validators[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -43,53 +43,52 @@ func ReturnTrieLayer(elements [][32]byte, length uint64) ([][]*[32]byte, error)
|
|||||||
// ReturnTrieLayerVariable returns the representation of a merkle trie when
|
// ReturnTrieLayerVariable returns the representation of a merkle trie when
|
||||||
// provided with the elements of a variable sized trie and the corresponding depth of
|
// provided with the elements of a variable sized trie and the corresponding depth of
|
||||||
// it.
|
// it.
|
||||||
func ReturnTrieLayerVariable(elements [][32]byte, length uint64) [][]*[32]byte {
|
func ReturnTrieLayerVariable(elements [][32]byte, length uint64) [][]byte {
|
||||||
depth := ssz.Depth(length)
|
depth := ssz.Depth(length)
|
||||||
layers := make([][]*[32]byte, depth+1)
|
layers := make([][]byte, depth+1)
|
||||||
// Return zerohash at depth
|
// Return zerohash at depth
|
||||||
if len(elements) == 0 {
|
if len(elements) == 0 {
|
||||||
zerohash := trie.ZeroHashes[depth]
|
zerohash := trie.ZeroHashes[depth]
|
||||||
layers[len(layers)-1] = []*[32]byte{&zerohash}
|
layers[len(layers)-1] = zerohash[:]
|
||||||
return layers
|
return layers
|
||||||
}
|
}
|
||||||
transformedLeaves := make([]*[32]byte, len(elements))
|
transformedLeaves := make([]byte, len(elements)*32)
|
||||||
for i := range elements {
|
for i := range elements {
|
||||||
arr := elements[i]
|
copy(transformedLeaves[i*32:(i+1)*32], elements[i][:])
|
||||||
transformedLeaves[i] = &arr
|
|
||||||
}
|
}
|
||||||
layers[0] = transformedLeaves
|
layers[0] = transformedLeaves
|
||||||
buffer := bytes.NewBuffer([]byte{})
|
buffer := bytes.NewBuffer([]byte{})
|
||||||
buffer.Grow(64)
|
buffer.Grow(64)
|
||||||
|
|
||||||
for i := uint8(0); i < depth; i++ {
|
for i := uint8(0); i < depth; i++ {
|
||||||
layerLen := len(layers[i])
|
numOfChunks := len(layers[i]) / 32
|
||||||
oddNodeLength := layerLen%2 == 1
|
oddNodeLength := numOfChunks%2 == 1
|
||||||
if oddNodeLength {
|
if oddNodeLength {
|
||||||
zerohash := trie.ZeroHashes[i]
|
zerohash := trie.ZeroHashes[i]
|
||||||
elements = append(elements, zerohash)
|
elements = append(elements, zerohash)
|
||||||
layerLen++
|
numOfChunks++
|
||||||
}
|
}
|
||||||
|
|
||||||
layers[i+1] = make([]*[32]byte, layerLen/2)
|
layers[i+1] = make([]byte, (numOfChunks/2)*32)
|
||||||
newElems := make([][32]byte, layerLen/2)
|
newElems := make([][32]byte, numOfChunks/2)
|
||||||
htr.VectorizedSha256(elements, newElems)
|
htr.VectorizedSha256(elements, newElems)
|
||||||
elements = newElems
|
elements = newElems
|
||||||
for j := range elements {
|
for j := range elements {
|
||||||
layers[i+1][j] = &elements[j]
|
copy(layers[i+1][j*32:(j+1)*32], elements[j][:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return layers
|
return layers
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecomputeFromLayer recomputes specific branches of a fixed sized trie depending on the provided changed indexes.
|
// RecomputeFromLayer recomputes specific branches of a fixed sized trie depending on the provided changed indexes.
|
||||||
func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][]*[32]byte) ([32]byte, [][]*[32]byte, error) {
|
func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][]byte) ([32]byte, [][]byte, error) {
|
||||||
hasher := hash.CustomSHA256Hasher()
|
hasher := hash.CustomSHA256Hasher()
|
||||||
for i, idx := range changedIdx {
|
for i, idx := range changedIdx {
|
||||||
layer[0][idx] = &changedLeaves[i]
|
copy(layer[0][idx*32:(idx+1)*32], changedLeaves[i][:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(changedIdx) == 0 {
|
if len(changedIdx) == 0 {
|
||||||
return *layer[0][0], layer, nil
|
return *(*[32]byte)(layer[0][:32]), layer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
leaves := layer[0]
|
leaves := layer[0]
|
||||||
@@ -102,7 +101,7 @@ func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][
|
|||||||
changedIdx = append(changedIdx, maxChangedIndex+1)
|
changedIdx = append(changedIdx, maxChangedIndex+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
root := *layer[0][0]
|
root := *(*[32]byte)(layer[0][:32])
|
||||||
|
|
||||||
for _, idx := range changedIdx {
|
for _, idx := range changedIdx {
|
||||||
ii, err := math.Int(idx)
|
ii, err := math.Int(idx)
|
||||||
@@ -118,12 +117,12 @@ func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RecomputeFromLayerVariable recomputes specific branches of a variable sized trie depending on the provided changed indexes.
|
// RecomputeFromLayerVariable recomputes specific branches of a variable sized trie depending on the provided changed indexes.
|
||||||
func RecomputeFromLayerVariable(changedLeaves [][32]byte, changedIdx []uint64, layer [][]*[32]byte) ([32]byte, [][]*[32]byte, error) {
|
func RecomputeFromLayerVariable(changedLeaves [][32]byte, changedIdx []uint64, layer [][]byte) ([32]byte, [][]byte, error) {
|
||||||
hasher := hash.CustomSHA256Hasher()
|
hasher := hash.CustomSHA256Hasher()
|
||||||
if len(changedIdx) == 0 {
|
if len(changedIdx) == 0 {
|
||||||
return *layer[0][0], layer, nil
|
return *(*[32]byte)(layer[0][:32]), layer, nil
|
||||||
}
|
}
|
||||||
root := *layer[len(layer)-1][0]
|
root := *(*[32]byte)(layer[len(layer)-1][:32])
|
||||||
|
|
||||||
for i, idx := range changedIdx {
|
for i, idx := range changedIdx {
|
||||||
ii, err := math.Int(idx)
|
ii, err := math.Int(idx)
|
||||||
@@ -140,9 +139,9 @@ func RecomputeFromLayerVariable(changedLeaves [][32]byte, changedIdx []uint64, l
|
|||||||
|
|
||||||
// this method assumes that the provided trie already has all its elements included
|
// this method assumes that the provided trie already has all its elements included
|
||||||
// in the base depth.
|
// in the base depth.
|
||||||
func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
|
func recomputeRootFromLayer(idx int, layers [][]byte, chunks []byte,
|
||||||
hasher func([]byte) [32]byte) ([32]byte, [][]*[32]byte, error) {
|
hasher func([]byte) [32]byte) ([32]byte, [][]byte, error) {
|
||||||
root := *chunks[idx]
|
root := *(*[32]byte)(chunks[idx*32 : (idx+1)*32])
|
||||||
layers[0] = chunks
|
layers[0] = chunks
|
||||||
// The merkle tree structure looks as follows:
|
// The merkle tree structure looks as follows:
|
||||||
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
|
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
|
||||||
@@ -157,7 +156,7 @@ func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
|
|||||||
|
|
||||||
var neighbor [32]byte
|
var neighbor [32]byte
|
||||||
if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
|
if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
|
||||||
neighbor = *layers[i][neighborIdx]
|
neighbor = *(*[32]byte)(layers[i][neighborIdx*32 : (neighborIdx+1)*32])
|
||||||
}
|
}
|
||||||
if isLeft {
|
if isLeft {
|
||||||
copy(combinedChunks[:32], root[:])
|
copy(combinedChunks[:32], root[:])
|
||||||
@@ -174,15 +173,15 @@ func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
|
|||||||
// Update the cached layers at the parent index.
|
// Update the cached layers at the parent index.
|
||||||
rootVal := root
|
rootVal := root
|
||||||
if len(layers[i+1]) == 0 {
|
if len(layers[i+1]) == 0 {
|
||||||
layers[i+1] = append(layers[i+1], &rootVal)
|
layers[i+1] = append(layers[i+1], rootVal[:]...)
|
||||||
} else {
|
} else {
|
||||||
layers[i+1][parentIdx] = &rootVal
|
copy(layers[i+1][parentIdx*32:(parentIdx+1)*32], rootVal[:])
|
||||||
}
|
}
|
||||||
currentIndex = parentIdx
|
currentIndex = parentIdx
|
||||||
}
|
}
|
||||||
// If there is only a single leaf, we return it (the identity element).
|
// If there is only a single leaf, we return it (the identity element).
|
||||||
if len(layers[0]) == 1 {
|
if len(layers[0]) == 1 {
|
||||||
return *layers[0][0], layers, nil
|
return *(*[32]byte)(layers[0][:32]), layers, nil
|
||||||
}
|
}
|
||||||
return root, layers, nil
|
return root, layers, nil
|
||||||
}
|
}
|
||||||
@@ -190,13 +189,13 @@ func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
|
|||||||
// this method assumes that the base branch does not consist of all leaves of the
|
// this method assumes that the base branch does not consist of all leaves of the
|
||||||
// trie. Instead missing leaves are assumed to be zerohashes, following the structure
|
// trie. Instead missing leaves are assumed to be zerohashes, following the structure
|
||||||
// of a sparse merkle trie.
|
// of a sparse merkle trie.
|
||||||
func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte,
|
func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]byte,
|
||||||
hasher func([]byte) [32]byte) ([32]byte, [][]*[32]byte, error) {
|
hasher func([]byte) [32]byte) ([32]byte, [][]byte, error) {
|
||||||
for idx >= len(layers[0]) {
|
for idx >= len(layers[0]) {
|
||||||
zerohash := trie.ZeroHashes[0]
|
zerohash := trie.ZeroHashes[0]
|
||||||
layers[0] = append(layers[0], &zerohash)
|
layers[0] = append(layers[0], zerohash[:]...)
|
||||||
}
|
}
|
||||||
layers[0][idx] = &item
|
copy(layers[0][idx*32:(idx+1):32], item[:])
|
||||||
|
|
||||||
currentIndex := idx
|
currentIndex := idx
|
||||||
root := item
|
root := item
|
||||||
@@ -211,7 +210,7 @@ func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte
|
|||||||
if neighborIdx >= len(layers[i]) {
|
if neighborIdx >= len(layers[i]) {
|
||||||
neighbor = trie.ZeroHashes[i]
|
neighbor = trie.ZeroHashes[i]
|
||||||
} else {
|
} else {
|
||||||
neighbor = *layers[i][neighborIdx]
|
neighbor = *(*[32]byte)(layers[i][(neighborIdx * 32) : (neighborIdx+1)*32])
|
||||||
}
|
}
|
||||||
if isLeft {
|
if isLeft {
|
||||||
copy(combinedChunks[:32], root[:])
|
copy(combinedChunks[:32], root[:])
|
||||||
@@ -227,10 +226,10 @@ func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte
|
|||||||
parentIdx := currentIndex / 2
|
parentIdx := currentIndex / 2
|
||||||
if len(layers[i+1]) == 0 || parentIdx >= len(layers[i+1]) {
|
if len(layers[i+1]) == 0 || parentIdx >= len(layers[i+1]) {
|
||||||
newItem := root
|
newItem := root
|
||||||
layers[i+1] = append(layers[i+1], &newItem)
|
layers[i+1] = append(layers[i+1], newItem[:]...)
|
||||||
} else {
|
} else {
|
||||||
newItem := root
|
newItem := root
|
||||||
layers[i+1][parentIdx] = &newItem
|
copy(layers[i+1][parentIdx*32:(parentIdx+1)*32], newItem[:])
|
||||||
}
|
}
|
||||||
currentIndex = parentIdx
|
currentIndex = parentIdx
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ import (
|
|||||||
// hardware configuration, using this routine can lead to a significant
|
// hardware configuration, using this routine can lead to a significant
|
||||||
// performance improvement compared to the default method of hashing
|
// performance improvement compared to the default method of hashing
|
||||||
// lists.
|
// lists.
|
||||||
func VectorizedSha256(inputList [][32]byte, outputList [][32]byte) {
|
func VectorizedSha256(inputList []byte, outputList []byte) {
|
||||||
|
err := gohashtree.HashByteSlice(outputList, inputList)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func VectorizedSha256Chunks(inputList [][32]byte, outputList [][32]byte) {
|
||||||
err := gohashtree.Hash(outputList, inputList)
|
err := gohashtree.Hash(outputList, inputList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
4
deps.bzl
4
deps.bzl
@@ -3303,8 +3303,8 @@ def prysm_deps():
|
|||||||
go_repository(
|
go_repository(
|
||||||
name = "com_github_prysmaticlabs_gohashtree",
|
name = "com_github_prysmaticlabs_gohashtree",
|
||||||
importpath = "github.com/prysmaticlabs/gohashtree",
|
importpath = "github.com/prysmaticlabs/gohashtree",
|
||||||
sum = "h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY=",
|
sum = "h1:po9GKr5APkGj8blcsaPYj/EBlZbvCmoKE/oGLZE+PNI=",
|
||||||
version = "v0.0.3-alpha",
|
version = "v0.0.3-alpha.0.20230510131438-bf992328364a",
|
||||||
)
|
)
|
||||||
|
|
||||||
go_repository(
|
go_repository(
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ func MerkleizeVector(elements [][32]byte, length uint64) [32]byte {
|
|||||||
elements = append(elements, zerohash)
|
elements = append(elements, zerohash)
|
||||||
}
|
}
|
||||||
outputLen := len(elements) / 2
|
outputLen := len(elements) / 2
|
||||||
htr.VectorizedSha256(elements, elements)
|
htr.VectorizedSha256Chunks(elements, elements)
|
||||||
elements = elements[:outputLen]
|
elements = elements[:outputLen]
|
||||||
}
|
}
|
||||||
return elements[0]
|
return elements[0]
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -248,7 +248,7 @@ require (
|
|||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.11.1
|
github.com/go-playground/validator/v10 v10.11.1
|
||||||
github.com/peterh/liner v1.2.0 // indirect
|
github.com/peterh/liner v1.2.0 // indirect
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.3-alpha
|
github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230510131438-bf992328364a
|
||||||
golang.org/x/sys v0.7.0 // indirect
|
golang.org/x/sys v0.7.0 // indirect
|
||||||
google.golang.org/api v0.34.0 // indirect
|
google.golang.org/api v0.34.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1066,8 +1066,12 @@ github.com/prysmaticlabs/fastssz v0.0.0-20220628121656-93dfe28febab/go.mod h1:MA
|
|||||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20210108222456-8e92c3709aa0/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
|
github.com/prysmaticlabs/go-bitfield v0.0.0-20210108222456-8e92c3709aa0/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
|
||||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw=
|
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw=
|
||||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
|
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
|
||||||
|
github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw=
|
||||||
|
github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.3-alpha h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY=
|
github.com/prysmaticlabs/gohashtree v0.0.3-alpha h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY=
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.3-alpha/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
|
github.com/prysmaticlabs/gohashtree v0.0.3-alpha/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
|
||||||
|
github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230510131438-bf992328364a h1:po9GKr5APkGj8blcsaPYj/EBlZbvCmoKE/oGLZE+PNI=
|
||||||
|
github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230510131438-bf992328364a/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
|
||||||
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20230315201114-09284ba20446 h1:4wctORg/1TkgLgXejv9yOSAm3cDBJxoTzl/RNuZmX28=
|
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20230315201114-09284ba20446 h1:4wctORg/1TkgLgXejv9yOSAm3cDBJxoTzl/RNuZmX28=
|
||||||
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20230315201114-09284ba20446/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24=
|
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20230315201114-09284ba20446/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24=
|
||||||
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU=
|
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU=
|
||||||
|
|||||||
Reference in New Issue
Block a user