mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-11 06:18:05 -05:00
Compare commits
8 Commits
payload-ev
...
lite-super
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93514608b0 | ||
|
|
f999173ccd | ||
|
|
9c074acf59 | ||
|
|
430bb09a74 | ||
|
|
d72ce136b8 | ||
|
|
2937b62a10 | ||
|
|
2fb2fecd92 | ||
|
|
f93a77aef9 |
@@ -146,7 +146,6 @@ go_test(
|
||||
"//beacon-chain/cache/depositsnapshot:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/feed:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/peerdas:go_default_library",
|
||||
@@ -180,7 +179,6 @@ go_test(
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/payload-attribute:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
|
||||
@@ -174,6 +174,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*
|
||||
"payloadID": fmt.Sprintf("%#x", bytesutil.Trunc(payloadID[:])),
|
||||
}).Info("Forkchoice updated with payload attributes for proposal")
|
||||
s.cfg.PayloadIDCache.Set(nextSlot, arg.headRoot, pId)
|
||||
go s.firePayloadAttributesEvent(s.cfg.StateNotifier.StateFeed(), arg.headBlock, arg.headRoot, nextSlot)
|
||||
} else if hasAttr && payloadID == nil && !features.Get().PrepareAllPayloads {
|
||||
log.WithFields(logrus.Fields{
|
||||
"blockHash": fmt.Sprintf("%#x", headPayload.BlockHash()),
|
||||
@@ -181,10 +182,6 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*
|
||||
"nextSlot": nextSlot,
|
||||
}).Error("Received nil payload ID on VALID engine response")
|
||||
}
|
||||
|
||||
// If the attribute is nil, it gets built in the rpc package in events.go, which calls fillEventData and then computePayloadAttributes to populate the attribute data
|
||||
go s.firePayloadAttributesEvent(s.cfg.StateNotifier.StateFeed(), arg.headBlock, arg.headRoot, nextSlot)
|
||||
|
||||
return payloadID, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/cache"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
|
||||
feed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed"
|
||||
statefeed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/state"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/execution"
|
||||
mockExecution "github.com/OffchainLabs/prysm/v7/beacon-chain/execution/testing"
|
||||
forkchoicetypes "github.com/OffchainLabs/prysm/v7/beacon-chain/forkchoice/types"
|
||||
@@ -19,7 +17,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
consensusblocks "github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
payloadattribute "github.com/OffchainLabs/prysm/v7/consensus-types/payload-attribute"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v7/genesis"
|
||||
@@ -39,9 +36,7 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
|
||||
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
|
||||
altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
bellatrix := util.NewBeaconBlockBellatrix()
|
||||
bellatrix.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte{0x1}, fieldparams.RootLength)
|
||||
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, bellatrix)
|
||||
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix())
|
||||
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -49,7 +44,6 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
|
||||
service.head = &head{
|
||||
state: st,
|
||||
}
|
||||
require.Equal(t, true, service.cfg.SyncChecker.Synced())
|
||||
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
@@ -94,63 +88,6 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
|
||||
require.IsNil(t, got)
|
||||
}
|
||||
|
||||
func Test_NotifyForkchoiceUpdate_FiresPayloadAttributesEventWithoutPayloadID(t *testing.T) {
|
||||
service, tr := minimalTestService(t, WithPayloadIDCache(cache.NewPayloadIDCache()))
|
||||
ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
|
||||
|
||||
events := make(chan *feed.Event, 1)
|
||||
sub := service.cfg.StateNotifier.StateFeed().Subscribe(events)
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
|
||||
altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
bellatrix := util.NewBeaconBlockBellatrix()
|
||||
bellatrix.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte{0x1}, fieldparams.RootLength)
|
||||
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, bellatrix)
|
||||
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
st, _ := util.DeterministicGenesisState(t, 10)
|
||||
service.head = &head{
|
||||
state: st,
|
||||
}
|
||||
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 1, altairBlkRoot, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 2, bellatrixBlkRoot, altairBlkRoot, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
|
||||
attr, err := payloadattribute.New(&v1.PayloadAttributes{
|
||||
Timestamp: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, attr.IsEmpty())
|
||||
arg := &fcuConfig{
|
||||
headState: st,
|
||||
headRoot: bellatrixBlkRoot,
|
||||
headBlock: bellatrixBlk,
|
||||
attributes: attr,
|
||||
}
|
||||
|
||||
expectedSlot := service.CurrentSlot() + 1
|
||||
got, err := service.notifyForkchoiceUpdate(ctx, arg)
|
||||
require.NoError(t, err)
|
||||
require.IsNil(t, got)
|
||||
|
||||
data := waitForPayloadAttributesEvent(t, events)
|
||||
require.Equal(t, bellatrixBlkRoot, data.HeadRoot)
|
||||
require.Equal(t, expectedSlot, data.ProposalSlot)
|
||||
require.Equal(t, arg.headBlock.Block().Slot(), data.HeadBlock.Block().Slot())
|
||||
}
|
||||
|
||||
func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
service, tr := minimalTestService(t, WithPayloadIDCache(cache.NewPayloadIDCache()))
|
||||
ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
|
||||
@@ -1153,25 +1090,3 @@ func TestComputePayloadAttribute(t *testing.T) {
|
||||
require.Equal(t, false, fcu.attributes.IsEmpty())
|
||||
require.Equal(t, suggestedAddr, common.BytesToAddress(fcu.attributes.SuggestedFeeRecipient()))
|
||||
}
|
||||
|
||||
func waitForPayloadAttributesEvent(t *testing.T, events <-chan *feed.Event) payloadattribute.EventData {
|
||||
t.Helper()
|
||||
|
||||
timeout := time.NewTimer(2 * time.Second)
|
||||
defer timeout.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-timeout.C:
|
||||
t.Fatalf("timed out waiting for payload attributes event")
|
||||
return payloadattribute.EventData{}
|
||||
case evt := <-events:
|
||||
if evt == nil || evt.Type != statefeed.PayloadAttributes {
|
||||
continue
|
||||
}
|
||||
data, ok := evt.Data.(payloadattribute.EventData)
|
||||
require.Equal(t, true, ok)
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,10 +471,20 @@ func (s *Service) removeStartupState() {
|
||||
// It returns the (potentially updated) custody group count and the earliest available slot.
|
||||
func (s *Service) updateCustodyInfoInDB(slot primitives.Slot) (primitives.Slot, uint64, error) {
|
||||
isSubscribedToAllDataSubnets := flags.Get().SubscribeAllDataSubnets
|
||||
isLiteSupernode := flags.Get().LiteSupernode
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
custodyRequirement := cfg.CustodyRequirement
|
||||
|
||||
// Warn if both flags are set (supernode takes precedence).
|
||||
if isSubscribedToAllDataSubnets && isLiteSupernode {
|
||||
log.Warnf(
|
||||
"Both `--%s` and `--%s` flags are set. The supernode flag takes precedence.",
|
||||
flags.SubscribeAllDataSubnets.Name,
|
||||
flags.LiteSupernode.Name,
|
||||
)
|
||||
}
|
||||
|
||||
// Check if the node was previously subscribed to all data subnets, and if so,
|
||||
// store the new status accordingly.
|
||||
wasSubscribedToAllDataSubnets, err := s.cfg.BeaconDB.UpdateSubscribedToAllDataSubnets(s.ctx, isSubscribedToAllDataSubnets)
|
||||
@@ -490,11 +500,31 @@ func (s *Service) updateCustodyInfoInDB(slot primitives.Slot) (primitives.Slot,
|
||||
)
|
||||
}
|
||||
|
||||
// Check if the node was previously in lite-supernode mode, and if so,
|
||||
// store the new status accordingly.
|
||||
wasLiteSupernode, err := s.cfg.BeaconDB.UpdateLiteSupernode(s.ctx, isLiteSupernode)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not update lite-supernode status")
|
||||
}
|
||||
|
||||
// Warn the user if the node was previously in lite-supernode mode and is not any more.
|
||||
if wasLiteSupernode && !isLiteSupernode {
|
||||
log.Warnf(
|
||||
"Because the flag `--%s` was previously used, the node will remain in lite-supernode mode (subscribe to 64 subnets).",
|
||||
flags.LiteSupernode.Name,
|
||||
)
|
||||
}
|
||||
|
||||
// Compute the custody group count.
|
||||
// Note: Lite-supernode subscribes to 64 subnets (enough to reconstruct) but only custodies the minimum groups (4).
|
||||
// Only supernode increases custody to all 128 groups.
|
||||
// Persistence (preventing downgrades) is handled by UpdateCustodyInfo() which
|
||||
// refuses to decrease the stored custody count.
|
||||
custodyGroupCount := custodyRequirement
|
||||
if isSubscribedToAllDataSubnets {
|
||||
custodyGroupCount = cfg.NumberOfCustodyGroups
|
||||
}
|
||||
// Lite-supernode does NOT increase custody count - it keeps the minimum (4 or validator requirement).
|
||||
|
||||
// Safely compute the fulu fork slot.
|
||||
fuluForkSlot, err := fuluForkSlot()
|
||||
|
||||
@@ -129,6 +129,7 @@ type NoHeadAccessDatabase interface {
|
||||
|
||||
// Custody operations.
|
||||
UpdateSubscribedToAllDataSubnets(ctx context.Context, subscribed bool) (bool, error)
|
||||
UpdateLiteSupernode(ctx context.Context, enabled bool) (bool, error)
|
||||
UpdateCustodyInfo(ctx context.Context, earliestAvailableSlot primitives.Slot, custodyGroupCount uint64) (primitives.Slot, uint64, error)
|
||||
UpdateEarliestAvailableSlot(ctx context.Context, earliestAvailableSlot primitives.Slot) error
|
||||
|
||||
|
||||
@@ -203,3 +203,61 @@ func (s *Store) UpdateSubscribedToAllDataSubnets(ctx context.Context, subscribed
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateLiteSupernode updates the "lite-supernode" status in the database
|
||||
// only if `enabled` is `true`.
|
||||
// It returns the previous lite-supernode status.
|
||||
func (s *Store) UpdateLiteSupernode(ctx context.Context, enabled bool) (bool, error) {
|
||||
_, span := trace.StartSpan(ctx, "BeaconDB.UpdateLiteSupernode")
|
||||
defer span.End()
|
||||
|
||||
result := false
|
||||
if !enabled {
|
||||
if err := s.db.View(func(tx *bolt.Tx) error {
|
||||
// Retrieve the custody bucket.
|
||||
bucket := tx.Bucket(custodyBucket)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Retrieve the lite-supernode flag.
|
||||
bytes := bucket.Get(liteSupernodeKey)
|
||||
if len(bytes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if bytes[0] == 1 {
|
||||
result = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if err := s.db.Update(func(tx *bolt.Tx) error {
|
||||
// Retrieve the custody bucket.
|
||||
bucket, err := tx.CreateBucketIfNotExists(custodyBucket)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create custody bucket")
|
||||
}
|
||||
|
||||
bytes := bucket.Get(liteSupernodeKey)
|
||||
if len(bytes) != 0 && bytes[0] == 1 {
|
||||
result = true
|
||||
}
|
||||
|
||||
if err := bucket.Put(liteSupernodeKey, []byte{1}); err != nil {
|
||||
return errors.Wrap(err, "put lite-supernode")
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -67,6 +67,29 @@ func getSubscriptionStatusFromDB(t *testing.T, db *Store) bool {
|
||||
return subscribed
|
||||
}
|
||||
|
||||
// getLiteSupernodeStatusFromDB reads the lite-supernode status directly from the database for testing purposes.
|
||||
func getLiteSupernodeStatusFromDB(t *testing.T, db *Store) bool {
|
||||
t.Helper()
|
||||
var enabled bool
|
||||
|
||||
err := db.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(custodyBucket)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bytes := bucket.Get(liteSupernodeKey)
|
||||
if len(bytes) != 0 && bytes[0] == 1 {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return enabled
|
||||
}
|
||||
|
||||
func TestUpdateCustodyInfo(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
@@ -302,3 +325,57 @@ func TestUpdateSubscribedToAllDataSubnets(t *testing.T) {
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateLiteSupernode(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("initial update with empty database - set to false", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, false, stored)
|
||||
})
|
||||
|
||||
t.Run("initial update with empty database - set to true", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
|
||||
t.Run("attempt to update from true to false (should not change)", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
_, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
|
||||
t.Run("update from true to true (no change)", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
_, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,4 +77,5 @@ var (
|
||||
groupCountKey = []byte("group-count")
|
||||
earliestAvailableSlotKey = []byte("earliest-available-slot")
|
||||
subscribeAllDataSubnetsKey = []byte("subscribe-all-data-subnets")
|
||||
liteSupernodeKey = []byte("lite-supernode")
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
@@ -184,13 +183,11 @@ func (s *Service) validateWithKzgBatchVerifier(ctx context.Context, dataColumns
|
||||
func (s *Service) validateUnbatchedColumnsKzg(ctx context.Context, columns []blocks.RODataColumn) (pubsub.ValidationResult, error) {
|
||||
_, span := trace.StartSpan(ctx, "sync.validateUnbatchedColumnsKzg")
|
||||
defer span.End()
|
||||
start := time.Now()
|
||||
if err := peerdas.VerifyDataColumnsSidecarKZGProofs(columns); err != nil {
|
||||
err = errors.Wrap(err, "could not verify")
|
||||
tracing.AnnotateError(span, err)
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
verification.DataColumnBatchKZGVerificationHistogram.WithLabelValues("fallback").Observe(float64(time.Since(start).Milliseconds()))
|
||||
return pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
@@ -205,12 +202,9 @@ func verifyKzgBatch(kzgBatch []*kzgVerifier) {
|
||||
}
|
||||
|
||||
var verificationErr error
|
||||
start := time.Now()
|
||||
err := peerdas.VerifyDataColumnsSidecarKZGProofs(allDataColumns)
|
||||
if err != nil {
|
||||
verificationErr = errors.Wrap(err, "batch KZG verification failed")
|
||||
} else {
|
||||
verification.DataColumnBatchKZGVerificationHistogram.WithLabelValues("batch").Observe(float64(time.Since(start).Milliseconds()))
|
||||
}
|
||||
|
||||
// Send the same result to all verifiers in the batch
|
||||
|
||||
@@ -96,9 +96,12 @@ func (s *Service) updateCustodyInfoIfNeeded() error {
|
||||
|
||||
// custodyGroupCount computes the custody group count based on the custody requirement,
|
||||
// the validators custody requirement, and whether the node is subscribed to all data subnets.
|
||||
// Note: Lite-supernode subscribes to 64 subnets (enough to reconstruct) but only custodies the minimum groups.
|
||||
func (s *Service) custodyGroupCount(context.Context) (uint64, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
|
||||
// Only supernode mode increases custody to all 128 groups.
|
||||
// Lite-supernode subscribes to 64 subnets but custodies the minimum.
|
||||
if flags.Get().SubscribeAllDataSubnets {
|
||||
return cfg.NumberOfCustodyGroups, nil
|
||||
}
|
||||
|
||||
@@ -697,10 +697,16 @@ func (s *Service) dataColumnSubnetIndices(primitives.Slot) map[uint64]bool {
|
||||
func (s *Service) samplingSize() (uint64, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
|
||||
// Supernode subscribes to all subnets.
|
||||
if flags.Get().SubscribeAllDataSubnets {
|
||||
return cfg.DataColumnSidecarSubnetCount, nil
|
||||
}
|
||||
|
||||
// Lite-supernode subscribes to half (64 subnets - minimum needed to reconstruct).
|
||||
if flags.Get().LiteSupernode {
|
||||
return cfg.DataColumnSidecarSubnetCount / 2, nil
|
||||
}
|
||||
|
||||
// Compute the validators custody requirement.
|
||||
validatorsCustodyRequirement, err := s.validatorsCustodyRequirement()
|
||||
if err != nil {
|
||||
|
||||
@@ -473,7 +473,7 @@ func (dv *RODataColumnsVerifier) SidecarKzgProofVerified() (err error) {
|
||||
return columnErrBuilder(errors.Wrap(err, "verify data column commitment"))
|
||||
}
|
||||
|
||||
DataColumnBatchKZGVerificationHistogram.WithLabelValues("direct").Observe(float64(time.Since(startTime).Milliseconds()))
|
||||
dataColumnBatchKZGVerificationHistogram.Observe(float64(time.Since(startTime).Milliseconds()))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,11 @@ var (
|
||||
Buckets: []float64{5, 10, 50, 100, 150, 250, 500, 1000, 2000},
|
||||
},
|
||||
)
|
||||
DataColumnBatchKZGVerificationHistogram = promauto.NewHistogramVec(
|
||||
dataColumnBatchKZGVerificationHistogram = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "beacon_kzg_verification_data_column_batch_milliseconds",
|
||||
Help: "Captures the time taken for batched data column kzg verification.",
|
||||
Buckets: []float64{5, 10, 50, 100, 150, 250, 500, 1000, 2000},
|
||||
},
|
||||
[]string{"path"},
|
||||
)
|
||||
)
|
||||
|
||||
2
changelog/james-prysm_lite-supernode.md
Normal file
2
changelog/james-prysm_lite-supernode.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Added
|
||||
- New flag `--lite-supernode` is an option to run the node with the minimum custody based on number of validators, but will subscribe to 64 subnets to obtain 64 data columns required to reconstruct all blobs.
|
||||
@@ -1,3 +0,0 @@
|
||||
### Ignored
|
||||
|
||||
- Copied deleted dependency `github.com/tyler-smith/go-bip39` to the third_party directory and updated prysm to use that.
|
||||
@@ -1,3 +0,0 @@
|
||||
### Added
|
||||
|
||||
- Record data column gossip KZG batch verification latency in both the pooled worker and fallback paths so the `beacon_kzg_verification_data_column_batch_milliseconds` histogram reflects gossip traffic, annotated with `path` labels to distinguish the sources.
|
||||
@@ -1,2 +0,0 @@
|
||||
### Fixed
|
||||
- Always emit payload attribute events whenever payload attributes exist, even if the EL omits a payload ID.
|
||||
@@ -339,6 +339,13 @@ var (
|
||||
Aliases: []string{"subscribe-all-data-subnets"},
|
||||
Usage: "Enable subscription to all data subnets and store all blob columns, serving them over RPC. Required post-Fusaka for full blob reconstruction. This is effectively one-way: once enabled, the node keeps storing and serving all columns even if the flag is later unset.",
|
||||
}
|
||||
// LiteSupernode enables lite-supernode mode: subscribe to 64 subnets and store 64 columns (minimum for reconstruction),
|
||||
// but only custody/serve the minimum 4 groups to peers.
|
||||
LiteSupernode = &cli.BoolFlag{
|
||||
Name: "lite-supernode",
|
||||
Usage: "Enable lite-supernode mode: subscribe to 64 data column subnets (enough to reconstruct), " +
|
||||
"but only custody and serve the minimum 4 groups to peers. Once set, you can only upgrade to full supernode, not downgrade.",
|
||||
}
|
||||
// BatchVerifierLimit sets the maximum number of signatures to batch verify at once.
|
||||
BatchVerifierLimit = &cli.IntFlag{
|
||||
Name: "batch-verifier-limit",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
type GlobalFlags struct {
|
||||
SubscribeToAllSubnets bool
|
||||
SubscribeAllDataSubnets bool
|
||||
LiteSupernode bool
|
||||
MinimumSyncPeers int
|
||||
MinimumPeersPerSubnet int
|
||||
MaxConcurrentDials int
|
||||
@@ -47,10 +48,15 @@ func ConfigureGlobalFlags(ctx *cli.Context) {
|
||||
}
|
||||
|
||||
if ctx.Bool(SubscribeAllDataSubnets.Name) {
|
||||
log.Warning("Subscribing to all data subnets")
|
||||
log.Warning("Subscribing to all data subnets (super-node mode: 128 custody groups)")
|
||||
cfg.SubscribeAllDataSubnets = true
|
||||
}
|
||||
|
||||
if ctx.Bool(LiteSupernode.Name) {
|
||||
log.Warning("Enabling lite-supernode mode (subscribe to 64 subnets, custody 4 groups)")
|
||||
cfg.LiteSupernode = true
|
||||
}
|
||||
|
||||
cfg.BlockBatchLimit = ctx.Int(BlockBatchLimit.Name)
|
||||
cfg.BlockBatchLimitBurstFactor = ctx.Int(BlockBatchLimitBurstFactor.Name)
|
||||
cfg.BlobBatchLimit = ctx.Int(BlobBatchLimit.Name)
|
||||
|
||||
@@ -66,6 +66,7 @@ var appFlags = []cli.Flag{
|
||||
flags.DisableDebugRPCEndpoints,
|
||||
flags.SubscribeToAllSubnets,
|
||||
flags.SubscribeAllDataSubnets,
|
||||
flags.LiteSupernode,
|
||||
flags.HistoricalSlasherNode,
|
||||
flags.ChainID,
|
||||
flags.NetworkID,
|
||||
|
||||
@@ -108,6 +108,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.MinSyncPeers,
|
||||
flags.SubscribeToAllSubnets,
|
||||
flags.SubscribeAllDataSubnets,
|
||||
flags.LiteSupernode,
|
||||
},
|
||||
},
|
||||
{ // Flags relevant to storing data on disk and configuring the beacon chain database.
|
||||
|
||||
@@ -15,8 +15,6 @@ go_library(
|
||||
"//config/features:go_default_library",
|
||||
"//io/prompt:go_default_library",
|
||||
"//runtime/tos:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//third_party/go-bip39/wordlists:go_default_library",
|
||||
"//validator/accounts:go_default_library",
|
||||
"//validator/accounts/userprompt:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
@@ -24,6 +22,8 @@ go_library(
|
||||
"@com_github_manifoldco_promptui//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//wordlists:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
42
deps.bzl
42
deps.bzl
@@ -3405,6 +3405,12 @@ def prysm_deps():
|
||||
sum = "h1:EBoYk5zHOfuHDBqLFx4eSPRVcbnW+L3aFJzoCi8zRnk=",
|
||||
version = "v0.0.0-20250212181730-4c2b8e9e784b",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_tyler_smith_go_bip39",
|
||||
importpath = "github.com/tyler-smith/go-bip39",
|
||||
sum = "h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=",
|
||||
version = "v1.1.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_ugorji_go_codec",
|
||||
importpath = "github.com/ugorji/go/codec",
|
||||
@@ -4778,8 +4784,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_crypto",
|
||||
importpath = "golang.org/x/crypto",
|
||||
sum = "h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=",
|
||||
version = "v0.44.0",
|
||||
sum = "h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=",
|
||||
version = "v0.43.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_exp",
|
||||
@@ -4814,14 +4820,14 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_mod",
|
||||
importpath = "golang.org/x/mod",
|
||||
sum = "h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=",
|
||||
version = "v0.30.0",
|
||||
sum = "h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=",
|
||||
version = "v0.29.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_net",
|
||||
importpath = "golang.org/x/net",
|
||||
sum = "h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=",
|
||||
version = "v0.47.0",
|
||||
sum = "h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=",
|
||||
version = "v0.46.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_oauth2",
|
||||
@@ -4838,32 +4844,32 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_sync",
|
||||
importpath = "golang.org/x/sync",
|
||||
sum = "h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=",
|
||||
version = "v0.18.0",
|
||||
sum = "h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=",
|
||||
version = "v0.17.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_sys",
|
||||
importpath = "golang.org/x/sys",
|
||||
sum = "h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=",
|
||||
version = "v0.38.0",
|
||||
sum = "h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=",
|
||||
version = "v0.37.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_telemetry",
|
||||
importpath = "golang.org/x/telemetry",
|
||||
sum = "h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=",
|
||||
version = "v0.0.0-20251111182119-bc8e575c7b54",
|
||||
sum = "h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=",
|
||||
version = "v0.0.0-20251008203120-078029d740a8",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_term",
|
||||
importpath = "golang.org/x/term",
|
||||
sum = "h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=",
|
||||
version = "v0.37.0",
|
||||
sum = "h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=",
|
||||
version = "v0.36.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_text",
|
||||
importpath = "golang.org/x/text",
|
||||
sum = "h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=",
|
||||
version = "v0.31.0",
|
||||
sum = "h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=",
|
||||
version = "v0.30.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_time",
|
||||
@@ -4874,8 +4880,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_tools",
|
||||
importpath = "golang.org/x/tools",
|
||||
sum = "h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=",
|
||||
version = "v0.39.0",
|
||||
sum = "h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=",
|
||||
version = "v0.38.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_tools_go_expect",
|
||||
|
||||
20
go.mod
20
go.mod
@@ -88,10 +88,10 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
go.uber.org/mock v0.5.2
|
||||
golang.org/x/crypto v0.44.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/tools v0.39.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/tools v0.38.0
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
|
||||
google.golang.org/grpc v1.71.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
@@ -263,12 +263,12 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/oauth2 v0.25.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
@@ -290,11 +290,9 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.13.0
|
||||
github.com/peterh/liner v1.2.0 // indirect
|
||||
github.com/prysmaticlabs/gohashtree v0.0.5-beta
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
k8s.io/klog/v2 v2.120.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
)
|
||||
|
||||
replace github.com/json-iterator/go => github.com/prestonvanloon/go v1.1.7-0.20190722034630-4f2e55fcf87b
|
||||
|
||||
replace github.com/tyler-smith/go-bip39 => ./third_party/go-bip39
|
||||
|
||||
38
go.sum
38
go.sum
@@ -1040,6 +1040,8 @@ github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDgu
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b h1:EBoYk5zHOfuHDBqLFx4eSPRVcbnW+L3aFJzoCi8zRnk=
|
||||
github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b/go.mod h1:4R6Qam+w871wOlyRq59zRLjhb5x9/De/wgPeaCTaCwI=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg=
|
||||
github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10/go.mod h1:x/Pa0FF5Te9kdrlZKJK82YmAkvL8+f989USgz6Jiw7M=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
@@ -1171,8 +1173,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1215,8 +1217,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1272,8 +1274,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1303,8 +1305,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1393,10 +1395,10 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -1405,8 +1407,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1421,8 +1423,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1495,8 +1497,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
14
third_party/go-bip39/BUILD.bazel
vendored
14
third_party/go-bip39/BUILD.bazel
vendored
@@ -1,14 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
# gazelle:prefix github.com/tyler-smith/go-bip39
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["bip39.go"],
|
||||
importpath = "github.com/tyler-smith/go-bip39",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//third_party/go-bip39/wordlists:go_default_library",
|
||||
"@org_golang_x_crypto//pbkdf2:go_default_library",
|
||||
],
|
||||
)
|
||||
21
third_party/go-bip39/LICENSE
vendored
21
third_party/go-bip39/LICENSE
vendored
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2018 Tyler Smith and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
45
third_party/go-bip39/README.md
vendored
45
third_party/go-bip39/README.md
vendored
@@ -1,45 +0,0 @@
|
||||
# go-bip39
|
||||
[](https://travis-ci.org/tyler-smith/go-bip39)
|
||||
[](https://github.com/tyler-smith/go-bip39/blob/master/LICENSE)
|
||||
[](http://godoc.org/github.com/tyler-smith/go-bip39)
|
||||
[](https://goreportcard.com/report/github.com/tyler-smith/go-bip39)
|
||||
[](https://github.com/tyler-smith/go-bip39/issues)
|
||||
|
||||
|
||||
A golang implementation of the BIP0039 spec for mnemonic seeds
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
"github.com/tyler-smith/go-bip32"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main(){
|
||||
// Generate a mnemonic for memorization or user-friendly seeds
|
||||
entropy, _ := bip39.NewEntropy(256)
|
||||
mnemonic, _ := bip39.NewMnemonic(entropy)
|
||||
|
||||
// Generate a Bip32 HD wallet for the mnemonic and a user supplied password
|
||||
seed := bip39.NewSeed(mnemonic, "Secret Passphrase")
|
||||
|
||||
masterKey, _ := bip32.NewMasterKey(seed)
|
||||
publicKey := masterKey.PublicKey()
|
||||
|
||||
// Display mnemonic and keys
|
||||
fmt.Println("Mnemonic: ", mnemonic)
|
||||
fmt.Println("Master private key: ", masterKey)
|
||||
fmt.Println("Master public key: ", publicKey)
|
||||
}
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
Wordlists are from the [bip39 spec](https://github.com/bitcoin/bips/tree/master/bip-0039).
|
||||
|
||||
Test vectors are from the standard Python BIP0039 implementation from the
|
||||
Trezor team: [https://github.com/trezor/python-mnemonic](https://github.com/trezor/python-mnemonic)
|
||||
360
third_party/go-bip39/bip39.go
vendored
360
third_party/go-bip39/bip39.go
vendored
@@ -1,360 +0,0 @@
|
||||
// Package bip39 is the Golang implementation of the BIP39 spec.
|
||||
//
|
||||
// The official BIP39 spec can be found at
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
|
||||
package bip39
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/tyler-smith/go-bip39/wordlists"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
var (
|
||||
// Some bitwise operands for working with big.Ints
|
||||
last11BitsMask = big.NewInt(2047)
|
||||
shift11BitsMask = big.NewInt(2048)
|
||||
bigOne = big.NewInt(1)
|
||||
bigTwo = big.NewInt(2)
|
||||
|
||||
// used to isolate the checksum bits from the entropy+checksum byte array
|
||||
wordLengthChecksumMasksMapping = map[int]*big.Int{
|
||||
12: big.NewInt(15),
|
||||
15: big.NewInt(31),
|
||||
18: big.NewInt(63),
|
||||
21: big.NewInt(127),
|
||||
24: big.NewInt(255),
|
||||
}
|
||||
// used to use only the desired x of 8 available checksum bits.
|
||||
// 256 bit (word length 24) requires all 8 bits of the checksum,
|
||||
// and thus no shifting is needed for it (we would get a divByZero crash if we did)
|
||||
wordLengthChecksumShiftMapping = map[int]*big.Int{
|
||||
12: big.NewInt(16),
|
||||
15: big.NewInt(8),
|
||||
18: big.NewInt(4),
|
||||
21: big.NewInt(2),
|
||||
}
|
||||
|
||||
// wordList is the set of words to use
|
||||
wordList []string
|
||||
|
||||
// wordMap is a reverse lookup map for wordList
|
||||
wordMap map[string]int
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidMnemonic is returned when trying to use a malformed mnemonic.
|
||||
ErrInvalidMnemonic = errors.New("Invalid mnenomic")
|
||||
|
||||
// ErrEntropyLengthInvalid is returned when trying to use an entropy set with
|
||||
// an invalid size.
|
||||
ErrEntropyLengthInvalid = errors.New("Entropy length must be [128, 256] and a multiple of 32")
|
||||
|
||||
// ErrValidatedSeedLengthMismatch is returned when a validated seed is not the
|
||||
// same size as the given seed. This should never happen is present only as a
|
||||
// sanity assertion.
|
||||
ErrValidatedSeedLengthMismatch = errors.New("Seed length does not match validated seed length")
|
||||
|
||||
// ErrChecksumIncorrect is returned when entropy has the incorrect checksum.
|
||||
ErrChecksumIncorrect = errors.New("Checksum incorrect")
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetWordList(wordlists.English)
|
||||
}
|
||||
|
||||
// SetWordList sets the list of words to use for mnemonics. Currently the list
|
||||
// that is set is used package-wide.
|
||||
func SetWordList(list []string) {
|
||||
wordList = list
|
||||
wordMap = map[string]int{}
|
||||
for i, v := range wordList {
|
||||
wordMap[v] = i
|
||||
}
|
||||
}
|
||||
|
||||
// GetWordList gets the list of words to use for mnemonics.
|
||||
func GetWordList() []string {
|
||||
return wordList
|
||||
}
|
||||
|
||||
// GetWordIndex gets word index in wordMap.
|
||||
func GetWordIndex(word string) (int, bool) {
|
||||
idx, ok := wordMap[word]
|
||||
return idx, ok
|
||||
}
|
||||
|
||||
// NewEntropy will create random entropy bytes
|
||||
// so long as the requested size bitSize is an appropriate size.
|
||||
//
|
||||
// bitSize has to be a multiple 32 and be within the inclusive range of {128, 256}
|
||||
func NewEntropy(bitSize int) ([]byte, error) {
|
||||
err := validateEntropyBitSize(bitSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entropy := make([]byte, bitSize/8)
|
||||
_, err = rand.Read(entropy)
|
||||
return entropy, err
|
||||
}
|
||||
|
||||
// EntropyFromMnemonic takes a mnemonic generated by this library,
|
||||
// and returns the input entropy used to generate the given mnemonic.
|
||||
// An error is returned if the given mnemonic is invalid.
|
||||
func EntropyFromMnemonic(mnemonic string) ([]byte, error) {
|
||||
mnemonicSlice, isValid := splitMnemonicWords(mnemonic)
|
||||
if !isValid {
|
||||
return nil, ErrInvalidMnemonic
|
||||
}
|
||||
|
||||
// Decode the words into a big.Int.
|
||||
b := big.NewInt(0)
|
||||
for _, v := range mnemonicSlice {
|
||||
index, found := wordMap[v]
|
||||
if found == false {
|
||||
return nil, fmt.Errorf("word `%v` not found in reverse map", v)
|
||||
}
|
||||
var wordBytes [2]byte
|
||||
binary.BigEndian.PutUint16(wordBytes[:], uint16(index))
|
||||
b = b.Mul(b, shift11BitsMask)
|
||||
b = b.Or(b, big.NewInt(0).SetBytes(wordBytes[:]))
|
||||
}
|
||||
|
||||
// Build and add the checksum to the big.Int.
|
||||
checksum := big.NewInt(0)
|
||||
checksumMask := wordLengthChecksumMasksMapping[len(mnemonicSlice)]
|
||||
checksum = checksum.And(b, checksumMask)
|
||||
|
||||
b.Div(b, big.NewInt(0).Add(checksumMask, bigOne))
|
||||
|
||||
// The entropy is the underlying bytes of the big.Int. Any upper bytes of
|
||||
// all 0's are not returned so we pad the beginning of the slice with empty
|
||||
// bytes if necessary.
|
||||
entropy := b.Bytes()
|
||||
entropy = padByteSlice(entropy, len(mnemonicSlice)/3*4)
|
||||
|
||||
// Generate the checksum and compare with the one we got from the mneomnic.
|
||||
entropyChecksumBytes := computeChecksum(entropy)
|
||||
entropyChecksum := big.NewInt(int64(entropyChecksumBytes[0]))
|
||||
if l := len(mnemonicSlice); l != 24 {
|
||||
checksumShift := wordLengthChecksumShiftMapping[l]
|
||||
entropyChecksum.Div(entropyChecksum, checksumShift)
|
||||
}
|
||||
|
||||
if checksum.Cmp(entropyChecksum) != 0 {
|
||||
return nil, ErrChecksumIncorrect
|
||||
}
|
||||
|
||||
return entropy, nil
|
||||
}
|
||||
|
||||
// NewMnemonic will return a string consisting of the mnemonic words for
|
||||
// the given entropy.
|
||||
// If the provide entropy is invalid, an error will be returned.
|
||||
func NewMnemonic(entropy []byte) (string, error) {
|
||||
// Compute some lengths for convenience.
|
||||
entropyBitLength := len(entropy) * 8
|
||||
checksumBitLength := entropyBitLength / 32
|
||||
sentenceLength := (entropyBitLength + checksumBitLength) / 11
|
||||
|
||||
// Validate that the requested size is supported.
|
||||
err := validateEntropyBitSize(entropyBitLength)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Add checksum to entropy.
|
||||
entropy = addChecksum(entropy)
|
||||
|
||||
// Break entropy up into sentenceLength chunks of 11 bits.
|
||||
// For each word AND mask the rightmost 11 bits and find the word at that index.
|
||||
// Then bitshift entropy 11 bits right and repeat.
|
||||
// Add to the last empty slot so we can work with LSBs instead of MSB.
|
||||
|
||||
// Entropy as an int so we can bitmask without worrying about bytes slices.
|
||||
entropyInt := new(big.Int).SetBytes(entropy)
|
||||
|
||||
// Slice to hold words in.
|
||||
words := make([]string, sentenceLength)
|
||||
|
||||
// Throw away big.Int for AND masking.
|
||||
word := big.NewInt(0)
|
||||
|
||||
for i := sentenceLength - 1; i >= 0; i-- {
|
||||
// Get 11 right most bits and bitshift 11 to the right for next time.
|
||||
word.And(entropyInt, last11BitsMask)
|
||||
entropyInt.Div(entropyInt, shift11BitsMask)
|
||||
|
||||
// Get the bytes representing the 11 bits as a 2 byte slice.
|
||||
wordBytes := padByteSlice(word.Bytes(), 2)
|
||||
|
||||
// Convert bytes to an index and add that word to the list.
|
||||
words[i] = wordList[binary.BigEndian.Uint16(wordBytes)]
|
||||
}
|
||||
|
||||
return strings.Join(words, " "), nil
|
||||
}
|
||||
|
||||
// MnemonicToByteArray takes a mnemonic string and turns it into a byte array
|
||||
// suitable for creating another mnemonic.
|
||||
// An error is returned if the mnemonic is invalid.
|
||||
func MnemonicToByteArray(mnemonic string, raw ...bool) ([]byte, error) {
|
||||
var (
|
||||
mnemonicSlice = strings.Split(mnemonic, " ")
|
||||
entropyBitSize = len(mnemonicSlice) * 11
|
||||
checksumBitSize = entropyBitSize % 32
|
||||
fullByteSize = (entropyBitSize-checksumBitSize)/8 + 1
|
||||
checksumByteSize = fullByteSize - (fullByteSize % 4)
|
||||
)
|
||||
|
||||
// Pre validate that the mnemonic is well formed and only contains words that
|
||||
// are present in the word list.
|
||||
if !IsMnemonicValid(mnemonic) {
|
||||
return nil, ErrInvalidMnemonic
|
||||
}
|
||||
|
||||
// Convert word indices to a big.Int representing the entropy.
|
||||
checksummedEntropy := big.NewInt(0)
|
||||
modulo := big.NewInt(2048)
|
||||
for _, v := range mnemonicSlice {
|
||||
index := big.NewInt(int64(wordMap[v]))
|
||||
checksummedEntropy.Mul(checksummedEntropy, modulo)
|
||||
checksummedEntropy.Add(checksummedEntropy, index)
|
||||
}
|
||||
|
||||
// Calculate the unchecksummed entropy so we can validate that the checksum is
|
||||
// correct.
|
||||
checksumModulo := big.NewInt(0).Exp(bigTwo, big.NewInt(int64(checksumBitSize)), nil)
|
||||
rawEntropy := big.NewInt(0).Div(checksummedEntropy, checksumModulo)
|
||||
|
||||
// Convert big.Ints to byte padded byte slices.
|
||||
rawEntropyBytes := padByteSlice(rawEntropy.Bytes(), checksumByteSize)
|
||||
checksummedEntropyBytes := padByteSlice(checksummedEntropy.Bytes(), fullByteSize)
|
||||
|
||||
// Validate that the checksum is correct.
|
||||
newChecksummedEntropyBytes := padByteSlice(addChecksum(rawEntropyBytes), fullByteSize)
|
||||
if !compareByteSlices(checksummedEntropyBytes, newChecksummedEntropyBytes) {
|
||||
return nil, ErrChecksumIncorrect
|
||||
}
|
||||
|
||||
if len(raw) > 0 && raw[0] {
|
||||
return rawEntropyBytes, nil
|
||||
}
|
||||
|
||||
return checksummedEntropyBytes, nil
|
||||
}
|
||||
|
||||
// NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
|
||||
// An error is returned if the mnemonic is not convertible to a byte array.
|
||||
func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) {
|
||||
_, err := MnemonicToByteArray(mnemonic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewSeed(mnemonic, password), nil
|
||||
}
|
||||
|
||||
// NewSeed creates a hashed seed output given a provided string and password.
|
||||
// No checking is performed to validate that the string provided is a valid mnemonic.
|
||||
func NewSeed(mnemonic string, password string) []byte {
|
||||
return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
|
||||
}
|
||||
|
||||
// IsMnemonicValid attempts to verify that the provided mnemonic is valid.
|
||||
// Validity is determined by both the number of words being appropriate,
|
||||
// and that all the words in the mnemonic are present in the word list.
|
||||
func IsMnemonicValid(mnemonic string) bool {
|
||||
_, err := EntropyFromMnemonic(mnemonic)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Appends to data the first (len(data) / 32)bits of the result of sha256(data)
|
||||
// Currently only supports data up to 32 bytes
|
||||
func addChecksum(data []byte) []byte {
|
||||
// Get first byte of sha256
|
||||
hash := computeChecksum(data)
|
||||
firstChecksumByte := hash[0]
|
||||
|
||||
// len() is in bytes so we divide by 4
|
||||
checksumBitLength := uint(len(data) / 4)
|
||||
|
||||
// For each bit of check sum we want we shift the data one the left
|
||||
// and then set the (new) right most bit equal to checksum bit at that index
|
||||
// staring from the left
|
||||
dataBigInt := new(big.Int).SetBytes(data)
|
||||
for i := range checksumBitLength {
|
||||
// Bitshift 1 left
|
||||
dataBigInt.Mul(dataBigInt, bigTwo)
|
||||
|
||||
// Set rightmost bit if leftmost checksum bit is set
|
||||
if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
|
||||
dataBigInt.Or(dataBigInt, bigOne)
|
||||
}
|
||||
}
|
||||
|
||||
return dataBigInt.Bytes()
|
||||
}
|
||||
|
||||
func computeChecksum(data []byte) []byte {
|
||||
hasher := sha256.New()
|
||||
hasher.Write(data)
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
// validateEntropyBitSize ensures that entropy is the correct size for being a
|
||||
// mnemonic.
|
||||
func validateEntropyBitSize(bitSize int) error {
|
||||
if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
|
||||
return ErrEntropyLengthInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// padByteSlice returns a byte slice of the given size with contents of the
|
||||
// given slice left padded and any empty spaces filled with 0's.
|
||||
func padByteSlice(slice []byte, length int) []byte {
|
||||
offset := length - len(slice)
|
||||
if offset <= 0 {
|
||||
return slice
|
||||
}
|
||||
newSlice := make([]byte, length)
|
||||
copy(newSlice[offset:], slice)
|
||||
return newSlice
|
||||
}
|
||||
|
||||
// compareByteSlices returns true of the byte slices have equal contents and
|
||||
// returns false otherwise.
|
||||
func compareByteSlices(a, b []byte) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func splitMnemonicWords(mnemonic string) ([]string, bool) {
|
||||
// Create a list of all the words in the mnemonic sentence
|
||||
words := strings.Fields(mnemonic)
|
||||
|
||||
// Get num of words
|
||||
numOfWords := len(words)
|
||||
|
||||
// The number of words should be 12, 15, 18, 21 or 24
|
||||
if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {
|
||||
return nil, false
|
||||
}
|
||||
return words, true
|
||||
}
|
||||
5
third_party/go-bip39/go.mod
vendored
5
third_party/go-bip39/go.mod
vendored
@@ -1,5 +0,0 @@
|
||||
module github.com/tyler-smith/go-bip39
|
||||
|
||||
go 1.25
|
||||
|
||||
require golang.org/x/crypto v0.40.0
|
||||
20
third_party/go-bip39/wordlists/BUILD.bazel
vendored
20
third_party/go-bip39/wordlists/BUILD.bazel
vendored
@@ -1,20 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
# gazelle:prefix github.com/tyler-smith/go-bip39/wordlists
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"chinese_simplified.go",
|
||||
"chinese_traditional.go",
|
||||
"czech.go",
|
||||
"english.go",
|
||||
"french.go",
|
||||
"italian.go",
|
||||
"japanese.go",
|
||||
"korean.go",
|
||||
"spanish.go",
|
||||
],
|
||||
importpath = "github.com/tyler-smith/go-bip39/wordlists",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
2071
third_party/go-bip39/wordlists/chinese_simplified.go
vendored
2071
third_party/go-bip39/wordlists/chinese_simplified.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/chinese_traditional.go
vendored
2071
third_party/go-bip39/wordlists/chinese_traditional.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/czech.go
vendored
2071
third_party/go-bip39/wordlists/czech.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/english.go
vendored
2071
third_party/go-bip39/wordlists/english.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/french.go
vendored
2071
third_party/go-bip39/wordlists/french.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/italian.go
vendored
2071
third_party/go-bip39/wordlists/italian.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/japanese.go
vendored
2071
third_party/go-bip39/wordlists/japanese.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/korean.go
vendored
2071
third_party/go-bip39/wordlists/korean.go
vendored
File diff suppressed because it is too large
Load Diff
2071
third_party/go-bip39/wordlists/spanish.go
vendored
2071
third_party/go-bip39/wordlists/spanish.go
vendored
File diff suppressed because it is too large
Load Diff
@@ -8,11 +8,11 @@ go_library(
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//io/file:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_util//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -149,7 +149,6 @@ go_test(
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"//testing/validator-mock:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"//validator/accounts/testing:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
@@ -172,6 +171,7 @@ go_test(
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@com_github_stretchr_testify//assert:go_default_library",
|
||||
"@com_github_stretchr_testify//require:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_util//:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
|
||||
@@ -20,14 +20,14 @@ go_library(
|
||||
"//crypto/rand:go_default_library",
|
||||
"//io/prompt:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//third_party/go-bip39/wordlists:go_default_library",
|
||||
"//validator/accounts/iface:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"@com_github_logrusorgru_aurora//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//wordlists:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_util//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -47,11 +47,11 @@ go_test(
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//third_party/go-bip39/wordlists:go_default_library",
|
||||
"//validator/accounts/testing:go_default_library",
|
||||
"//validator/testing:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//wordlists:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_util//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -49,8 +49,6 @@ go_library(
|
||||
"//network/httputil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//third_party/go-bip39/wordlists:go_default_library",
|
||||
"//validator/accounts:go_default_library",
|
||||
"//validator/accounts/petnames:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
@@ -78,6 +76,8 @@ go_library(
|
||||
"@com_github_grpc_ecosystem_go_grpc_prometheus//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//wordlists:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library",
|
||||
"@io_opentelemetry_go_contrib_instrumentation_net_http_otelhttp//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
@@ -124,7 +124,6 @@ go_test(
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/validator-mock:go_default_library",
|
||||
"//third_party/go-bip39:go_default_library",
|
||||
"//validator/accounts:go_default_library",
|
||||
"//validator/accounts/iface:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
@@ -147,6 +146,7 @@ go_test(
|
||||
"@com_github_google_uuid//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@com_github_tyler_smith_go_bip39//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
|
||||
Reference in New Issue
Block a user