From b0f3288b51931134b5665b48ed1a1a877f0c9b06 Mon Sep 17 00:00:00 2001 From: Ian Shim <100327837+ian-shim@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:03:38 -0800 Subject: [PATCH 01/15] [v2] Read blob version params from chain (#922) --- common/read_only_map.go | 26 ++++++ common/read_only_map_test.go | 31 +++++++ core/chainio.go | 6 ++ core/data.go | 6 ++ core/eth/reader.go | 36 ++++++++ core/mock/v2/validator.go | 2 +- core/mock/writer.go | 15 +++ core/v2/assignment.go | 39 ++++---- core/v2/assignment_test.go | 58 +++--------- core/v2/blob_params.go | 12 +++ core/v2/core_test.go | 18 +++- core/v2/types.go | 29 +----- core/v2/validator.go | 91 +++++++++++-------- disperser/apiserver/disperse_blob_v2.go | 37 ++++---- disperser/apiserver/server_v2.go | 24 +++-- disperser/apiserver/server_v2_test.go | 8 ++ disperser/cmd/controller/config.go | 17 ++-- disperser/cmd/controller/flags/flags.go | 8 ++ disperser/controller/encoding_manager.go | 58 +++++++++++- disperser/controller/encoding_manager_test.go | 32 +++++-- disperser/encoder/server_v2_test.go | 12 ++- node/config.go | 4 +- node/flags/flags.go | 8 ++ node/grpc/server_v2_test.go | 12 +++ node/node.go | 89 ++++++++++++++---- node/node_test.go | 34 ++++--- node/node_v2.go | 14 ++- node/node_v2_test.go | 33 +++++++ relay/cmd/config.go | 8 +- relay/cmd/flags/flags.go | 11 ++- relay/cmd/main.go | 43 ++++----- relay/metadata_provider.go | 23 ++++- relay/metadata_provider_test.go | 10 +- relay/relay_test_utils.go | 21 +++++ relay/server.go | 50 +++++++++- relay/server_test.go | 28 ++++-- 36 files changed, 693 insertions(+), 260 deletions(-) create mode 100644 common/read_only_map.go create mode 100644 common/read_only_map_test.go create mode 100644 core/v2/blob_params.go diff --git a/common/read_only_map.go b/common/read_only_map.go new file mode 100644 index 0000000000..3e6e097054 --- /dev/null +++ b/common/read_only_map.go @@ -0,0 +1,26 @@ +package common + +type ReadOnlyMap[K comparable, V any] struct { + data map[K]V +} + +func NewReadOnlyMap[K comparable, V any](data map[K]V) *ReadOnlyMap[K, V] { + return &ReadOnlyMap[K, V]{data: data} +} + +func (m *ReadOnlyMap[K, V]) Get(key K) (V, bool) { + value, ok := m.data[key] + return value, ok +} + +func (m *ReadOnlyMap[K, V]) Keys() []K { + keys := make([]K, 0, len(m.data)) + for key := range m.data { + keys = append(keys, key) + } + return keys +} + +func (m *ReadOnlyMap[K, V]) Len() int { + return len(m.data) +} diff --git a/common/read_only_map_test.go b/common/read_only_map_test.go new file mode 100644 index 0000000000..8c1716eda3 --- /dev/null +++ b/common/read_only_map_test.go @@ -0,0 +1,31 @@ +package common_test + +import ( + "testing" + + "github.com/Layr-Labs/eigenda/common" + "github.com/stretchr/testify/require" +) + +func TestReadOnlyMap(t *testing.T) { + data := map[uint8]string{ + 1: "one", + 2: "two", + 3: "three", + } + m := common.NewReadOnlyMap(data) + res, ok := m.Get(1) + require.True(t, ok) + require.Equal(t, "one", res) + res, ok = m.Get(2) + require.True(t, ok) + require.Equal(t, "two", res) + res, ok = m.Get(3) + require.True(t, ok) + require.Equal(t, "three", res) + res, ok = m.Get(4) + require.False(t, ok) + require.Equal(t, "", res) + require.Equal(t, 3, m.Len()) + require.ElementsMatch(t, []uint8{1, 2, 3}, m.Keys()) +} diff --git a/core/chainio.go b/core/chainio.go index 6d820d6295..340e9e6b18 100644 --- a/core/chainio.go +++ b/core/chainio.go @@ -100,6 +100,12 @@ type Reader interface { // GetRequiredQuorumNumbers returns set of required quorum numbers GetRequiredQuorumNumbers(ctx context.Context, blockNumber uint32) ([]QuorumID, error) + // GetVersionedBlobParams returns the blob version parameters for the given block number and blob version. + GetVersionedBlobParams(ctx context.Context, blobVersion uint8) (*BlobVersionParameters, error) + + // GetAllVersionedBlobParams returns the blob version parameters for all blob versions at the given block number. + GetAllVersionedBlobParams(ctx context.Context) (map[uint8]*BlobVersionParameters, error) + // GetActiveReservations returns active reservations (end timestamp > current timestamp) GetActiveReservations(ctx context.Context, blockNumber uint32, accountIDs []string) (map[string]ActiveReservation, error) diff --git a/core/data.go b/core/data.go index 61f6be0e77..4303056902 100644 --- a/core/data.go +++ b/core/data.go @@ -612,3 +612,9 @@ type ActiveReservation struct { type OnDemandPayment struct { CumulativePayment *big.Int // Total amount deposited by the user } + +type BlobVersionParameters struct { + CodingRate uint32 + MaxNumOperators uint32 + NumChunks uint32 +} diff --git a/core/eth/reader.go b/core/eth/reader.go index b5bafca3c6..3f47e3c3cb 100644 --- a/core/eth/reader.go +++ b/core/eth/reader.go @@ -4,6 +4,7 @@ import ( "context" "crypto/ecdsa" "math/big" + "strings" "github.com/Layr-Labs/eigenda/common" avsdir "github.com/Layr-Labs/eigenda/contracts/bindings/AVSDirectory" @@ -580,6 +581,41 @@ func (t *Reader) GetRequiredQuorumNumbers(ctx context.Context, blockNumber uint3 return requiredQuorums, nil } +func (t *Reader) GetVersionedBlobParams(ctx context.Context, blobVersion uint8) (*core.BlobVersionParameters, error) { + params, err := t.bindings.EigenDAServiceManager.GetBlobParams(&bind.CallOpts{ + Context: ctx, + }, uint16(blobVersion)) + if err != nil { + return nil, err + } + return &core.BlobVersionParameters{ + CodingRate: uint32(params.CodingRate), + NumChunks: uint32(params.NumChunks), + MaxNumOperators: uint32(params.MaxNumOperators), + }, nil +} + +func (t *Reader) GetAllVersionedBlobParams(ctx context.Context) (map[uint8]*core.BlobVersionParameters, error) { + res := make(map[uint8]*core.BlobVersionParameters) + version := uint8(0) + for { + params, err := t.GetVersionedBlobParams(ctx, version) + if err != nil && strings.Contains(err.Error(), "execution reverted") { + break + } else if err != nil { + return nil, err + } + res[version] = params + version++ + } + + if len(res) == 0 { + return nil, errors.New("no blob version parameters found") + } + + return res, nil +} + func (t *Reader) GetActiveReservations(ctx context.Context, blockNumber uint32, accountIDs []string) (map[string]core.ActiveReservation, error) { // contract is not implemented yet return map[string]core.ActiveReservation{}, nil diff --git a/core/mock/v2/validator.go b/core/mock/v2/validator.go index 591257a97c..e819c808b9 100644 --- a/core/mock/v2/validator.go +++ b/core/mock/v2/validator.go @@ -25,7 +25,7 @@ func (v *MockShardValidator) ValidateBatchHeader(ctx context.Context, header *co return args.Error(0) } -func (v *MockShardValidator) ValidateBlobs(ctx context.Context, blobs []*corev2.BlobShard, pool common.WorkerPool, state *core.OperatorState) error { +func (v *MockShardValidator) ValidateBlobs(ctx context.Context, blobs []*corev2.BlobShard, blobVersionParams *corev2.BlobVersionParameterMap, pool common.WorkerPool, state *core.OperatorState) error { args := v.Called() return args.Error(0) } diff --git a/core/mock/writer.go b/core/mock/writer.go index cd7f9a78f5..b700b8cd71 100644 --- a/core/mock/writer.go +++ b/core/mock/writer.go @@ -197,6 +197,21 @@ func (t *MockWriter) GetRequiredQuorumNumbers(ctx context.Context, blockNumber u return result.([]uint8), args.Error(1) } +func (t *MockWriter) GetVersionedBlobParams(ctx context.Context, blobVersion uint8) (*core.BlobVersionParameters, error) { + args := t.Called() + if args.Get(0) == nil { + return nil, args.Error(1) + } + result := args.Get(0) + return result.(*core.BlobVersionParameters), args.Error(1) +} + +func (t *MockWriter) GetAllVersionedBlobParams(ctx context.Context) (map[uint8]*core.BlobVersionParameters, error) { + args := t.Called() + result := args.Get(0) + return result.(map[uint8]*core.BlobVersionParameters), args.Error(1) +} + func (t *MockWriter) PubkeyHashToOperator(ctx context.Context, operatorId core.OperatorID) (gethcommon.Address, error) { args := t.Called() result := args.Get(0) diff --git a/core/v2/assignment.go b/core/v2/assignment.go index 53e6b96fb9..320406a18d 100644 --- a/core/v2/assignment.go +++ b/core/v2/assignment.go @@ -8,11 +8,9 @@ import ( "github.com/Layr-Labs/eigenda/core" ) -func GetAssignments(state *core.OperatorState, blobVersion BlobVersion, quorum uint8) (map[core.OperatorID]Assignment, error) { - - params, ok := ParametersMap[blobVersion] - if !ok { - return nil, fmt.Errorf("blob version %d not found", blobVersion) +func GetAssignments(state *core.OperatorState, blobParams *core.BlobVersionParameters, quorum uint8) (map[core.OperatorID]Assignment, error) { + if blobParams == nil { + return nil, fmt.Errorf("blob params cannot be nil") } ops, ok := state.Operators[quorum] @@ -20,12 +18,12 @@ func GetAssignments(state *core.OperatorState, blobVersion BlobVersion, quorum u return nil, fmt.Errorf("no operators found for quorum %d", quorum) } - if len(ops) > int(params.MaxNumOperators()) { - return nil, fmt.Errorf("too many operators for blob version %d", blobVersion) + if uint32(len(ops)) > blobParams.MaxNumOperators { + return nil, fmt.Errorf("too many operators (%d) to get assignments: max number of operators is %d", len(ops), blobParams.MaxNumOperators) } numOperators := big.NewInt(int64(len(ops))) - numChunks := big.NewInt(int64(params.NumChunks)) + numChunks := big.NewInt(int64(blobParams.NumChunks)) type assignment struct { id core.OperatorID @@ -58,9 +56,9 @@ func GetAssignments(state *core.OperatorState, blobVersion BlobVersion, quorum u mp += int(a.chunks) } - delta := int(params.NumChunks) - mp + delta := int(blobParams.NumChunks) - mp if delta < 0 { - return nil, fmt.Errorf("total chunks %d exceeds maximum %d", mp, params.NumChunks) + return nil, fmt.Errorf("total chunks %d exceeds maximum %d", mp, blobParams.NumChunks) } assignments := make(map[core.OperatorID]Assignment, len(chunkAssignments)) @@ -81,9 +79,11 @@ func GetAssignments(state *core.OperatorState, blobVersion BlobVersion, quorum u } -func GetAssignment(state *core.OperatorState, blobVersion BlobVersion, quorum core.QuorumID, id core.OperatorID) (Assignment, error) { - - assignments, err := GetAssignments(state, blobVersion, quorum) +func GetAssignment(state *core.OperatorState, blobParams *core.BlobVersionParameters, quorum core.QuorumID, id core.OperatorID) (Assignment, error) { + if blobParams == nil { + return Assignment{}, fmt.Errorf("blob params cannot be nil") + } + assignments, err := GetAssignments(state, blobParams, quorum) if err != nil { return Assignment{}, err } @@ -96,22 +96,21 @@ func GetAssignment(state *core.OperatorState, blobVersion BlobVersion, quorum co return assignment, nil } -func GetChunkLength(blobVersion BlobVersion, blobLength uint32) (uint32, error) { - +func GetChunkLength(blobLength uint32, blobParams *core.BlobVersionParameters) (uint32, error) { if blobLength == 0 { return 0, fmt.Errorf("blob length must be greater than 0") } + if blobParams == nil { + return 0, fmt.Errorf("blob params cannot be nil") + } + // Check that the blob length is a power of 2 if blobLength&(blobLength-1) != 0 { return 0, fmt.Errorf("blob length %d is not a power of 2", blobLength) } - if _, ok := ParametersMap[blobVersion]; !ok { - return 0, fmt.Errorf("blob version %d not found", blobVersion) - } - - chunkLength := blobLength * ParametersMap[blobVersion].CodingRate / ParametersMap[blobVersion].NumChunks + chunkLength := blobLength * blobParams.CodingRate / blobParams.NumChunks if chunkLength == 0 { chunkLength = 1 } diff --git a/core/v2/assignment_test.go b/core/v2/assignment_test.go index d8b5d2da81..5062f219ad 100644 --- a/core/v2/assignment_test.go +++ b/core/v2/assignment_test.go @@ -11,18 +11,12 @@ import ( "github.com/stretchr/testify/assert" ) -const ( - maxNumOperators = 3537 -) - func TestOperatorAssignmentsV2(t *testing.T) { state := dat.GetTotalOperatorState(context.Background(), 0) operatorState := state.OperatorState - blobVersion := corev2.BlobVersion(0) - - assignments, err := corev2.GetAssignments(operatorState, blobVersion, 0) + assignments, err := corev2.GetAssignments(operatorState, blobParams, 0) assert.NoError(t, err) expectedAssignments := map[core.OperatorID]corev2.Assignment{ mock.MakeOperatorId(0): { @@ -55,7 +49,7 @@ func TestOperatorAssignmentsV2(t *testing.T) { assert.Equal(t, assignment, expectedAssignments[operatorID]) - assignment, err := corev2.GetAssignment(operatorState, blobVersion, 0, operatorID) + assignment, err := corev2.GetAssignment(operatorState, blobParams, 0, operatorID) assert.NoError(t, err) assert.Equal(t, assignment, expectedAssignments[operatorID]) @@ -64,20 +58,14 @@ func TestOperatorAssignmentsV2(t *testing.T) { } -func TestMaxNumOperators(t *testing.T) { - - assert.Equal(t, corev2.ParametersMap[0].MaxNumOperators(), uint32(maxNumOperators)) - -} - func TestAssignmentWithTooManyOperators(t *testing.T) { - numOperators := maxNumOperators + 1 + numOperators := blobParams.MaxNumOperators + 1 stakes := map[core.QuorumID]map[core.OperatorID]int{ 0: {}, } - for i := 0; i < numOperators; i++ { + for i := 0; i < int(numOperators); i++ { stakes[0][mock.MakeOperatorId(i)] = rand.Intn(100) + 1 } @@ -88,11 +76,9 @@ func TestAssignmentWithTooManyOperators(t *testing.T) { state := dat.GetTotalOperatorState(context.Background(), 0) - assert.Equal(t, len(state.Operators[0]), numOperators) - - blobVersion := corev2.BlobVersion(0) + assert.Equal(t, len(state.Operators[0]), int(numOperators)) - _, err = corev2.GetAssignments(state.OperatorState, blobVersion, 0) + _, err = corev2.GetAssignments(state.OperatorState, blobParams, 0) assert.Error(t, err) } @@ -110,7 +96,7 @@ func FuzzOperatorAssignmentsV2(f *testing.F) { } for i := 0; i < 5; i++ { - f.Add(maxNumOperators) + f.Add(int(blobParams.MaxNumOperators)) } f.Fuzz(func(t *testing.T, numOperators int) { @@ -131,9 +117,7 @@ func FuzzOperatorAssignmentsV2(f *testing.F) { state := dat.GetTotalOperatorState(context.Background(), 0) - blobVersion := corev2.BlobVersion(0) - - assignments, err := corev2.GetAssignments(state.OperatorState, blobVersion, 0) + assignments, err := corev2.GetAssignments(state.OperatorState, blobParams, 0) assert.NoError(t, err) // Check that the total number of chunks is correct @@ -141,7 +125,7 @@ func FuzzOperatorAssignmentsV2(f *testing.F) { for _, assignment := range assignments { totalChunks += assignment.NumChunks } - assert.Equal(t, totalChunks, corev2.ParametersMap[blobVersion].NumChunks) + assert.Equal(t, totalChunks, blobParams.NumChunks) // Check that each operator's assignment satisfies the security requirement for operatorID, assignment := range assignments { @@ -149,21 +133,16 @@ func FuzzOperatorAssignmentsV2(f *testing.F) { totalStake := uint32(state.Totals[0].Stake.Uint64()) myStake := uint32(state.Operators[0][operatorID].Stake.Uint64()) - LHS := assignment.NumChunks * totalStake * corev2.ParametersMap[blobVersion].CodingRate * uint32(corev2.ParametersMap[blobVersion].ReconstructionThreshold*100) - RHS := 100 * myStake * corev2.ParametersMap[blobVersion].NumChunks + reconstructionThreshold := 0.22 + LHS := assignment.NumChunks * totalStake * blobParams.CodingRate * uint32(reconstructionThreshold*100) + RHS := 100 * myStake * blobParams.NumChunks assert.GreaterOrEqual(t, LHS, RHS) - } - }) - } func TestChunkLength(t *testing.T) { - - blobVersion := corev2.BlobVersion(0) - pairs := []struct { blobLength uint32 chunkLength uint32 @@ -176,20 +155,13 @@ func TestChunkLength(t *testing.T) { } for _, pair := range pairs { - - chunkLength, err := corev2.GetChunkLength(blobVersion, pair.blobLength) - + chunkLength, err := corev2.GetChunkLength(pair.blobLength, blobParams) assert.NoError(t, err) - assert.Equal(t, pair.chunkLength, chunkLength) } - } func TestInvalidChunkLength(t *testing.T) { - - blobVersion := corev2.BlobVersion(0) - invalidLengths := []uint32{ 0, 3, @@ -212,9 +184,7 @@ func TestInvalidChunkLength(t *testing.T) { } for _, length := range invalidLengths { - - _, err := corev2.GetChunkLength(blobVersion, length) + _, err := corev2.GetChunkLength(length, blobParams) assert.Error(t, err) } - } diff --git a/core/v2/blob_params.go b/core/v2/blob_params.go new file mode 100644 index 0000000000..5b16a61295 --- /dev/null +++ b/core/v2/blob_params.go @@ -0,0 +1,12 @@ +package v2 + +import ( + "github.com/Layr-Labs/eigenda/common" + "github.com/Layr-Labs/eigenda/core" +) + +type BlobVersionParameterMap = common.ReadOnlyMap[BlobVersion, *core.BlobVersionParameters] + +func NewBlobVersionParameterMap(params map[BlobVersion]*core.BlobVersionParameters) *BlobVersionParameterMap { + return common.NewReadOnlyMap(params) +} diff --git a/core/v2/core_test.go b/core/v2/core_test.go index 54f4e02e45..ebc6eadb77 100644 --- a/core/v2/core_test.go +++ b/core/v2/core_test.go @@ -12,6 +12,7 @@ import ( "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/core/mock" corev2 "github.com/Layr-Labs/eigenda/core/v2" + v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/encoding" "github.com/Layr-Labs/eigenda/encoding/kzg" "github.com/Layr-Labs/eigenda/encoding/kzg/prover" @@ -32,6 +33,15 @@ var ( v encoding.Verifier GETTYSBURG_ADDRESS_BYTES = []byte("Fourscore and seven years ago our fathers brought forth, on this continent, a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived, and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting-place for those who here gave their lives, that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we cannot dedicate, we cannot consecrate—we cannot hallow—this ground. The brave men, living and dead, who struggled here, have consecrated it far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they here gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom, and that government of the people, by the people, for the people, shall not perish from the earth.") + + blobParams = &core.BlobVersionParameters{ + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, + } + blobParamsMap = v2.NewBlobVersionParameterMap(map[corev2.BlobVersion]*core.BlobVersionParameters{ + 0: blobParams, + }) ) func TestMain(m *testing.M) { @@ -134,7 +144,7 @@ func prepareBlobs( blob := blobs[z] header := cert.BlobHeader - params, err := header.GetEncodingParams() + params, err := header.GetEncodingParams(blobParams) if err != nil { t.Fatal(err) } @@ -153,7 +163,7 @@ func prepareBlobs( for _, quorum := range header.QuorumNumbers { - assignments, err := corev2.GetAssignments(state, header.BlobVersion, quorum) + assignments, err := corev2.GetAssignments(state, blobParams, quorum) if err != nil { t.Fatal(err) } @@ -216,11 +226,11 @@ func checkBatchByUniversalVerifier( for id := range state.IndexedOperators { - val := corev2.NewShardValidator(v, id) + val := corev2.NewShardValidator(v, id, logging.NewNoopLogger()) blobs := packagedBlobs[id] - err := val.ValidateBlobs(ctx, blobs, pool, state.OperatorState) + err := val.ValidateBlobs(ctx, blobs, blobParamsMap, pool, state.OperatorState) if err != nil { errList = multierror.Append(errList, err) } diff --git a/core/v2/types.go b/core/v2/types.go index aeb3c34fc5..796ab06b51 100644 --- a/core/v2/types.go +++ b/core/v2/types.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "errors" "fmt" - "math" "math/big" "strings" @@ -16,15 +15,7 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" ) -var ( - // TODO(mooselumph): Put these parameters on chain and add on-chain checks to ensure that the number of operators does not - // conflict with the existing on-chain limits - ParametersMap = map[BlobVersion]BlobVersionParameters{ - 0: {CodingRate: 8, ReconstructionThreshold: 0.22, NumChunks: 8192}, - } -) - -type BlobVersion uint8 +type BlobVersion = uint8 // Assignment contains information about the set of chunks that a specific node will receive type Assignment struct { @@ -158,16 +149,14 @@ func (b *BlobHeader) ToProtobuf() (*commonpb.BlobHeader, error) { }, nil } -func (b *BlobHeader) GetEncodingParams() (encoding.EncodingParams, error) { - params := ParametersMap[b.BlobVersion] - - length, err := GetChunkLength(b.BlobVersion, uint32(b.BlobCommitments.Length)) +func (b *BlobHeader) GetEncodingParams(blobParams *core.BlobVersionParameters) (encoding.EncodingParams, error) { + length, err := GetChunkLength(uint32(b.BlobCommitments.Length), blobParams) if err != nil { return encoding.EncodingParams{}, err } return encoding.EncodingParams{ - NumChunks: uint64(params.NumChunks), + NumChunks: uint64(blobParams.NumChunks), ChunkLength: uint64(length), }, nil } @@ -380,16 +369,6 @@ func (v *BlobVerificationInfo) ToProtobuf(blobCert *BlobCertificate) (*disperser }, nil } -type BlobVersionParameters struct { - CodingRate uint32 - ReconstructionThreshold float64 - NumChunks uint32 -} - -func (p BlobVersionParameters) MaxNumOperators() uint32 { - return uint32(math.Floor(float64(p.NumChunks) * (1 - 1/(p.ReconstructionThreshold*float64(p.CodingRate))))) -} - // DispersalRequest is a request to disperse a batch to a specific operator type DispersalRequest struct { core.OperatorID `dynamodbav:"-"` diff --git a/core/v2/validator.go b/core/v2/validator.go index cf16d9f41c..97c42e767e 100644 --- a/core/v2/validator.go +++ b/core/v2/validator.go @@ -9,6 +9,7 @@ import ( "github.com/Layr-Labs/eigenda/common" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/encoding" + "github.com/Layr-Labs/eigensdk-go/logging" ) var ( @@ -18,7 +19,7 @@ var ( type ShardValidator interface { ValidateBatchHeader(ctx context.Context, header *BatchHeader, blobCerts []*BlobCertificate) error - ValidateBlobs(ctx context.Context, blobs []*BlobShard, pool common.WorkerPool, state *core.OperatorState) error + ValidateBlobs(ctx context.Context, blobs []*BlobShard, blobVersionParams *BlobVersionParameterMap, pool common.WorkerPool, state *core.OperatorState) error } type BlobShard struct { @@ -30,18 +31,20 @@ type BlobShard struct { type shardValidator struct { verifier encoding.Verifier operatorID core.OperatorID + logger logging.Logger } var _ ShardValidator = (*shardValidator)(nil) -func NewShardValidator(v encoding.Verifier, operatorID core.OperatorID) *shardValidator { +func NewShardValidator(v encoding.Verifier, operatorID core.OperatorID, logger logging.Logger) *shardValidator { return &shardValidator{ verifier: v, operatorID: operatorID, + logger: logger, } } -func (v *shardValidator) validateBlobQuorum(quorum core.QuorumID, blob *BlobShard, operatorState *core.OperatorState) ([]*encoding.Frame, *Assignment, error) { +func (v *shardValidator) validateBlobQuorum(quorum core.QuorumID, blob *BlobShard, blobParams *core.BlobVersionParameters, operatorState *core.OperatorState) ([]*encoding.Frame, *Assignment, error) { // Check if the operator is a member of the quorum if _, ok := operatorState.Operators[quorum]; !ok { @@ -49,7 +52,7 @@ func (v *shardValidator) validateBlobQuorum(quorum core.QuorumID, blob *BlobShar } // Get the assignments for the quorum - assignment, err := GetAssignment(operatorState, blob.BlobHeader.BlobVersion, quorum, v.operatorID) + assignment, err := GetAssignment(operatorState, blobParams, quorum, v.operatorID) if err != nil { return nil, nil, err } @@ -63,7 +66,7 @@ func (v *shardValidator) validateBlobQuorum(quorum core.QuorumID, blob *BlobShar } // Get the chunk length - chunkLength, err := GetChunkLength(blob.BlobHeader.BlobVersion, uint32(blob.BlobHeader.BlobCommitments.Length)) + chunkLength, err := GetChunkLength(uint32(blob.BlobHeader.BlobCommitments.Length), blobParams) if err != nil { return nil, nil, fmt.Errorf("invalid chunk length: %w", err) } @@ -99,7 +102,15 @@ func (v *shardValidator) ValidateBatchHeader(ctx context.Context, header *BatchH return nil } -func (v *shardValidator) ValidateBlobs(ctx context.Context, blobs []*BlobShard, pool common.WorkerPool, state *core.OperatorState) error { +func (v *shardValidator) ValidateBlobs(ctx context.Context, blobs []*BlobShard, blobVersionParams *BlobVersionParameterMap, pool common.WorkerPool, state *core.OperatorState) error { + if len(blobs) == 0 { + return fmt.Errorf("no blobs") + } + + if blobVersionParams == nil { + return fmt.Errorf("blob version params is nil") + } + var err error subBatchMap := make(map[encoding.EncodingParams]*encoding.SubBatch) blobCommitmentList := make([]encoding.BlobCommitments, len(blobs)) @@ -114,49 +125,55 @@ func (v *shardValidator) ValidateBlobs(ctx context.Context, blobs []*BlobShard, // for each quorum for _, quorum := range blob.BlobHeader.QuorumNumbers { - chunks, assignment, err := v.validateBlobQuorum(quorum, blob, state) - if err != nil { + blobParams, ok := blobVersionParams.Get(blob.BlobHeader.BlobVersion) + if !ok { + return fmt.Errorf("blob version %d not found", blob.BlobHeader.BlobVersion) + } + chunks, assignment, err := v.validateBlobQuorum(quorum, blob, blobParams, state) + if errors.Is(err, ErrBlobQuorumSkip) { + v.logger.Warn("Skipping blob for quorum", "quorum", quorum, "err", err) + continue + } else if err != nil { return err } + // TODO: Define params for the blob - params, err := blob.BlobHeader.GetEncodingParams() + params, err := blob.BlobHeader.GetEncodingParams(blobParams) if err != nil { return err } - if errors.Is(err, ErrBlobQuorumSkip) { - continue - } else if err != nil { + if err != nil { return err - } else { - // Check the received chunks against the commitment - blobIndex := 0 - subBatch, ok := subBatchMap[params] - if ok { - blobIndex = subBatch.NumBlobs - } + } + + // Check the received chunks against the commitment + blobIndex := 0 + subBatch, ok := subBatchMap[params] + if ok { + blobIndex = subBatch.NumBlobs + } - indices := assignment.GetIndices() - samples := make([]encoding.Sample, len(chunks)) - for ind := range chunks { - samples[ind] = encoding.Sample{ - Commitment: blob.BlobHeader.BlobCommitments.Commitment, - Chunk: chunks[ind], - AssignmentIndex: uint(indices[ind]), - BlobIndex: blobIndex, - } + indices := assignment.GetIndices() + samples := make([]encoding.Sample, len(chunks)) + for ind := range chunks { + samples[ind] = encoding.Sample{ + Commitment: blob.BlobHeader.BlobCommitments.Commitment, + Chunk: chunks[ind], + AssignmentIndex: uint(indices[ind]), + BlobIndex: blobIndex, } + } - // update subBatch - if !ok { - subBatchMap[params] = &encoding.SubBatch{ - Samples: samples, - NumBlobs: 1, - } - } else { - subBatch.Samples = append(subBatch.Samples, samples...) - subBatch.NumBlobs += 1 + // update subBatch + if !ok { + subBatchMap[params] = &encoding.SubBatch{ + Samples: samples, + NumBlobs: 1, } + } else { + subBatch.Samples = append(subBatch.Samples, samples...) + subBatch.NumBlobs += 1 } } } diff --git a/disperser/apiserver/disperse_blob_v2.go b/disperser/apiserver/disperse_blob_v2.go index 5fc160b677..05034122cf 100644 --- a/disperser/apiserver/disperse_blob_v2.go +++ b/disperser/apiserver/disperse_blob_v2.go @@ -14,7 +14,12 @@ import ( ) func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBlobRequest) (*pb.DisperseBlobReply, error) { - if err := s.validateDispersalRequest(req); err != nil { + onchainState := s.onchainState.Load() + if onchainState == nil { + return nil, api.NewErrorInternal("onchain state is nil") + } + + if err := s.validateDispersalRequest(req, onchainState); err != nil { return nil, err } @@ -27,9 +32,9 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl // TODO(ian-shim): handle payments and check rate limits - blobKey, err := s.StoreBlob(ctx, data, blobHeader, time.Now()) + blobKey, err := s.StoreBlob(ctx, data, blobHeader, time.Now(), onchainState.TTL) if err != nil { - return nil, api.NewErrorInternal(err.Error()) + return nil, err } return &pb.DisperseBlobReply{ @@ -38,20 +43,20 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl }, nil } -func (s *DispersalServerV2) StoreBlob(ctx context.Context, data []byte, blobHeader *corev2.BlobHeader, requestedAt time.Time) (corev2.BlobKey, error) { +func (s *DispersalServerV2) StoreBlob(ctx context.Context, data []byte, blobHeader *corev2.BlobHeader, requestedAt time.Time, ttl time.Duration) (corev2.BlobKey, error) { blobKey, err := blobHeader.BlobKey() if err != nil { - return corev2.BlobKey{}, err + return corev2.BlobKey{}, api.NewErrorInvalidArg(fmt.Sprintf("failed to get blob key: %v", err)) } if err := s.blobStore.StoreBlob(ctx, blobKey, data); err != nil { - return corev2.BlobKey{}, err + return corev2.BlobKey{}, api.NewErrorInternal(fmt.Sprintf("failed to store blob: %v", err)) } blobMetadata := &dispv2.BlobMetadata{ BlobHeader: blobHeader, BlobStatus: dispv2.Queued, - Expiry: uint64(requestedAt.Add(s.onchainState.TTL).Unix()), + Expiry: uint64(requestedAt.Add(ttl).Unix()), NumRetries: 0, BlobSize: uint64(len(data)), RequestedAt: uint64(requestedAt.UnixNano()), @@ -61,7 +66,7 @@ func (s *DispersalServerV2) StoreBlob(ctx context.Context, data []byte, blobHead return blobKey, err } -func (s *DispersalServerV2) validateDispersalRequest(req *pb.DisperseBlobRequest) error { +func (s *DispersalServerV2) validateDispersalRequest(req *pb.DisperseBlobRequest, onchainState *OnchainState) error { data := req.GetData() blobSize := len(data) if blobSize == 0 { @@ -81,13 +86,13 @@ func (s *DispersalServerV2) validateDispersalRequest(req *pb.DisperseBlobRequest return api.NewErrorInvalidArg("blob header must contain at least one quorum number") } - if len(blobHeaderProto.GetQuorumNumbers()) > int(s.onchainState.QuorumCount) { - return api.NewErrorInvalidArg(fmt.Sprintf("too many quorum numbers specified: maximum is %d", s.onchainState.QuorumCount)) + if len(blobHeaderProto.GetQuorumNumbers()) > int(onchainState.QuorumCount) { + return api.NewErrorInvalidArg(fmt.Sprintf("too many quorum numbers specified: maximum is %d", onchainState.QuorumCount)) } for _, quorum := range blobHeaderProto.GetQuorumNumbers() { - if quorum > corev2.MaxQuorumID || uint8(quorum) >= s.onchainState.QuorumCount { - return api.NewErrorInvalidArg(fmt.Sprintf("invalid quorum number %d; maximum is %d", quorum, s.onchainState.QuorumCount)) + if quorum > corev2.MaxQuorumID || uint8(quorum) >= onchainState.QuorumCount { + return api.NewErrorInvalidArg(fmt.Sprintf("invalid quorum number %d; maximum is %d", quorum, onchainState.QuorumCount)) } } @@ -98,12 +103,8 @@ func (s *DispersalServerV2) validateDispersalRequest(req *pb.DisperseBlobRequest return api.NewErrorInvalidArg("encountered an error to convert a 32-bytes into a valid field element, please use the correct format where every 32bytes(big-endian) is less than 21888242871839275222246405745257275088548364400416034343698204186575808495617") } - if _, ok := s.onchainState.BlobVersionParameters[corev2.BlobVersion(blobHeaderProto.GetVersion())]; !ok { - validVersions := make([]int32, 0, len(s.onchainState.BlobVersionParameters)) - for version := range s.onchainState.BlobVersionParameters { - validVersions = append(validVersions, int32(version)) - } - return api.NewErrorInvalidArg(fmt.Sprintf("invalid blob version %d; valid blob versions are: %v", blobHeaderProto.GetVersion(), validVersions)) + if _, ok := onchainState.BlobVersionParameters.Get(corev2.BlobVersion(blobHeaderProto.GetVersion())); !ok { + return api.NewErrorInvalidArg(fmt.Sprintf("invalid blob version %d; valid blob versions are: %v", blobHeaderProto.GetVersion(), onchainState.BlobVersionParameters.Keys())) } blobHeader, err := corev2.BlobHeaderFromProtobuf(blobHeaderProto) diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index e3cbf733f2..acf85b0542 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "sync/atomic" "time" "github.com/Layr-Labs/eigenda/api" @@ -14,6 +15,7 @@ import ( healthcheck "github.com/Layr-Labs/eigenda/common/healthcheck" "github.com/Layr-Labs/eigenda/core" corev2 "github.com/Layr-Labs/eigenda/core/v2" + v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/disperser" "github.com/Layr-Labs/eigenda/disperser/common/v2/blobstore" "github.com/Layr-Labs/eigenda/encoding" @@ -25,7 +27,7 @@ import ( type OnchainState struct { QuorumCount uint8 RequiredQuorums []core.QuorumID - BlobVersionParameters map[corev2.BlobVersion]corev2.BlobVersionParameters + BlobVersionParameters *corev2.BlobVersionParameterMap TTL time.Duration } @@ -42,7 +44,7 @@ type DispersalServerV2 struct { logger logging.Logger // state - onchainState OnchainState + onchainState atomic.Pointer[OnchainState] maxNumSymbolsPerBlob uint64 onchainStateRefreshInterval time.Duration } @@ -73,7 +75,6 @@ func NewDispersalServerV2( prover: prover, logger: logger, - onchainState: OnchainState{}, maxNumSymbolsPerBlob: maxNumSymbolsPerBlob, onchainStateRefreshInterval: onchainStateRefreshInterval, } @@ -190,12 +191,19 @@ func (s *DispersalServerV2) RefreshOnchainState(ctx context.Context) error { if err != nil || storeDurationBlocks == 0 { return fmt.Errorf("failed to get STORE_DURATION_BLOCKS: %w", err) } - s.onchainState = OnchainState{ - QuorumCount: quorumCount, - RequiredQuorums: requiredQuorums, - // TODO(ian-shim): this should be fetched from chain - BlobVersionParameters: corev2.ParametersMap, + + blobParams, err := s.chainReader.GetAllVersionedBlobParams(ctx) + if err != nil { + return fmt.Errorf("failed to get blob version parameters: %w", err) + } + onchainState := &OnchainState{ + QuorumCount: quorumCount, + RequiredQuorums: requiredQuorums, + BlobVersionParameters: v2.NewBlobVersionParameterMap(blobParams), TTL: time.Duration((storeDurationBlocks+blockStaleMeasure)*12) * time.Second, } + + s.onchainState.Store(onchainState) + return nil } diff --git a/disperser/apiserver/server_v2_test.go b/disperser/apiserver/server_v2_test.go index 5ef2fe8dac..77afef0085 100644 --- a/disperser/apiserver/server_v2_test.go +++ b/disperser/apiserver/server_v2_test.go @@ -16,6 +16,7 @@ import ( auth "github.com/Layr-Labs/eigenda/core/auth/v2" "github.com/Layr-Labs/eigenda/core/mock" corev2 "github.com/Layr-Labs/eigenda/core/v2" + v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/disperser/apiserver" dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2" "github.com/Layr-Labs/eigenda/disperser/common/v2/blobstore" @@ -435,6 +436,13 @@ func newTestServerV2(t *testing.T) *testComponents { chainReader.On("GetRequiredQuorumNumbers", tmock.Anything).Return([]uint8{0, 1}, nil) chainReader.On("GetBlockStaleMeasure", tmock.Anything).Return(uint32(10), nil) chainReader.On("GetStoreDurationBlocks", tmock.Anything).Return(uint32(100), nil) + chainReader.On("GetAllVersionedBlobParams", tmock.Anything).Return(map[v2.BlobVersion]*core.BlobVersionParameters{ + 0: { + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, + }, + }, nil) s := apiserver.NewDispersalServerV2(disperser.ServerConfig{ GrpcPort: "51002", diff --git a/disperser/cmd/controller/config.go b/disperser/cmd/controller/config.go index 3f146631b5..db1a94629c 100644 --- a/disperser/cmd/controller/config.go +++ b/disperser/cmd/controller/config.go @@ -63,14 +63,15 @@ func NewConfig(ctx *cli.Context) (Config, error) { AwsClientConfig: aws.ReadClientConfig(ctx, flags.FlagPrefix), LoggerConfig: *loggerConfig, EncodingManagerConfig: controller.EncodingManagerConfig{ - PullInterval: ctx.GlobalDuration(flags.EncodingPullIntervalFlag.Name), - EncodingRequestTimeout: ctx.GlobalDuration(flags.EncodingRequestTimeoutFlag.Name), - StoreTimeout: ctx.GlobalDuration(flags.EncodingStoreTimeoutFlag.Name), - NumEncodingRetries: ctx.GlobalInt(flags.NumEncodingRetriesFlag.Name), - NumRelayAssignment: uint16(numRelayAssignments), - AvailableRelays: relays, - EncoderAddress: ctx.GlobalString(flags.EncoderAddressFlag.Name), - MaxNumBlobsPerIteration: int32(ctx.GlobalInt(flags.MaxNumBlobsPerIterationFlag.Name)), + PullInterval: ctx.GlobalDuration(flags.EncodingPullIntervalFlag.Name), + EncodingRequestTimeout: ctx.GlobalDuration(flags.EncodingRequestTimeoutFlag.Name), + StoreTimeout: ctx.GlobalDuration(flags.EncodingStoreTimeoutFlag.Name), + NumEncodingRetries: ctx.GlobalInt(flags.NumEncodingRetriesFlag.Name), + NumRelayAssignment: uint16(numRelayAssignments), + AvailableRelays: relays, + EncoderAddress: ctx.GlobalString(flags.EncoderAddressFlag.Name), + MaxNumBlobsPerIteration: int32(ctx.GlobalInt(flags.MaxNumBlobsPerIterationFlag.Name)), + OnchainStateRefreshInterval: ctx.GlobalDuration(flags.OnchainStateRefreshIntervalFlag.Name), }, DispatcherConfig: controller.DispatcherConfig{ PullInterval: ctx.GlobalDuration(flags.DispatcherPullIntervalFlag.Name), diff --git a/disperser/cmd/controller/flags/flags.go b/disperser/cmd/controller/flags/flags.go index 71654cc4d3..7a54153aa6 100644 --- a/disperser/cmd/controller/flags/flags.go +++ b/disperser/cmd/controller/flags/flags.go @@ -109,6 +109,13 @@ var ( EnvVar: common.PrefixEnvVar(envVarPrefix, "MAX_NUM_BLOBS_PER_ITERATION"), Value: 128, } + OnchainStateRefreshIntervalFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "onchain-state-refresh-interval"), + Usage: "Interval at which to refresh the onchain state", + Required: false, + EnvVar: common.PrefixEnvVar(envVarPrefix, "ONCHAIN_STATE_REFRESH_INTERVAL"), + Value: 1 * time.Hour, + } // Dispatcher Flags DispatcherPullIntervalFlag = cli.DurationFlag{ @@ -188,6 +195,7 @@ var optionalFlags = []cli.Flag{ NumRelayAssignmentFlag, NumConcurrentEncodingRequestsFlag, MaxNumBlobsPerIterationFlag, + OnchainStateRefreshIntervalFlag, FinalizationBlockDelayFlag, NumRequestRetriesFlag, diff --git a/disperser/controller/encoding_manager.go b/disperser/controller/encoding_manager.go index 551f6af14f..a6e015051b 100644 --- a/disperser/controller/encoding_manager.go +++ b/disperser/controller/encoding_manager.go @@ -6,6 +6,7 @@ import ( "fmt" "math" "math/rand" + "sync/atomic" "time" "github.com/Layr-Labs/eigenda/common" @@ -36,6 +37,8 @@ type EncodingManagerConfig struct { EncoderAddress string // MaxNumBlobsPerIteration is the maximum number of blobs to encode per iteration MaxNumBlobsPerIteration int32 + // OnchainStateRefreshInterval is the interval at which the onchain state is refreshed + OnchainStateRefreshInterval time.Duration } // EncodingManager is responsible for pulling queued blobs from the blob @@ -52,7 +55,8 @@ type EncodingManager struct { logger logging.Logger // state - cursor *blobstore.StatusIndexCursor + cursor *blobstore.StatusIndexCursor + blobVersionParameters atomic.Pointer[corev2.BlobVersionParameterMap] } func NewEncodingManager( @@ -84,6 +88,30 @@ func NewEncodingManager( } func (e *EncodingManager) Start(ctx context.Context) error { + // Refresh blob version parameters + err := e.refreshBlobVersionParams(ctx) + if err != nil { + return fmt.Errorf("failed to refresh blob version parameters: %w", err) + } + + go func() { + ticker := time.NewTicker(e.EncodingManagerConfig.OnchainStateRefreshInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + e.logger.Info("refreshing blob version params") + if err := e.refreshBlobVersionParams(ctx); err != nil { + e.logger.Error("failed to refresh blob version params", "err", err) + } + case <-ctx.Done(): + return + } + } + }() + + // Start the encoding loop go func() { ticker := time.NewTicker(e.PullInterval) defer ticker.Stop() @@ -118,6 +146,11 @@ func (e *EncodingManager) HandleBatch(ctx context.Context) error { return errNoBlobsToEncode } + blobVersionParams := e.blobVersionParameters.Load() + if blobVersionParams == nil { + return fmt.Errorf("blob version parameters is nil") + } + for _, blob := range blobMetadatas { blob := blob blobKey, err := blob.BlobHeader.BlobKey() @@ -126,11 +159,17 @@ func (e *EncodingManager) HandleBatch(ctx context.Context) error { continue } + blobParams, ok := blobVersionParams.Get(blob.BlobHeader.BlobVersion) + if !ok { + e.logger.Error("failed to get blob version parameters", "version", blob.BlobHeader.BlobVersion) + continue + } + // Encode the blobs e.pool.Submit(func() { for i := 0; i < e.NumEncodingRetries+1; i++ { encodingCtx, cancel := context.WithTimeout(ctx, e.EncodingRequestTimeout) - fragmentInfo, err := e.encodeBlob(encodingCtx, blobKey, blob) + fragmentInfo, err := e.encodeBlob(encodingCtx, blobKey, blob, blobParams) cancel() if err != nil { e.logger.Error("failed to encode blob", "blobKey", blobKey.Hex(), "err", err) @@ -183,14 +222,25 @@ func (e *EncodingManager) HandleBatch(ctx context.Context) error { return nil } -func (e *EncodingManager) encodeBlob(ctx context.Context, blobKey corev2.BlobKey, blob *v2.BlobMetadata) (*encoding.FragmentInfo, error) { - encodingParams, err := blob.BlobHeader.GetEncodingParams() +func (e *EncodingManager) encodeBlob(ctx context.Context, blobKey corev2.BlobKey, blob *v2.BlobMetadata, blobParams *core.BlobVersionParameters) (*encoding.FragmentInfo, error) { + encodingParams, err := blob.BlobHeader.GetEncodingParams(blobParams) if err != nil { return nil, fmt.Errorf("failed to get encoding params: %w", err) } return e.encodingClient.EncodeBlob(ctx, blobKey, encodingParams) } +func (e *EncodingManager) refreshBlobVersionParams(ctx context.Context) error { + e.logger.Debug("Refreshing blob version params") + blobParams, err := e.chainReader.GetAllVersionedBlobParams(ctx) + if err != nil { + return fmt.Errorf("failed to get blob version parameters: %w", err) + } + + e.blobVersionParameters.Store(corev2.NewBlobVersionParameterMap(blobParams)) + return nil +} + func GetRelayKeys(numAssignment uint16, availableRelays []corev2.RelayKey) ([]corev2.RelayKey, error) { if int(numAssignment) > len(availableRelays) { return nil, fmt.Errorf("numAssignment (%d) cannot be greater than numRelays (%d)", numAssignment, len(availableRelays)) diff --git a/disperser/controller/encoding_manager_test.go b/disperser/controller/encoding_manager_test.go index 4724cf410c..7ab6b25730 100644 --- a/disperser/controller/encoding_manager_test.go +++ b/disperser/controller/encoding_manager_test.go @@ -7,8 +7,10 @@ import ( "github.com/Layr-Labs/eigenda/common" commonmock "github.com/Layr-Labs/eigenda/common/mock" + "github.com/Layr-Labs/eigenda/core" coremock "github.com/Layr-Labs/eigenda/core/mock" corev2 "github.com/Layr-Labs/eigenda/core/v2" + v2 "github.com/Layr-Labs/eigenda/core/v2" dispcommon "github.com/Layr-Labs/eigenda/disperser/common" commonv2 "github.com/Layr-Labs/eigenda/disperser/common/v2" "github.com/Layr-Labs/eigenda/disperser/controller" @@ -294,16 +296,30 @@ func newTestComponents(t *testing.T, mockPool bool) *testComponents { encodingClient := dispmock.NewMockEncoderClientV2() chainReader := &coremock.MockWriter{} chainReader.On("GetCurrentBlockNumber").Return(blockNumber, nil) + chainReader.On("GetAllVersionedBlobParams", mock.Anything).Return(map[v2.BlobVersion]*core.BlobVersionParameters{ + 0: { + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, + }, + }, nil) + onchainRefreshInterval := 1 * time.Millisecond em, err := controller.NewEncodingManager(&controller.EncodingManagerConfig{ - PullInterval: 1 * time.Second, - EncodingRequestTimeout: 5 * time.Second, - StoreTimeout: 5 * time.Second, - NumEncodingRetries: 1, - NumRelayAssignment: 2, - AvailableRelays: []corev2.RelayKey{0, 1, 2, 3}, - MaxNumBlobsPerIteration: 5, + PullInterval: 1 * time.Second, + EncodingRequestTimeout: 5 * time.Second, + StoreTimeout: 5 * time.Second, + NumEncodingRetries: 1, + NumRelayAssignment: 2, + AvailableRelays: []corev2.RelayKey{0, 1, 2, 3}, + MaxNumBlobsPerIteration: 5, + OnchainStateRefreshInterval: onchainRefreshInterval, }, blobMetadataStore, pool, encodingClient, chainReader, logger) - require.NoError(t, err) + assert.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), 2*onchainRefreshInterval) + defer cancel() + // Start the encoding manager to fetch the onchain state + _ = em.Start(ctx) return &testComponents{ EncodingManager: em, Pool: pool, diff --git a/disperser/encoder/server_v2_test.go b/disperser/encoder/server_v2_test.go index 57a850b2c0..69b30b7448 100644 --- a/disperser/encoder/server_v2_test.go +++ b/disperser/encoder/server_v2_test.go @@ -24,6 +24,12 @@ import ( "golang.org/x/exp/rand" ) +var blobParams = &core.BlobVersionParameters{ + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, +} + type testComponents struct { encoderServer *encoder.EncoderServerV2 blobStore *blobstore.BlobStore @@ -58,8 +64,8 @@ func TestEncodeBlob(t *testing.T) { ) var ( - codingRatio = corev2.ParametersMap[0].CodingRate - numChunks = corev2.ParametersMap[0].NumChunks + codingRatio = blobParams.CodingRate + numChunks = blobParams.NumChunks ) ctx, cancel := context.WithTimeout(context.Background(), timeoutSeconds*time.Second) @@ -85,7 +91,7 @@ func TestEncodeBlob(t *testing.T) { blobLength := encoding.GetBlobLength(blobSize) // Get chunk length for blob version 0 - chunkLength, err := corev2.GetChunkLength(0, core.NextPowerOf2(uint32(blobLength))) + chunkLength, err := corev2.GetChunkLength(core.NextPowerOf2(uint32(blobLength)), blobParams) if !assert.NoError(t, err, "Failed to get chunk length") { t.FailNow() } diff --git a/node/config.go b/node/config.go index e67fc7894f..7d73bdcb20 100644 --- a/node/config.go +++ b/node/config.go @@ -89,7 +89,8 @@ type Config struct { LoggerConfig common.LoggerConfig EncoderConfig kzg.KzgConfig - EnableV2 bool + EnableV2 bool + OnchainStateRefreshInterval time.Duration } // NewConfig parses the Config from the provided flags or environment variables and @@ -235,5 +236,6 @@ func NewConfig(ctx *cli.Context) (*Config, error) { BLSSignerTLSCertFilePath: ctx.GlobalString(flags.BLSSignerCertFileFlag.Name), BLSRemoteSignerEnabled: blsRemoteSignerEnabled, EnableV2: ctx.GlobalBool(flags.EnableV2Flag.Name), + OnchainStateRefreshInterval: ctx.GlobalDuration(flags.OnchainStateRefreshIntervalFlag.Name), }, nil } diff --git a/node/flags/flags.go b/node/flags/flags.go index 5bcd95a98b..b16e2709e9 100644 --- a/node/flags/flags.go +++ b/node/flags/flags.go @@ -224,6 +224,13 @@ var ( Required: false, EnvVar: common.PrefixEnvVar(EnvVarPrefix, "ENABLE_V2"), } + OnchainStateRefreshIntervalFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "onchain-state-refresh-interval"), + Usage: "The interval at which to refresh the onchain state. This flag is only relevant in v2 (default: 1h)", + Required: false, + EnvVar: common.PrefixEnvVar(EnvVarPrefix, "ONCHAIN_STATE_REFRESH_INTERVAL"), + Value: 1 * time.Hour, + } // Test only, DO NOT USE the following flags in production @@ -353,6 +360,7 @@ var optionalFlags = []cli.Flag{ BLSPublicKeyHexFlag, BLSSignerCertFileFlag, EnableV2Flag, + OnchainStateRefreshIntervalFlag, } func init() { diff --git a/node/grpc/server_v2_test.go b/node/grpc/server_v2_test.go index 6bb15870c6..249bd6bb77 100644 --- a/node/grpc/server_v2_test.go +++ b/node/grpc/server_v2_test.go @@ -29,6 +29,17 @@ import ( "google.golang.org/grpc/status" ) +var ( + blobParams = &core.BlobVersionParameters{ + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, + } + blobParamsMap = map[v2.BlobVersion]*core.BlobVersionParameters{ + 0: blobParams, + } +) + type testComponents struct { server *grpc.ServerV2 node *node.Node @@ -67,6 +78,7 @@ func newTestComponents(t *testing.T, config *node.Config) *testComponents { ValidatorV2: val, RelayClient: relay, } + node.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParamsMap)) server := grpc.NewServerV2(config, node, logger, ratelimiter) return &testComponents{ server: server, diff --git a/node/node.go b/node/node.go index d22058c7a5..925fbe4517 100644 --- a/node/node.go +++ b/node/node.go @@ -14,6 +14,7 @@ import ( "os" "strings" "sync" + "sync/atomic" "time" "github.com/Layr-Labs/eigenda/common/kvstore/tablestore" @@ -36,6 +37,7 @@ import ( "github.com/Layr-Labs/eigenda/core/eth" "github.com/Layr-Labs/eigenda/core/indexer" corev2 "github.com/Layr-Labs/eigenda/core/v2" + v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigensdk-go/logging" "github.com/Layr-Labs/eigensdk-go/metrics" rpccalls "github.com/Layr-Labs/eigensdk-go/metrics/collectors/rpc_calls" @@ -79,6 +81,10 @@ type Node struct { mu sync.Mutex CurrentSocket string + + // BlobVersionParams is a map of blob version parameters loaded from the chain. + // It is used to determine blob parameters based on the version number. + BlobVersionParams atomic.Pointer[corev2.BlobVersionParameterMap] } // NewNode creates a new Node with the provided config. @@ -177,7 +183,7 @@ func NewNode( } asgn := &core.StdAssignmentCoordinator{} validator := core.NewShardValidator(v, asgn, cst, config.ID) - validatorV2 := corev2.NewShardValidator(v, config.ID) + validatorV2 := corev2.NewShardValidator(v, config.ID, logger) // Resolve the BLOCK_STALE_MEASURE and STORE_DURATION_BLOCKS. var blockStaleMeasure, storeDurationBlocks uint32 @@ -217,7 +223,31 @@ func NewNode( "eigenDAServiceManagerAddr", config.EigenDAServiceManagerAddr, "blockStaleMeasure", blockStaleMeasure, "storeDurationBlocks", storeDurationBlocks, "enableGnarkBundleEncoding", config.EnableGnarkBundleEncoding) var relayClient clients.RelayClient + + n := &Node{ + Config: config, + Logger: nodeLogger, + KeyPair: keyPair, + Metrics: metrics, + NodeApi: nodeApi, + Store: store, + ChainState: cst, + Transactor: tx, + Validator: validator, + ValidatorV2: validatorV2, + PubIPProvider: pubIPProvider, + OperatorSocketsFilterer: socketsFilterer, + ChainID: chainID, + RelayClient: relayClient, + BLSSigner: blsClient, + } + + if !config.EnableV2 { + return n, nil + } + var storeV2 StoreV2 + var blobVersionParams *corev2.BlobVersionParameterMap if config.EnableV2 { v2Path := config.DbPath + "/chunk_v2" dbV2, err := tablestore.Start(logger, &tablestore.Config{ @@ -233,27 +263,18 @@ func NewNode( } storeV2 = NewLevelDBStoreV2(dbV2, logger) + blobParams, err := tx.GetAllVersionedBlobParams(context.Background()) + if err != nil { + return nil, fmt.Errorf("failed to get versioned blob parameters: %w", err) + } + blobVersionParams = corev2.NewBlobVersionParameterMap(blobParams) + // TODO(ian-shim): Create a new relay client with relay addresses onchain } - return &Node{ - Config: config, - Logger: nodeLogger, - KeyPair: keyPair, - Metrics: metrics, - NodeApi: nodeApi, - Store: store, - StoreV2: storeV2, - ChainState: cst, - Transactor: tx, - Validator: validator, - ValidatorV2: validatorV2, - PubIPProvider: pubIPProvider, - OperatorSocketsFilterer: socketsFilterer, - ChainID: chainID, - RelayClient: relayClient, - BLSSigner: blsClient, - }, nil + n.StoreV2 = storeV2 + n.BlobVersionParams.Store(blobVersionParams) + return n, nil } // Start starts the Node. If the node is not registered, register it on chain, otherwise just @@ -271,6 +292,12 @@ func (n *Node) Start(ctx context.Context) error { go n.expireLoop() go n.checkNodeReachability() + if n.Config.EnableV2 { + go func() { + _ = n.RefreshOnchainState(ctx) + }() + } + // Build the socket based on the hostname/IP provided in the CLI socket := string(core.MakeOperatorSocket(n.Config.Hostname, n.Config.DispersalPort, n.Config.RetrievalPort)) var operator *Operator @@ -354,6 +381,30 @@ func (n *Node) expireLoop() { } } +func (n *Node) RefreshOnchainState(ctx context.Context) error { + if !n.Config.EnableV2 || n.Config.OnchainStateRefreshInterval <= 0 { + return nil + } + ticker := time.NewTicker(n.Config.OnchainStateRefreshInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + n.Logger.Info("Refreshing onchain state") + blobParams, err := n.Transactor.GetAllVersionedBlobParams(ctx) + if err != nil { + n.Logger.Error("error fetching blob params", "err", err) + continue + } + + n.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParams)) + case <-ctx.Done(): + return ctx.Err() + } + } +} + // ProcessBatch validates the batch is correct, stores data into the node's Store, and then returns a signature for the entire batch. // // The batch will be itemized into batch header, header and chunks of each blob in the batch. These items will diff --git a/node/node_test.go b/node/node_test.go index 85ae43ab64..f2607362f0 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -12,6 +12,7 @@ import ( "github.com/Layr-Labs/eigenda/common/geth" "github.com/Layr-Labs/eigenda/core" coremock "github.com/Layr-Labs/eigenda/core/mock" + v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/node" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -20,6 +21,15 @@ import ( var ( privateKey = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" opID = [32]byte{0} + + blobParams = &core.BlobVersionParameters{ + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, + } + blobParamsMap = map[v2.BlobVersion]*core.BlobVersionParameters{ + 0: blobParams, + } ) type components struct { @@ -72,18 +82,20 @@ func newComponents(t *testing.T) *components { } defer os.Remove(dbPath) relayClient := clientsmock.NewRelayClient() + n := &node.Node{ + Config: config, + Logger: logger, + KeyPair: keyPair, + Metrics: nil, + Store: store, + ChainState: chainState, + Validator: mockVal, + Transactor: tx, + RelayClient: relayClient, + } + n.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParamsMap)) return &components{ - node: &node.Node{ - Config: config, - Logger: logger, - KeyPair: keyPair, - Metrics: nil, - Store: store, - ChainState: chainState, - Validator: mockVal, - Transactor: tx, - RelayClient: relayClient, - }, + node: n, tx: tx, relayClient: relayClient, } diff --git a/node/node_v2.go b/node/node_v2.go index 5dd91992a5..c37c4c4647 100644 --- a/node/node_v2.go +++ b/node/node_v2.go @@ -38,6 +38,11 @@ func (n *Node) DownloadBundles(ctx context.Context, batch *corev2.Batch, operato return nil, nil, fmt.Errorf("relay client is not set") } + blobVersionParams := n.BlobVersionParams.Load() + if blobVersionParams == nil { + return nil, nil, fmt.Errorf("blob version params is nil") + } + blobShards := make([]*corev2.BlobShard, len(batch.BlobCertificates)) rawBundles := make([]*RawBundles, len(batch.BlobCertificates)) requests := make(map[corev2.RelayKey]*relayRequest) @@ -61,7 +66,11 @@ func (n *Node) DownloadBundles(ctx context.Context, batch *corev2.Batch, operato relayIndex := rand.Intn(len(cert.RelayKeys)) relayKey := cert.RelayKeys[relayIndex] for _, quorum := range cert.BlobHeader.QuorumNumbers { - assgn, err := corev2.GetAssignment(operatorState, batch.BlobCertificates[0].BlobHeader.BlobVersion, quorum, n.Config.ID) + blobParams, ok := blobVersionParams.Get(cert.BlobHeader.BlobVersion) + if !ok { + return nil, nil, fmt.Errorf("blob version %d not found", cert.BlobHeader.BlobVersion) + } + assgn, err := corev2.GetAssignment(operatorState, blobParams, quorum, n.Config.ID) if err != nil { return nil, nil, fmt.Errorf("failed to get assignments: %v", err) } @@ -145,5 +154,6 @@ func (n *Node) ValidateBatchV2( return fmt.Errorf("failed to validate batch header: %v", err) } pool := workerpool.New(n.Config.NumBatchValidators) - return n.ValidatorV2.ValidateBlobs(ctx, blobShards, pool, operatorState) + blobVersionParams := n.BlobVersionParams.Load() + return n.ValidatorV2.ValidateBlobs(ctx, blobShards, blobVersionParams, pool, operatorState) } diff --git a/node/node_v2_test.go b/node/node_v2_test.go index 3fc9795dde..cc56550439 100644 --- a/node/node_v2_test.go +++ b/node/node_v2_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "testing" + "time" "github.com/Layr-Labs/eigenda/api/clients" "github.com/Layr-Labs/eigenda/core" @@ -122,6 +123,38 @@ func TestDownloadBundlesFail(t *testing.T) { require.Nil(t, rawBundles) } +func TestRefreshOnchainState(t *testing.T) { + c := newComponents(t) + c.node.Config.EnableV2 = true + c.node.Config.OnchainStateRefreshInterval = time.Millisecond + ctx := context.Background() + bp, ok := c.node.BlobVersionParams.Load().Get(0) + require.True(t, ok) + require.Equal(t, bp, blobParams) + _, ok = c.node.BlobVersionParams.Load().Get(1) + require.False(t, ok) + + newCtx, cancel := context.WithTimeout(ctx, c.node.Config.OnchainStateRefreshInterval*2) + defer cancel() + blobParams2 := &core.BlobVersionParameters{ + NumChunks: 111, + CodingRate: 1, + MaxNumOperators: 222, + } + c.tx.On("GetAllVersionedBlobParams", mock.Anything).Return(map[v2.BlobVersion]*core.BlobVersionParameters{ + 0: blobParams, + 1: blobParams2, + }, nil) + err := c.node.RefreshOnchainState(newCtx) + require.ErrorIs(t, err, context.DeadlineExceeded) + bp, ok = c.node.BlobVersionParams.Load().Get(0) + require.True(t, ok) + require.Equal(t, bp, blobParams) + bp, ok = c.node.BlobVersionParams.Load().Get(1) + require.True(t, ok) + require.Equal(t, bp, blobParams2) +} + func bundleEqual(t *testing.T, expected, actual core.Bundle) { for i := range expected { frameEqual(t, expected[i], actual[i]) diff --git a/relay/cmd/config.go b/relay/cmd/config.go index 42078db96a..13f56e7ada 100644 --- a/relay/cmd/config.go +++ b/relay/cmd/config.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/Layr-Labs/eigenda/common" "github.com/Layr-Labs/eigenda/common/aws" "github.com/Layr-Labs/eigenda/common/geth" @@ -80,9 +81,10 @@ func NewConfig(ctx *cli.Context) (Config, error) { GetChunkBytesBurstinessClient: ctx.Int(flags.GetChunkBytesBurstinessClientFlag.Name), MaxConcurrentGetChunkOpsClient: ctx.Int(flags.MaxConcurrentGetChunkOpsClientFlag.Name), }, - AuthenticationKeyCacheSize: ctx.Int(flags.AuthenticationKeyCacheSizeFlag.Name), - AuthenticationTimeout: ctx.Duration(flags.AuthenticationTimeoutFlag.Name), - AuthenticationDisabled: ctx.Bool(flags.AuthenticationDisabledFlag.Name), + AuthenticationKeyCacheSize: ctx.Int(flags.AuthenticationKeyCacheSizeFlag.Name), + AuthenticationTimeout: ctx.Duration(flags.AuthenticationTimeoutFlag.Name), + AuthenticationDisabled: ctx.Bool(flags.AuthenticationDisabledFlag.Name), + OnchainStateRefreshInterval: ctx.Duration(flags.OnchainStateRefreshIntervalFlag.Name), }, EthClientConfig: geth.ReadEthClientConfig(ctx), BLSOperatorStateRetrieverAddr: ctx.String(flags.BlsOperatorStateRetrieverAddrFlag.Name), diff --git a/relay/cmd/flags/flags.go b/relay/cmd/flags/flags.go index 57fcc6cbd0..f471765966 100644 --- a/relay/cmd/flags/flags.go +++ b/relay/cmd/flags/flags.go @@ -1,11 +1,12 @@ package flags import ( + "time" + "github.com/Layr-Labs/eigenda/common" "github.com/Layr-Labs/eigenda/common/aws" "github.com/Layr-Labs/eigenda/common/geth" "github.com/urfave/cli" - "time" ) const ( @@ -230,6 +231,13 @@ var ( Required: false, EnvVar: common.PrefixEnvVar(envVarPrefix, "AUTHENTICATION_DISABLED"), } + OnchainStateRefreshIntervalFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "onchain-state-refresh-interval"), + Usage: "The interval at which to refresh the onchain state", + Required: false, + EnvVar: common.PrefixEnvVar(envVarPrefix, "ONCHAIN_STATE_REFRESH_INTERVAL"), + Value: 1 * time.Hour, + } ) var requiredFlags = []cli.Flag{ @@ -268,6 +276,7 @@ var optionalFlags = []cli.Flag{ AuthenticationKeyCacheSizeFlag, AuthenticationTimeoutFlag, AuthenticationDisabledFlag, + OnchainStateRefreshIntervalFlag, } var Flags []cli.Flag diff --git a/relay/cmd/main.go b/relay/cmd/main.go index eb39cdb03a..bffdd9fa9e 100644 --- a/relay/cmd/main.go +++ b/relay/cmd/main.go @@ -3,14 +3,13 @@ package main import ( "context" "fmt" + "log" + "os" + "github.com/Layr-Labs/eigenda/common/geth" - "github.com/Layr-Labs/eigenda/core" coreeth "github.com/Layr-Labs/eigenda/core/eth" "github.com/Layr-Labs/eigenda/core/thegraph" - "github.com/Layr-Labs/eigensdk-go/logging" gethcommon "github.com/ethereum/go-ethereum/common" - "log" - "os" "github.com/Layr-Labs/eigenda/common" "github.com/Layr-Labs/eigenda/common/aws/dynamodb" @@ -70,11 +69,19 @@ func RunRelay(ctx *cli.Context) error { metadataStore := blobstore.NewBlobMetadataStore(dynamoClient, logger, config.MetadataTableName) blobStore := blobstore.NewBlobStore(config.BucketName, s3Client, logger) chunkReader := chunkstore.NewChunkReader(logger, s3Client, config.BucketName) - ics, err := buildICS(logger, &config) + client, err := geth.NewMultiHomingClient(config.EthClientConfig, gethcommon.Address{}, logger) if err != nil { - return fmt.Errorf("failed to build ics: %w", err) + return fmt.Errorf("failed to create eth client: %w", err) } + tx, err := coreeth.NewWriter(logger, client, config.BLSOperatorStateRetrieverAddr, config.EigenDAServiceManagerAddr) + if err != nil { + return fmt.Errorf("failed to create eth writer: %w", err) + } + + cs := coreeth.NewChainState(tx, client) + ics := thegraph.MakeIndexedChainState(config.ChainStateConfig, cs, logger) + server, err := relay.NewServer( context.Background(), logger, @@ -82,33 +89,17 @@ func RunRelay(ctx *cli.Context) error { metadataStore, blobStore, chunkReader, - ics) + tx, + ics, + ) if err != nil { return fmt.Errorf("failed to create relay server: %w", err) } - err = server.Start() + err = server.Start(context.Background()) if err != nil { return fmt.Errorf("failed to start relay server: %w", err) } return nil } - -func buildICS(logger logging.Logger, config *Config) (core.IndexedChainState, error) { - client, err := geth.NewMultiHomingClient(config.EthClientConfig, gethcommon.Address{}, logger) - if err != nil { - logger.Error("Cannot create chain.Client", "err", err) - return nil, err - } - - tx, err := coreeth.NewWriter(logger, client, config.BLSOperatorStateRetrieverAddr, config.EigenDAServiceManagerAddr) - if err != nil { - return nil, fmt.Errorf("failed to create eth writer: %w", err) - } - - cs := coreeth.NewChainState(tx, client) - ics := thegraph.MakeIndexedChainState(config.ChainStateConfig, cs, logger) - - return ics, nil -} diff --git a/relay/metadata_provider.go b/relay/metadata_provider.go index e70531702d..f86bccfddd 100644 --- a/relay/metadata_provider.go +++ b/relay/metadata_provider.go @@ -40,6 +40,9 @@ type metadataProvider struct { // relayIDSet is the set of relay IDs assigned to this relay. This relay will refuse to serve metadata for blobs // that are not assigned to one of these IDs. relayIDSet map[v2.RelayKey]struct{} + + // blobParamsMap is a map of blob version to blob version parameters. + blobParamsMap atomic.Pointer[v2.BlobVersionParameterMap] } // newMetadataProvider creates a new metadataProvider. @@ -49,7 +52,9 @@ func newMetadataProvider( metadataStore *blobstore.BlobMetadataStore, metadataCacheSize int, maxIOConcurrency int, - relayIDs []v2.RelayKey) (*metadataProvider, error) { + relayIDs []v2.RelayKey, + blobParamsMap *v2.BlobVersionParameterMap, +) (*metadataProvider, error) { relayIDSet := make(map[v2.RelayKey]struct{}, len(relayIDs)) for _, id := range relayIDs { @@ -62,6 +67,7 @@ func newMetadataProvider( metadataStore: metadataStore, relayIDSet: relayIDSet, } + server.blobParamsMap.Store(blobParamsMap) metadataCache, err := cache.NewCachedAccessor[v2.BlobKey, *blobMetadata]( metadataCacheSize, @@ -141,8 +147,17 @@ func (m *metadataProvider) GetMetadataForBlobs(keys []v2.BlobKey) (metadataMap, return mMap, nil } +func (m *metadataProvider) UpdateBlobVersionParameters(blobParamsMap *v2.BlobVersionParameterMap) { + m.blobParamsMap.Store(blobParamsMap) +} + // fetchMetadata retrieves metadata about a blob. Fetches from the cache if available, otherwise from the store. func (m *metadataProvider) fetchMetadata(key v2.BlobKey) (*blobMetadata, error) { + blobParamsMap := m.blobParamsMap.Load() + if blobParamsMap == nil { + return nil, fmt.Errorf("blob version parameters is nil") + } + // Retrieve the metadata from the store. cert, fragmentInfo, err := m.metadataStore.GetBlobCertificate(m.ctx, key) if err != nil { @@ -165,7 +180,11 @@ func (m *metadataProvider) fetchMetadata(key v2.BlobKey) (*blobMetadata, error) // TODO(cody-littley): blob size is not correct https://github.com/Layr-Labs/eigenda/pull/906#discussion_r1847396530 blobSize := uint32(cert.BlobHeader.BlobCommitments.Length) * encoding.BYTES_PER_SYMBOL - chunkSize, err := v2.GetChunkLength(cert.BlobHeader.BlobVersion, blobSize) + blobParams, ok := blobParamsMap.Get(cert.BlobHeader.BlobVersion) + if !ok { + return nil, fmt.Errorf("blob version %d not found in blob params map", cert.BlobHeader.BlobVersion) + } + chunkSize, err := v2.GetChunkLength(blobSize, blobParams) chunkSize *= encoding.BYTES_PER_SYMBOL if err != nil { return nil, fmt.Errorf("error getting chunk length: %w", err) diff --git a/relay/metadata_provider_test.go b/relay/metadata_provider_test.go index 32e5a3e80c..228ec83264 100644 --- a/relay/metadata_provider_test.go +++ b/relay/metadata_provider_test.go @@ -23,7 +23,7 @@ func TestGetNonExistentBlob(t *testing.T) { defer teardown() metadataStore := buildMetadataStore(t) - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil) + server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Try to fetch a non-existent blobs @@ -81,7 +81,7 @@ func TestFetchingIndividualMetadata(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil) + server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Fetch the metadata from the server. @@ -157,7 +157,7 @@ func TestBatchedFetch(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil) + server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Each iteration, choose a random subset of the keys to fetch @@ -255,7 +255,7 @@ func TestIndividualFetchWithSharding(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, shardList) + server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, shardList, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Fetch the metadata from the server. @@ -379,7 +379,7 @@ func TestBatchedFetchWithSharding(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, shardList) + server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, shardList, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Each iteration, choose two random keys to fetch. There will be a 25% chance that both blobs map to valid shards. diff --git a/relay/relay_test_utils.go b/relay/relay_test_utils.go index 9e99abe929..2a075a8294 100644 --- a/relay/relay_test_utils.go +++ b/relay/relay_test_utils.go @@ -20,6 +20,8 @@ import ( test_utils "github.com/Layr-Labs/eigenda/common/aws/dynamodb/utils" "github.com/Layr-Labs/eigenda/common/aws/s3" tu "github.com/Layr-Labs/eigenda/common/testutils" + "github.com/Layr-Labs/eigenda/core" + coremock "github.com/Layr-Labs/eigenda/core/mock" v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/disperser/common/v2/blobstore" "github.com/Layr-Labs/eigenda/encoding" @@ -32,6 +34,7 @@ import ( "github.com/Layr-Labs/eigensdk-go/logging" "github.com/google/uuid" "github.com/ory/dockertest/v3" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -176,6 +179,24 @@ func buildChunkStore(t *testing.T, logger logging.Logger) (chunkstore.ChunkReade return chunkReader, chunkWriter } +func newMockChainReader() *coremock.MockWriter { + w := &coremock.MockWriter{} + w.On("GetAllVersionedBlobParams", mock.Anything).Return(mockBlobParamsMap(), nil) + return w +} + +func mockBlobParamsMap() map[uint8]*core.BlobVersionParameters { + blobParams := &core.BlobVersionParameters{ + NumChunks: 8192, + CodingRate: 8, + MaxNumOperators: 3537, + } + + return map[v2.BlobVersion]*core.BlobVersionParameters{ + 0: blobParams, + } +} + func randomBlob(t *testing.T) (*v2.BlobHeader, []byte) { data := tu.RandomBytes(225) // TODO talk to Ian about this diff --git a/relay/server.go b/relay/server.go index 730a13f82d..32267de763 100644 --- a/relay/server.go +++ b/relay/server.go @@ -54,6 +54,9 @@ type Server struct { // authenticator is used to authenticate requests to the relay service. authenticator auth.RequestAuthenticator + + // chainReader is the core.Reader used to fetch blob parameters. + chainReader core.Reader } type Config struct { @@ -104,6 +107,9 @@ type Config struct { // AuthenticationDisabled will disable authentication if set to true. AuthenticationDisabled bool + + // OnchainStateRefreshInterval is the interval at which the onchain state is refreshed. + OnchainStateRefreshInterval time.Duration } // NewServer creates a new relay Server. @@ -114,7 +120,17 @@ func NewServer( metadataStore *blobstore.BlobMetadataStore, blobStore *blobstore.BlobStore, chunkReader chunkstore.ChunkReader, - ics core.IndexedChainState) (*Server, error) { + chainReader core.Reader, + ics core.IndexedChainState, +) (*Server, error) { + if chainReader == nil { + return nil, errors.New("chainReader is required") + } + + blobParams, err := chainReader.GetAllVersionedBlobParams(ctx) + if err != nil { + return nil, fmt.Errorf("error fetching blob params: %w", err) + } mp, err := newMetadataProvider( ctx, @@ -122,7 +138,9 @@ func NewServer( metadataStore, config.MetadataCacheSize, config.MetadataMaxConcurrency, - config.RelayIDs) + config.RelayIDs, + v2.NewBlobVersionParameterMap(blobParams), + ) if err != nil { return nil, fmt.Errorf("error creating metadata provider: %w", err) } @@ -399,7 +417,13 @@ func computeChunkRequestRequiredBandwidth(request *pb.GetChunksRequest, mMap met } // Start starts the server listening for requests. This method will block until the server is stopped. -func (s *Server) Start() error { +func (s *Server) Start(ctx context.Context) error { + if s.chainReader != nil && s.metadataProvider != nil { + go func() { + _ = s.RefreshOnchainState(ctx) + }() + } + // Serve grpc requests addr := fmt.Sprintf("0.0.0.0:%d", s.config.GRPCPort) listener, err := net.Listen("tcp", addr) @@ -426,6 +450,26 @@ func (s *Server) Start() error { return nil } +func (s *Server) RefreshOnchainState(ctx context.Context) error { + ticker := time.NewTicker(s.config.OnchainStateRefreshInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + s.logger.Info("refreshing onchain state") + blobParams, err := s.chainReader.GetAllVersionedBlobParams(ctx) + if err != nil { + s.logger.Error("error fetching blob params", "err", err) + continue + } + s.metadataProvider.UpdateBlobVersionParameters(v2.NewBlobVersionParameterMap(blobParams)) + case <-ctx.Done(): + return ctx.Err() + } + } +} + // Stop stops the server. func (s *Server) Stop() { if s.grpcServer != nil { diff --git a/relay/server_test.go b/relay/server_test.go index f67a8fb650..baaf873150 100644 --- a/relay/server_test.go +++ b/relay/server_test.go @@ -94,6 +94,7 @@ func TestReadWriteBlobs(t *testing.T) { // These are used to write data to S3/dynamoDB metadataStore := buildMetadataStore(t) blobStore := buildBlobStore(t, logger) + chainReader := newMockChainReader() // This is the server used to read it back config := defaultConfig() @@ -104,11 +105,12 @@ func TestReadWriteBlobs(t *testing.T) { metadataStore, blobStore, nil, /* not used in this test*/ + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() @@ -175,6 +177,7 @@ func TestReadNonExistentBlob(t *testing.T) { // This is the server used to read it back config := defaultConfig() + chainReader := newMockChainReader() server, err := NewServer( context.Background(), logger, @@ -182,11 +185,12 @@ func TestReadNonExistentBlob(t *testing.T) { metadataStore, blobStore, nil, /* not used in this test */ + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() @@ -228,6 +232,7 @@ func TestReadWriteBlobsWithSharding(t *testing.T) { // This is the server used to read it back config := defaultConfig() config.RelayIDs = shardList + chainReader := newMockChainReader() server, err := NewServer( context.Background(), logger, @@ -235,11 +240,12 @@ func TestReadWriteBlobsWithSharding(t *testing.T) { metadataStore, blobStore, nil, /* not used in this test*/ + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() @@ -346,6 +352,7 @@ func TestReadWriteChunks(t *testing.T) { config.RateLimits.GetChunkOpsBurstiness = 1000 config.RateLimits.MaxGetChunkOpsPerSecondClient = 1000 config.RateLimits.GetChunkOpsBurstinessClient = 1000 + chainReader := newMockChainReader() server, err := NewServer( context.Background(), logger, @@ -353,11 +360,12 @@ func TestReadWriteChunks(t *testing.T) { metadataStore, nil, /* not used in this test*/ chunkReader, + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() @@ -542,6 +550,7 @@ func TestBatchedReadWriteChunks(t *testing.T) { // This is the server used to read it back config := defaultConfig() + chainReader := newMockChainReader() server, err := NewServer( context.Background(), logger, @@ -549,11 +558,12 @@ func TestBatchedReadWriteChunks(t *testing.T) { metadataStore, nil, /* not used in this test */ chunkReader, + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() @@ -668,6 +678,7 @@ func TestReadWriteChunksWithSharding(t *testing.T) { config.RateLimits.GetChunkOpsBurstiness = 1000 config.RateLimits.MaxGetChunkOpsPerSecondClient = 1000 config.RateLimits.GetChunkOpsBurstinessClient = 1000 + chainReader := newMockChainReader() server, err := NewServer( context.Background(), logger, @@ -675,11 +686,12 @@ func TestReadWriteChunksWithSharding(t *testing.T) { metadataStore, nil, /* not used in this test*/ chunkReader, + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() @@ -943,6 +955,7 @@ func TestBatchedReadWriteChunksWithSharding(t *testing.T) { config.RateLimits.GetChunkOpsBurstiness = 1000 config.RateLimits.MaxGetChunkOpsPerSecondClient = 1000 config.RateLimits.GetChunkOpsBurstinessClient = 1000 + chainReader := newMockChainReader() server, err := NewServer( context.Background(), logger, @@ -950,11 +963,12 @@ func TestBatchedReadWriteChunksWithSharding(t *testing.T) { metadataStore, nil, /* not used in this test */ chunkReader, + chainReader, nil /* not used in this test*/) require.NoError(t, err) go func() { - err = server.Start() + err = server.Start(context.Background()) require.NoError(t, err) }() defer server.Stop() From 12619f1f34b4d202d3f54ab2ea079d9081f78b4d Mon Sep 17 00:00:00 2001 From: Bowen Xue <93296844+bxue-l2@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:23:03 -0800 Subject: [PATCH 02/15] add pprof to disperser (#927) Co-authored-by: Ubuntu --- disperser/apiserver/pprof.go | 31 ++++++++++++++++++++++++++ disperser/apiserver/server.go | 6 +++++ disperser/cmd/apiserver/config.go | 6 +++-- disperser/cmd/apiserver/flags/flags.go | 15 +++++++++++++ disperser/server_config.go | 3 +++ go.mod | 2 +- 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 disperser/apiserver/pprof.go diff --git a/disperser/apiserver/pprof.go b/disperser/apiserver/pprof.go new file mode 100644 index 0000000000..606b8aa09e --- /dev/null +++ b/disperser/apiserver/pprof.go @@ -0,0 +1,31 @@ +package apiserver + +import ( + "fmt" + "net/http" + + _ "net/http/pprof" + + "github.com/Layr-Labs/eigensdk-go/logging" +) + +type PprofProfiler struct { + logger logging.Logger + httpPort string +} + +func NewPprofProfiler(httpPort string, logger logging.Logger) *PprofProfiler { + return &PprofProfiler{ + logger: logger.With("component", "PprofProfiler"), + httpPort: httpPort, + } +} + +// Start the pprof server +func (p *PprofProfiler) Start(logger logging.Logger) { + pprofAddr := fmt.Sprintf("%s:%s", "0.0.0.0", p.httpPort) + + if err := http.ListenAndServe(pprofAddr, nil); err != nil { + p.logger.Error("pprof server failed", "error", err, "pprofAddr", pprofAddr) + } +} diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 87e82b5a10..34f60efd41 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -819,6 +819,12 @@ func (s *DispersalServer) GetRateConfig() *RateConfig { } func (s *DispersalServer) Start(ctx context.Context) error { + pprofProfiler := NewPprofProfiler(s.serverConfig.PprofHttpPort, s.logger) + if s.serverConfig.EnablePprof { + go pprofProfiler.Start(s.logger) + s.logger.Info("Enabled pprof for disperser apiserver", "port", s.serverConfig.PprofHttpPort) + } + go func() { t := time.NewTicker(s.rateConfig.AllowlistRefreshInterval) defer t.Stop() diff --git a/disperser/cmd/apiserver/config.go b/disperser/cmd/apiserver/config.go index 6e25b8af65..a27bd0b793 100644 --- a/disperser/cmd/apiserver/config.go +++ b/disperser/cmd/apiserver/config.go @@ -95,8 +95,10 @@ func NewConfig(ctx *cli.Context) (Config, error) { DisperserVersion: DisperserVersion(version), AwsClientConfig: aws.ReadClientConfig(ctx, flags.FlagPrefix), ServerConfig: disperser.ServerConfig{ - GrpcPort: ctx.GlobalString(flags.GrpcPortFlag.Name), - GrpcTimeout: ctx.GlobalDuration(flags.GrpcTimeoutFlag.Name), + GrpcPort: ctx.GlobalString(flags.GrpcPortFlag.Name), + GrpcTimeout: ctx.GlobalDuration(flags.GrpcTimeoutFlag.Name), + PprofHttpPort: ctx.GlobalString(flags.PprofHttpPort.Name), + EnablePprof: ctx.GlobalBool(flags.EnablePprof.Name), }, BlobstoreConfig: blobstore.Config{ BucketName: ctx.GlobalString(flags.S3BucketNameFlag.Name), diff --git a/disperser/cmd/apiserver/flags/flags.go b/disperser/cmd/apiserver/flags/flags.go index 4bffb6f67e..af31d87ff9 100644 --- a/disperser/cmd/apiserver/flags/flags.go +++ b/disperser/cmd/apiserver/flags/flags.go @@ -155,6 +155,19 @@ var ( EnvVar: common.PrefixEnvVar(envVarPrefix, "MAX_NUM_SYMBOLS_PER_BLOB"), Required: false, } + PprofHttpPort = cli.StringFlag{ + Name: common.PrefixFlag(FlagPrefix, "pprof-http-port"), + Usage: "the http port which the pprof server is listening", + Required: false, + Value: "6060", + EnvVar: common.PrefixEnvVar(envVarPrefix, "PPROF_HTTP_PORT"), + } + EnablePprof = cli.BoolFlag{ + Name: common.PrefixFlag(FlagPrefix, "enable-pprof"), + Usage: "start prrof server", + Required: false, + EnvVar: common.PrefixEnvVar(envVarPrefix, "ENABLE_PPROF"), + } ) var kzgFlags = []cli.Flag{ @@ -247,6 +260,8 @@ var optionalFlags = []cli.Flag{ GlobalRateTableName, OnchainStateRefreshInterval, MaxNumSymbolsPerBlob, + PprofHttpPort, + EnablePprof, } // Flags contains the list of configuration options available to the binary. diff --git a/disperser/server_config.go b/disperser/server_config.go index b094fca2a6..152ff675c7 100644 --- a/disperser/server_config.go +++ b/disperser/server_config.go @@ -9,4 +9,7 @@ const ( type ServerConfig struct { GrpcPort string GrpcTimeout time.Duration + + PprofHttpPort string + EnablePprof bool } diff --git a/go.mod b/go.mod index 38c95f9157..45e0bbe49a 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( go.uber.org/mock v0.4.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.8.0 + golang.org/x/time v0.5.0 google.golang.org/grpc v1.64.1 ) @@ -151,7 +152,6 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.4.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect From 7164f3bea17298beba9daef4e5d8afcc9d67fa53 Mon Sep 17 00:00:00 2001 From: Bowen Xue <93296844+bxue-l2@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:54:06 -0800 Subject: [PATCH 03/15] remove s.logger (#929) Co-authored-by: Ubuntu --- disperser/apiserver/pprof.go | 2 +- disperser/apiserver/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/disperser/apiserver/pprof.go b/disperser/apiserver/pprof.go index 606b8aa09e..db3847b3d3 100644 --- a/disperser/apiserver/pprof.go +++ b/disperser/apiserver/pprof.go @@ -22,7 +22,7 @@ func NewPprofProfiler(httpPort string, logger logging.Logger) *PprofProfiler { } // Start the pprof server -func (p *PprofProfiler) Start(logger logging.Logger) { +func (p *PprofProfiler) Start() { pprofAddr := fmt.Sprintf("%s:%s", "0.0.0.0", p.httpPort) if err := http.ListenAndServe(pprofAddr, nil); err != nil { diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 34f60efd41..6c9be3c54f 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -821,7 +821,7 @@ func (s *DispersalServer) GetRateConfig() *RateConfig { func (s *DispersalServer) Start(ctx context.Context) error { pprofProfiler := NewPprofProfiler(s.serverConfig.PprofHttpPort, s.logger) if s.serverConfig.EnablePprof { - go pprofProfiler.Start(s.logger) + go pprofProfiler.Start() s.logger.Info("Enabled pprof for disperser apiserver", "port", s.serverConfig.PprofHttpPort) } From 0a4e8528afff9c7d016e6a8dd2981a8ba8d2433b Mon Sep 17 00:00:00 2001 From: Jian Xiao <99709935+jianoaix@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:03:13 -0800 Subject: [PATCH 04/15] Optimize the Disperser perf (#930) --- common/aws/s3/client.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/common/aws/s3/client.go b/common/aws/s3/client.go index 3b773140c8..8bb35b37f3 100644 --- a/common/aws/s3/client.go +++ b/common/aws/s3/client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "fmt" "runtime" "sync" @@ -105,15 +106,32 @@ func NewClient(ctx context.Context, cfg commonaws.ClientConfig, logger logging.L return ref, err } +func PeekObjectSize(ctx context.Context, s3Client *s3.Client, bucket, key string) (int64, error) { + input := &s3.HeadObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(key), + } + result, err := s3Client.HeadObject(ctx, input) + if err != nil { + return 0, fmt.Errorf("failed to head object: %w", err) + } + return *result.ContentLength, nil +} + func (s *client) DownloadObject(ctx context.Context, bucket string, key string) ([]byte, error) { + size, err := PeekObjectSize(ctx, s.s3Client, bucket, key) + if err != nil { + return nil, err + } + buffer := manager.NewWriteAtBuffer(make([]byte, 0, size)) + var partMiBs int64 = 10 downloader := manager.NewDownloader(s.s3Client, func(d *manager.Downloader) { d.PartSize = partMiBs * 1024 * 1024 // 10MB per part d.Concurrency = 3 //The number of goroutines to spin up in parallel per call to Upload when sending parts }) - buffer := manager.NewWriteAtBuffer([]byte{}) - _, err := downloader.Download(ctx, buffer, &s3.GetObjectInput{ + _, err = downloader.Download(ctx, buffer, &s3.GetObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), }) From ac7ffdd9c18d4c115fe24c705d36224603fd4544 Mon Sep 17 00:00:00 2001 From: Cody Littley <56973212+cody-littley@users.noreply.github.com> Date: Mon, 25 Nov 2024 08:55:36 -0600 Subject: [PATCH 05/15] Relay timeouts (#918) Signed-off-by: Cody Littley --- common/aws/cli.go | 10 -- common/aws/s3/client.go | 6 - relay/auth/authenticator.go | 15 +- relay/auth/authenticator_test.go | 29 +++- relay/blob_provider.go | 24 ++-- relay/blob_provider_test.go | 23 +++- relay/cache/cached_accessor.go | 59 ++++++-- relay/cache/cached_accessor_test.go | 203 ++++++++++++++++++++++++++-- relay/chunk_provider.go | 31 ++++- relay/chunk_provider_test.go | 19 ++- relay/cmd/config.go | 8 ++ relay/cmd/flags/flags.go | 50 +++++++ relay/metadata_provider.go | 19 ++- relay/metadata_provider_test.go | 68 ++++++++-- relay/relay_test_utils.go | 28 ++-- relay/server.go | 40 ++++-- relay/server_test.go | 9 ++ relay/timeout_config.go | 26 ++++ 18 files changed, 547 insertions(+), 120 deletions(-) create mode 100644 relay/timeout_config.go diff --git a/common/aws/cli.go b/common/aws/cli.go index d1b3bf274a..e646712175 100644 --- a/common/aws/cli.go +++ b/common/aws/cli.go @@ -37,12 +37,6 @@ type ClientConfig struct { // FragmentParallelismConstant helps determine the size of the pool of workers to help upload/download files. // A non-zero value for this parameter adds a constant number of workers. Default is 0. FragmentParallelismConstant int - // FragmentReadTimeout is used to bound the maximum time to wait for a single fragmented read. - // Default is 30 seconds. - FragmentReadTimeout time.Duration - // FragmentWriteTimeout is used to bound the maximum time to wait for a single fragmented write. - // Default is 30 seconds. - FragmentWriteTimeout time.Duration } func ClientFlags(envPrefix string, flagPrefix string) []cli.Flag { @@ -120,8 +114,6 @@ func ReadClientConfig(ctx *cli.Context, flagPrefix string) ClientConfig { EndpointURL: ctx.GlobalString(common.PrefixFlag(flagPrefix, EndpointURLFlagName)), FragmentParallelismFactor: ctx.GlobalInt(common.PrefixFlag(flagPrefix, FragmentParallelismFactorFlagName)), FragmentParallelismConstant: ctx.GlobalInt(common.PrefixFlag(flagPrefix, FragmentParallelismConstantFlagName)), - FragmentReadTimeout: ctx.GlobalDuration(common.PrefixFlag(flagPrefix, FragmentReadTimeoutFlagName)), - FragmentWriteTimeout: ctx.GlobalDuration(common.PrefixFlag(flagPrefix, FragmentWriteTimeoutFlagName)), } } @@ -131,7 +123,5 @@ func DefaultClientConfig() *ClientConfig { Region: "us-east-2", FragmentParallelismFactor: 8, FragmentParallelismConstant: 0, - FragmentReadTimeout: 30 * time.Second, - FragmentWriteTimeout: 30 * time.Second, } } diff --git a/common/aws/s3/client.go b/common/aws/s3/client.go index 8bb35b37f3..c3ae159d41 100644 --- a/common/aws/s3/client.go +++ b/common/aws/s3/client.go @@ -241,9 +241,6 @@ func (s *client) FragmentedUploadObject( } resultChannel := make(chan error, len(fragments)) - ctx, cancel := context.WithTimeout(ctx, s.cfg.FragmentWriteTimeout) - defer cancel() - for _, fragment := range fragments { fragmentCapture := fragment s.concurrencyLimiter <- struct{}{} @@ -301,9 +298,6 @@ func (s *client) FragmentedDownloadObject( } resultChannel := make(chan *readResult, len(fragmentKeys)) - ctx, cancel := context.WithTimeout(ctx, s.cfg.FragmentWriteTimeout) - defer cancel() - for i, fragmentKey := range fragmentKeys { boundFragmentKey := fragmentKey boundI := i diff --git a/relay/auth/authenticator.go b/relay/auth/authenticator.go index a85c1f4865..2e89c83d18 100644 --- a/relay/auth/authenticator.go +++ b/relay/auth/authenticator.go @@ -17,6 +17,7 @@ type RequestAuthenticator interface { // The origin is the address of the peer that sent the request. This may be used to cache auth results // in order to save server resources. AuthenticateGetChunksRequest( + ctx context.Context, origin string, request *pb.GetChunksRequest, now time.Time) error @@ -53,6 +54,7 @@ type requestAuthenticator struct { // NewRequestAuthenticator creates a new RequestAuthenticator. func NewRequestAuthenticator( + ctx context.Context, ics core.IndexedChainState, keyCacheSize int, authenticationTimeoutDuration time.Duration) (RequestAuthenticator, error) { @@ -70,7 +72,7 @@ func NewRequestAuthenticator( keyCache: keyCache, } - err = authenticator.preloadCache() + err = authenticator.preloadCache(ctx) if err != nil { return nil, fmt.Errorf("failed to preload cache: %w", err) } @@ -78,12 +80,12 @@ func NewRequestAuthenticator( return authenticator, nil } -func (a *requestAuthenticator) preloadCache() error { +func (a *requestAuthenticator) preloadCache(ctx context.Context) error { blockNumber, err := a.ics.GetCurrentBlockNumber() if err != nil { return fmt.Errorf("failed to get current block number: %w", err) } - operators, err := a.ics.GetIndexedOperators(context.Background(), blockNumber) + operators, err := a.ics.GetIndexedOperators(ctx, blockNumber) if err != nil { return fmt.Errorf("failed to get operators: %w", err) } @@ -96,6 +98,7 @@ func (a *requestAuthenticator) preloadCache() error { } func (a *requestAuthenticator) AuthenticateGetChunksRequest( + ctx context.Context, origin string, request *pb.GetChunksRequest, now time.Time) error { @@ -105,7 +108,7 @@ func (a *requestAuthenticator) AuthenticateGetChunksRequest( return nil } - key, err := a.getOperatorKey(core.OperatorID(request.OperatorId)) + key, err := a.getOperatorKey(ctx, core.OperatorID(request.OperatorId)) if err != nil { return fmt.Errorf("failed to get operator key: %w", err) } @@ -131,7 +134,7 @@ func (a *requestAuthenticator) AuthenticateGetChunksRequest( } // getOperatorKey returns the public key of the operator with the given ID, caching the result. -func (a *requestAuthenticator) getOperatorKey(operatorID core.OperatorID) (*core.G2Point, error) { +func (a *requestAuthenticator) getOperatorKey(ctx context.Context, operatorID core.OperatorID) (*core.G2Point, error) { key, ok := a.keyCache.Get(operatorID) if ok { return key, nil @@ -141,7 +144,7 @@ func (a *requestAuthenticator) getOperatorKey(operatorID core.OperatorID) (*core if err != nil { return nil, fmt.Errorf("failed to get current block number: %w", err) } - operators, err := a.ics.GetIndexedOperators(context.Background(), blockNumber) + operators, err := a.ics.GetIndexedOperators(ctx, blockNumber) if err != nil { return nil, fmt.Errorf("failed to get operators: %w", err) } diff --git a/relay/auth/authenticator_test.go b/relay/auth/authenticator_test.go index debcbccc61..8569376984 100644 --- a/relay/auth/authenticator_test.go +++ b/relay/auth/authenticator_test.go @@ -15,6 +15,8 @@ import ( func TestMockSigning(t *testing.T) { tu.InitializeRandom() + ctx := context.Background() + operatorID := mock.MakeOperatorId(0) stakes := map[core.QuorumID]map[core.OperatorID]int{ core.QuorumID(0): { @@ -24,7 +26,7 @@ func TestMockSigning(t *testing.T) { ics, err := mock.NewChainDataMock(stakes) require.NoError(t, err) - operators, err := ics.GetIndexedOperators(context.Background(), 0) + operators, err := ics.GetIndexedOperators(ctx, 0) require.NoError(t, err) operator, ok := operators[operatorID] @@ -46,6 +48,8 @@ func TestMockSigning(t *testing.T) { func TestValidRequest(t *testing.T) { tu.InitializeRandom() + ctx := context.Background() + operatorID := mock.MakeOperatorId(0) stakes := map[core.QuorumID]map[core.OperatorID]int{ core.QuorumID(0): { @@ -58,7 +62,7 @@ func TestValidRequest(t *testing.T) { timeout := 10 * time.Second - authenticator, err := NewRequestAuthenticator(ics, 1024, timeout) + authenticator, err := NewRequestAuthenticator(ctx, ics, 1024, timeout) require.NoError(t, err) request := randomGetChunksRequest() @@ -69,6 +73,7 @@ func TestValidRequest(t *testing.T) { now := time.Now() err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", request, now) @@ -83,12 +88,14 @@ func TestValidRequest(t *testing.T) { start := now for now.Before(start.Add(timeout)) { err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", invalidRequest, now) require.NoError(t, err) err = authenticator.AuthenticateGetChunksRequest( + ctx, "baz", invalidRequest, now) @@ -99,6 +106,7 @@ func TestValidRequest(t *testing.T) { // After the timeout elapses, new requests should trigger authentication. err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", invalidRequest, now) @@ -108,6 +116,8 @@ func TestValidRequest(t *testing.T) { func TestAuthenticationSavingDisabled(t *testing.T) { tu.InitializeRandom() + ctx := context.Background() + operatorID := mock.MakeOperatorId(0) stakes := map[core.QuorumID]map[core.OperatorID]int{ core.QuorumID(0): { @@ -121,7 +131,7 @@ func TestAuthenticationSavingDisabled(t *testing.T) { // This disables saving of authentication results. timeout := time.Duration(0) - authenticator, err := NewRequestAuthenticator(ics, 1024, timeout) + authenticator, err := NewRequestAuthenticator(ctx, ics, 1024, timeout) require.NoError(t, err) request := randomGetChunksRequest() @@ -132,6 +142,7 @@ func TestAuthenticationSavingDisabled(t *testing.T) { now := time.Now() err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", request, now) @@ -144,6 +155,7 @@ func TestAuthenticationSavingDisabled(t *testing.T) { invalidRequest.OperatorSignature = signature // the previous signature is invalid here err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", invalidRequest, now) @@ -153,6 +165,8 @@ func TestAuthenticationSavingDisabled(t *testing.T) { func TestNonExistingClient(t *testing.T) { tu.InitializeRandom() + ctx := context.Background() + operatorID := mock.MakeOperatorId(0) stakes := map[core.QuorumID]map[core.OperatorID]int{ core.QuorumID(0): { @@ -165,7 +179,7 @@ func TestNonExistingClient(t *testing.T) { timeout := 10 * time.Second - authenticator, err := NewRequestAuthenticator(ics, 1024, timeout) + authenticator, err := NewRequestAuthenticator(ctx, ics, 1024, timeout) require.NoError(t, err) invalidOperatorID := tu.RandomBytes(32) @@ -174,6 +188,7 @@ func TestNonExistingClient(t *testing.T) { request.OperatorId = invalidOperatorID err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", request, time.Now()) @@ -183,6 +198,8 @@ func TestNonExistingClient(t *testing.T) { func TestBadSignature(t *testing.T) { tu.InitializeRandom() + ctx := context.Background() + operatorID := mock.MakeOperatorId(0) stakes := map[core.QuorumID]map[core.OperatorID]int{ core.QuorumID(0): { @@ -195,7 +212,7 @@ func TestBadSignature(t *testing.T) { timeout := 10 * time.Second - authenticator, err := NewRequestAuthenticator(ics, 1024, timeout) + authenticator, err := NewRequestAuthenticator(ctx, ics, 1024, timeout) require.NoError(t, err) request := randomGetChunksRequest() @@ -205,6 +222,7 @@ func TestBadSignature(t *testing.T) { now := time.Now() err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", request, now) @@ -217,6 +235,7 @@ func TestBadSignature(t *testing.T) { request.OperatorSignature[0] = request.OperatorSignature[0] ^ 1 err = authenticator.AuthenticateGetChunksRequest( + ctx, "foobar", request, now) diff --git a/relay/blob_provider.go b/relay/blob_provider.go index 44157f6069..9b9863bfda 100644 --- a/relay/blob_provider.go +++ b/relay/blob_provider.go @@ -7,6 +7,7 @@ import ( "github.com/Layr-Labs/eigenda/disperser/common/v2/blobstore" "github.com/Layr-Labs/eigenda/relay/cache" "github.com/Layr-Labs/eigensdk-go/logging" + "time" ) // blobProvider encapsulates logic for fetching blobs. Utilized by the relay Server. @@ -20,6 +21,9 @@ type blobProvider struct { // blobCache is an LRU cache of blobs. blobCache cache.CachedAccessor[v2.BlobKey, []byte] + + // fetchTimeout is the maximum time to wait for a blob fetch operation to complete. + fetchTimeout time.Duration } // newBlobProvider creates a new blobProvider. @@ -28,12 +32,14 @@ func newBlobProvider( logger logging.Logger, blobStore *blobstore.BlobStore, blobCacheSize int, - maxIOConcurrency int) (*blobProvider, error) { + maxIOConcurrency int, + fetchTimeout time.Duration) (*blobProvider, error) { server := &blobProvider{ - ctx: ctx, - logger: logger, - blobStore: blobStore, + ctx: ctx, + logger: logger, + blobStore: blobStore, + fetchTimeout: fetchTimeout, } c, err := cache.NewCachedAccessor[v2.BlobKey, []byte](blobCacheSize, maxIOConcurrency, server.fetchBlob) @@ -46,9 +52,8 @@ func newBlobProvider( } // GetBlob retrieves a blob from the blob store. -func (s *blobProvider) GetBlob(blobKey v2.BlobKey) ([]byte, error) { - - data, err := s.blobCache.Get(blobKey) +func (s *blobProvider) GetBlob(ctx context.Context, blobKey v2.BlobKey) ([]byte, error) { + data, err := s.blobCache.Get(ctx, blobKey) if err != nil { // It should not be possible for external users to force an error here since we won't @@ -62,7 +67,10 @@ func (s *blobProvider) GetBlob(blobKey v2.BlobKey) ([]byte, error) { // fetchBlob retrieves a single blob from the blob store. func (s *blobProvider) fetchBlob(blobKey v2.BlobKey) ([]byte, error) { - data, err := s.blobStore.GetBlob(s.ctx, blobKey) + ctx, cancel := context.WithTimeout(s.ctx, s.fetchTimeout) + defer cancel() + + data, err := s.blobStore.GetBlob(ctx, blobKey) if err != nil { s.logger.Errorf("Failed to fetch blob: %v", err) return nil, err diff --git a/relay/blob_provider_test.go b/relay/blob_provider_test.go index 6e996977bb..9309461c65 100644 --- a/relay/blob_provider_test.go +++ b/relay/blob_provider_test.go @@ -7,6 +7,7 @@ import ( v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/stretchr/testify/require" "testing" + "time" ) func TestReadWrite(t *testing.T) { @@ -34,12 +35,18 @@ func TestReadWrite(t *testing.T) { require.NoError(t, err) } - server, err := newBlobProvider(context.Background(), logger, blobStore, 10, 32) + server, err := newBlobProvider( + context.Background(), + logger, + blobStore, + 10, + 32, + 10*time.Second) require.NoError(t, err) // Read the blobs back. for key, data := range expectedData { - blob, err := server.GetBlob(key) + blob, err := server.GetBlob(context.Background(), key) require.NoError(t, err) require.Equal(t, data, blob) @@ -47,7 +54,7 @@ func TestReadWrite(t *testing.T) { // Read the blobs back again to test caching. for key, data := range expectedData { - blob, err := server.GetBlob(key) + blob, err := server.GetBlob(context.Background(), key) require.NoError(t, err) require.Equal(t, data, blob) @@ -65,11 +72,17 @@ func TestNonExistentBlob(t *testing.T) { blobStore := buildBlobStore(t, logger) - server, err := newBlobProvider(context.Background(), logger, blobStore, 10, 32) + server, err := newBlobProvider( + context.Background(), + logger, + blobStore, + 10, + 32, + 10*time.Second) require.NoError(t, err) for i := 0; i < 10; i++ { - blob, err := server.GetBlob(v2.BlobKey(tu.RandomBytes(32))) + blob, err := server.GetBlob(context.Background(), v2.BlobKey(tu.RandomBytes(32))) require.Error(t, err) require.Nil(t, blob) } diff --git a/relay/cache/cached_accessor.go b/relay/cache/cached_accessor.go index e39a3a3910..d131229082 100644 --- a/relay/cache/cached_accessor.go +++ b/relay/cache/cached_accessor.go @@ -1,7 +1,9 @@ package cache import ( + "context" lru "github.com/hashicorp/golang-lru/v2" + "golang.org/x/sync/semaphore" "sync" ) @@ -9,7 +11,9 @@ import ( // are expensive, and prevents multiple concurrent cache misses for the same key. type CachedAccessor[K comparable, V any] interface { // Get returns the value for the given key. If the value is not in the cache, it will be fetched using the Accessor. - Get(key K) (V, error) + // If the context is cancelled, the function may abort early. If multiple goroutines request the same key, + // cancellation of one request will not affect the others. + Get(ctx context.Context, key K) (V, error) } // Accessor is function capable of fetching a value from a resource. Used by CachedAccessor when there is a cache miss. @@ -17,8 +21,8 @@ type Accessor[K comparable, V any] func(key K) (V, error) // accessResult is a struct that holds the result of an Accessor call. type accessResult[V any] struct { - // wg.Wait() will block until the value is fetched. - wg sync.WaitGroup + // sem is a semaphore used to signal that the value has been fetched. + sem *semaphore.Weighted // value is the value fetched by the Accessor, or nil if there was an error. value V // err is the error returned by the Accessor, or nil if the fetch was successful. @@ -34,7 +38,6 @@ var _ CachedAccessor[string, string] = &cachedAccessor[string, string]{} // cachedAccessor is an implementation of CachedAccessor. type cachedAccessor[K comparable, V any] struct { - // lookupsInProgress has an entry for each key that is currently being looked up via the accessor. The value // is written into the channel when it is eventually fetched. If a key is requested more than once while a // lookup in progress, the second (and following) requests will wait for the result of the first lookup @@ -86,14 +89,13 @@ func NewCachedAccessor[K comparable, V any]( func newAccessResult[V any]() *accessResult[V] { result := &accessResult[V]{ - wg: sync.WaitGroup{}, + sem: semaphore.NewWeighted(1), } - result.wg.Add(1) + _ = result.sem.Acquire(context.Background(), 1) return result } -func (c *cachedAccessor[K, V]) Get(key K) (V, error) { - +func (c *cachedAccessor[K, V]) Get(ctx context.Context, key K) (V, error) { c.cacheLock.Lock() // first, attempt to get the value from the cache @@ -114,11 +116,35 @@ func (c *cachedAccessor[K, V]) Get(key K) (V, error) { if alreadyLoading { // The result is being fetched on another goroutine. Wait for it to finish. - result.wg.Wait() - return result.value, result.err + return c.waitForResult(ctx, result) } else { // We are the first goroutine to request this key. + return c.fetchResult(ctx, key, result) + } +} +// waitForResult waits for the result of a lookup that was initiated by another requester and returns it +// when it becomes is available. This method will return quickly if the provided context is cancelled. +// Doing so does not disrupt the other requesters that are also waiting for this result. +func (c *cachedAccessor[K, V]) waitForResult(ctx context.Context, result *accessResult[V]) (V, error) { + err := result.sem.Acquire(ctx, 1) + if err != nil { + var zeroValue V + return zeroValue, err + } + + result.sem.Release(1) + return result.value, result.err +} + +// fetchResult fetches the value for the given key and returns it. If the context is cancelled before the value +// is fetched, the function will return early. If the fetch is successful, the value will be added to the cache. +func (c *cachedAccessor[K, V]) fetchResult(ctx context.Context, key K, result *accessResult[V]) (V, error) { + + // Perform the work in a background goroutine. This allows us to return early if the context is cancelled + // without disrupting the fetch operation that other requesters may be waiting for. + waitChan := make(chan struct{}, 1) + go func() { if c.concurrencyLimiter != nil { c.concurrencyLimiter <- struct{}{} } @@ -139,13 +165,22 @@ func (c *cachedAccessor[K, V]) Get(key K) (V, error) { // Provide the result to all other goroutines that may be waiting for it. result.err = err result.value = value - result.wg.Done() + result.sem.Release(1) // Clean up the lookupInProgress map. delete(c.lookupsInProgress, key) c.cacheLock.Unlock() - return value, err + waitChan <- struct{}{} + }() + + select { + case <-ctx.Done(): + // The context was cancelled before the value was fetched, possibly due to a timeout. + var zeroValue V + return zeroValue, ctx.Err() + case <-waitChan: + return result.value, result.err } } diff --git a/relay/cache/cached_accessor_test.go b/relay/cache/cached_accessor_test.go index ab37fa5a2e..9048e3d88a 100644 --- a/relay/cache/cached_accessor_test.go +++ b/relay/cache/cached_accessor_test.go @@ -1,6 +1,7 @@ package cache import ( + "context" "errors" tu "github.com/Layr-Labs/eigenda/common/testutils" "github.com/stretchr/testify/require" @@ -36,7 +37,7 @@ func TestRandomOperationsSingleThread(t *testing.T) { require.NoError(t, err) for i := 0; i < dataSize; i++ { - value, err := ca.Get(i) + value, err := ca.Get(context.Background(), i) if i%17 == 0 { require.Error(t, err) @@ -48,7 +49,7 @@ func TestRandomOperationsSingleThread(t *testing.T) { } for k, v := range baseData { - value, err := ca.Get(k) + value, err := ca.Get(context.Background(), k) if k%17 == 0 { require.Error(t, err) @@ -86,7 +87,7 @@ func TestCacheMisses(t *testing.T) { expectedCacheMissCount := uint64(0) for i := 0; i < cacheSize; i++ { expectedCacheMissCount++ - value, err := ca.Get(i) + value, err := ca.Get(context.Background(), i) require.NoError(t, err) require.Equal(t, baseData[i], *value) require.Equal(t, expectedCacheMissCount, cacheMissCount.Load()) @@ -94,7 +95,7 @@ func TestCacheMisses(t *testing.T) { // Get the first cacheSize keys again. This should not increase the cache miss count. for i := 0; i < cacheSize; i++ { - value, err := ca.Get(i) + value, err := ca.Get(context.Background(), i) require.NoError(t, err) require.Equal(t, baseData[i], *value) require.Equal(t, expectedCacheMissCount, cacheMissCount.Load()) @@ -102,14 +103,14 @@ func TestCacheMisses(t *testing.T) { // Read the last key. This should cause the first key to be evicted. expectedCacheMissCount++ - value, err := ca.Get(cacheSize) + value, err := ca.Get(context.Background(), cacheSize) require.NoError(t, err) require.Equal(t, baseData[cacheSize], *value) // Read the keys in order. Due to the order of evictions, each read should result in a cache miss. for i := 0; i < cacheSize; i++ { expectedCacheMissCount++ - value, err := ca.Get(i) + value, err := ca.Get(context.Background(), i) require.NoError(t, err) require.Equal(t, baseData[i], *value) require.Equal(t, expectedCacheMissCount, cacheMissCount.Load()) @@ -154,7 +155,7 @@ func ParallelAccessTest(t *testing.T, sleepEnabled bool) { for i := 0; i < 10; i++ { go func() { defer wg.Done() - value, err := ca.Get(0) + value, err := ca.Get(context.Background(), 0) require.NoError(t, err) require.Equal(t, baseData[0], *value) }() @@ -177,7 +178,7 @@ func ParallelAccessTest(t *testing.T, sleepEnabled bool) { require.Equal(t, uint64(1), cacheMissCount.Load()) // Fetching the key again should not result in a cache miss. - value, err := ca.Get(0) + value, err := ca.Get(context.Background(), 0) require.NoError(t, err) require.Equal(t, baseData[0], *value) require.Equal(t, uint64(1), cacheMissCount.Load()) @@ -223,7 +224,7 @@ func TestParallelAccessWithError(t *testing.T) { for i := 0; i < 10; i++ { go func() { defer wg.Done() - value, err := ca.Get(0) + value, err := ca.Get(context.Background(), 0) require.Nil(t, value) require.Equal(t, errors.New("intentional error"), err) }() @@ -246,7 +247,7 @@ func TestParallelAccessWithError(t *testing.T) { require.True(t, count >= 1) // Fetching the key again should result in another cache miss since the previous fetch failed. - value, err := ca.Get(0) + value, err := ca.Get(context.Background(), 0) require.Nil(t, value) require.Equal(t, errors.New("intentional error"), err) require.Equal(t, count+1, cacheMissCount.Load()) @@ -291,7 +292,7 @@ func TestConcurrencyLimiter(t *testing.T) { for i := 0; i < dataSize; i++ { boundI := i go func() { - value, err := ca.Get(boundI) + value, err := ca.Get(context.Background(), boundI) require.NoError(t, err) require.Equal(t, baseData[boundI], *value) wg.Done() @@ -310,3 +311,183 @@ func TestConcurrencyLimiter(t *testing.T) { accessorLock.Unlock() wg.Wait() } + +func TestOriginalRequesterTimesOut(t *testing.T) { + tu.InitializeRandom() + + dataSize := 1024 + + baseData := make(map[int]string) + for i := 0; i < dataSize; i++ { + baseData[i] = tu.RandomString(10) + } + + accessorLock := sync.RWMutex{} + cacheMissCount := atomic.Uint64{} + accessor := func(key int) (*string, error) { + + // Intentionally block if accessorLock is held by the outside scope. + // Used to provoke specific race conditions. + accessorLock.Lock() + defer accessorLock.Unlock() + + cacheMissCount.Add(1) + + str := baseData[key] + return &str, nil + } + cacheSize := rand.Intn(dataSize) + 1 + + ca, err := NewCachedAccessor(cacheSize, 0, accessor) + require.NoError(t, err) + + // Lock the accessor. This will cause all cache misses to block. + accessorLock.Lock() + + // Start several goroutines that will attempt to access the same key. + wg := sync.WaitGroup{} + wg.Add(10) + errCount := atomic.Uint64{} + for i := 0; i < 10; i++ { + + var ctx context.Context + if i == 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(context.Background(), 1*time.Millisecond) + defer cancel() + } else { + ctx = context.Background() + } + + go func() { + defer wg.Done() + value, err := ca.Get(ctx, 0) + + if err != nil { + errCount.Add(1) + } else { + require.Equal(t, baseData[0], *value) + } + }() + + if i == 0 { + // Give the thread with the small timeout a chance to start. Although this sleep statement is + // not required for the test to pass, it makes it much more likely for this test to exercise + // the intended code pathway. + time.Sleep(100 * time.Millisecond) + } + } + + // Unlock the accessor. This will allow the goroutines to proceed. + accessorLock.Unlock() + + // Wait for the goroutines to finish. + wg.Wait() + + // Only one of the goroutines should have called into the accessor. + require.Equal(t, uint64(1), cacheMissCount.Load()) + + // At most, one goroutine should have timed out. + require.True(t, errCount.Load() <= 1) + + // Fetching the key again should not result in a cache miss. + value, err := ca.Get(context.Background(), 0) + require.NoError(t, err) + require.Equal(t, baseData[0], *value) + require.Equal(t, uint64(1), cacheMissCount.Load()) + + // The internal lookupsInProgress map should no longer contain the key. + require.Equal(t, 0, len(ca.(*cachedAccessor[int, *string]).lookupsInProgress)) +} + +func TestSecondaryRequesterTimesOut(t *testing.T) { + tu.InitializeRandom() + + dataSize := 1024 + + baseData := make(map[int]string) + for i := 0; i < dataSize; i++ { + baseData[i] = tu.RandomString(10) + } + + accessorLock := sync.RWMutex{} + cacheMissCount := atomic.Uint64{} + accessor := func(key int) (*string, error) { + + // Intentionally block if accessorLock is held by the outside scope. + // Used to provoke specific race conditions. + accessorLock.Lock() + defer accessorLock.Unlock() + + cacheMissCount.Add(1) + + str := baseData[key] + return &str, nil + } + cacheSize := rand.Intn(dataSize) + 1 + + ca, err := NewCachedAccessor(cacheSize, 0, accessor) + require.NoError(t, err) + + // Lock the accessor. This will cause all cache misses to block. + accessorLock.Lock() + + // Start several goroutines that will attempt to access the same key. + wg := sync.WaitGroup{} + wg.Add(10) + errCount := atomic.Uint64{} + for i := 0; i < 10; i++ { + + var ctx context.Context + if i == 1 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(context.Background(), 1*time.Millisecond) + defer cancel() + } else { + ctx = context.Background() + } + + go func() { + defer wg.Done() + value, err := ca.Get(ctx, 0) + + if err != nil { + errCount.Add(1) + } else { + require.Equal(t, baseData[0], *value) + } + }() + + if i == 0 { + // Give the thread with the context that won't time out a chance to start. Although this sleep statement is + // not required for the test to pass, it makes it much more likely for this test to exercise + // the intended code pathway. + time.Sleep(100 * time.Millisecond) + } + } + + // Give context a chance to time out. Although this sleep statement is not required for the test to pass, it makes + // it much more likely for this test to exercise the intended code pathway. + time.Sleep(100 * time.Millisecond) + + // Unlock the accessor. This will allow the goroutines to proceed. + accessorLock.Unlock() + + // Wait for the goroutines to finish. + wg.Wait() + + // Only one of the goroutines should have called into the accessor. + require.Equal(t, uint64(1), cacheMissCount.Load()) + + // At most, one goroutine should have timed out. + require.True(t, errCount.Load() <= 1) + + // Fetching the key again should not result in a cache miss. + value, err := ca.Get(context.Background(), 0) + require.NoError(t, err) + require.Equal(t, baseData[0], *value) + require.Equal(t, uint64(1), cacheMissCount.Load()) + + // The internal lookupsInProgress map should no longer contain the key. + require.Equal(t, 0, len(ca.(*cachedAccessor[int, *string]).lookupsInProgress)) +} diff --git a/relay/chunk_provider.go b/relay/chunk_provider.go index 3fffb42a3b..48ece7c3cd 100644 --- a/relay/chunk_provider.go +++ b/relay/chunk_provider.go @@ -11,6 +11,7 @@ import ( "github.com/Layr-Labs/eigenda/relay/chunkstore" "github.com/Layr-Labs/eigensdk-go/logging" "sync" + "time" ) type chunkProvider struct { @@ -23,6 +24,12 @@ type chunkProvider struct { // chunkReader is used to read chunks from the chunk store. chunkReader chunkstore.ChunkReader + + // fetchTimeout is the maximum time to wait for a chunk proof fetch operation to complete. + proofFetchTimeout time.Duration + + // coefficientFetchTimeout is the maximum time to wait for a chunk coefficient fetch operation to complete. + coefficientFetchTimeout time.Duration } // blobKeyWithMetadata attaches some additional metadata to a blobKey. @@ -41,12 +48,16 @@ func newChunkProvider( logger logging.Logger, chunkReader chunkstore.ChunkReader, cacheSize int, - maxIOConcurrency int) (*chunkProvider, error) { + maxIOConcurrency int, + proofFetchTimeout time.Duration, + coefficientFetchTimeout time.Duration) (*chunkProvider, error) { server := &chunkProvider{ - ctx: ctx, - logger: logger, - chunkReader: chunkReader, + ctx: ctx, + logger: logger, + chunkReader: chunkReader, + proofFetchTimeout: proofFetchTimeout, + coefficientFetchTimeout: coefficientFetchTimeout, } c, err := cache.NewCachedAccessor[blobKeyWithMetadata, []*encoding.Frame]( @@ -89,7 +100,7 @@ func (s *chunkProvider) GetFrames(ctx context.Context, mMap metadataMap) (frameM boundKey := key go func() { - frames, err := s.frameCache.Get(*boundKey) + frames, err := s.frameCache.Get(ctx, *boundKey) if err != nil { s.logger.Errorf("Failed to get frames for blob %v: %v", boundKey.blobKey, err) completionChannel <- &framesResult{ @@ -128,10 +139,13 @@ func (s *chunkProvider) fetchFrames(key blobKeyWithMetadata) ([]*encoding.Frame, var proofsErr error go func() { + ctx, cancel := context.WithTimeout(s.ctx, s.proofFetchTimeout) defer func() { wg.Done() + cancel() }() - proofs, proofsErr = s.chunkReader.GetChunkProofs(s.ctx, key.blobKey) + + proofs, proofsErr = s.chunkReader.GetChunkProofs(ctx, key.blobKey) }() fragmentInfo := &encoding.FragmentInfo{ @@ -139,7 +153,10 @@ func (s *chunkProvider) fetchFrames(key blobKeyWithMetadata) ([]*encoding.Frame, FragmentSizeBytes: key.metadata.fragmentSizeBytes, } - coefficients, err := s.chunkReader.GetChunkCoefficients(s.ctx, key.blobKey, fragmentInfo) + ctx, cancel := context.WithTimeout(s.ctx, s.coefficientFetchTimeout) + defer cancel() + + coefficients, err := s.chunkReader.GetChunkCoefficients(ctx, key.blobKey, fragmentInfo) if err != nil { return nil, err } diff --git a/relay/chunk_provider_test.go b/relay/chunk_provider_test.go index b768210d77..8615ad7d23 100644 --- a/relay/chunk_provider_test.go +++ b/relay/chunk_provider_test.go @@ -8,6 +8,7 @@ import ( "github.com/Layr-Labs/eigenda/encoding" "github.com/stretchr/testify/require" "testing" + "time" ) func TestFetchingIndividualBlobs(t *testing.T) { @@ -44,7 +45,14 @@ func TestFetchingIndividualBlobs(t *testing.T) { fragmentInfoMap[blobKey] = fragmentInfo } - server, err := newChunkProvider(context.Background(), logger, chunkReader, 10, 32) + server, err := newChunkProvider( + context.Background(), + logger, + chunkReader, + 10, + 32, + 10*time.Second, + 10*time.Second) require.NoError(t, err) // Read it back. @@ -124,7 +132,14 @@ func TestFetchingBatchedBlobs(t *testing.T) { fragmentInfoMap[blobKey] = fragmentInfo } - server, err := newChunkProvider(context.Background(), logger, chunkReader, 10, 32) + server, err := newChunkProvider( + context.Background(), + logger, + chunkReader, + 10, + 32, + 10*time.Second, + 10*time.Second) require.NoError(t, err) // Read it back. diff --git a/relay/cmd/config.go b/relay/cmd/config.go index 13f56e7ada..154c4c2bd2 100644 --- a/relay/cmd/config.go +++ b/relay/cmd/config.go @@ -85,6 +85,14 @@ func NewConfig(ctx *cli.Context) (Config, error) { AuthenticationTimeout: ctx.Duration(flags.AuthenticationTimeoutFlag.Name), AuthenticationDisabled: ctx.Bool(flags.AuthenticationDisabledFlag.Name), OnchainStateRefreshInterval: ctx.Duration(flags.OnchainStateRefreshIntervalFlag.Name), + Timeouts: relay.TimeoutConfig{ + GetChunksTimeout: ctx.Duration(flags.GetChunksTimeoutFlag.Name), + GetBlobTimeout: ctx.Duration(flags.GetBlobTimeoutFlag.Name), + InternalGetMetadataTimeout: ctx.Duration(flags.InternalGetMetadataTimeoutFlag.Name), + InternalGetBlobTimeout: ctx.Duration(flags.InternalGetBlobTimeoutFlag.Name), + InternalGetProofsTimeout: ctx.Duration(flags.InternalGetProofsTimeoutFlag.Name), + InternalGetCoefficientsTimeout: ctx.Duration(flags.InternalGetCoefficientsTimeoutFlag.Name), + }, }, EthClientConfig: geth.ReadEthClientConfig(ctx), BLSOperatorStateRetrieverAddr: ctx.String(flags.BlsOperatorStateRetrieverAddrFlag.Name), diff --git a/relay/cmd/flags/flags.go b/relay/cmd/flags/flags.go index f471765966..baed1fbcf4 100644 --- a/relay/cmd/flags/flags.go +++ b/relay/cmd/flags/flags.go @@ -231,6 +231,48 @@ var ( Required: false, EnvVar: common.PrefixEnvVar(envVarPrefix, "AUTHENTICATION_DISABLED"), } + GetChunksTimeoutFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "get-chunks-timeout"), + Usage: "Timeout for GetChunks()", + EnvVar: common.PrefixEnvVar(envVarPrefix, "GET_CHUNKS_TIMEOUT"), + Required: false, + Value: 20 * time.Second, + } + GetBlobTimeoutFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "get-blob-timeout"), + Usage: "Timeout for GetBlob()", + EnvVar: common.PrefixEnvVar(envVarPrefix, "GET_BLOB_TIMEOUT"), + Required: false, + Value: 20 * time.Second, + } + InternalGetMetadataTimeoutFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "internal-get-metadata-timeout"), + Usage: "Timeout for internal metadata fetch", + EnvVar: common.PrefixEnvVar(envVarPrefix, "INTERNAL_GET_METADATA_TIMEOUT"), + Required: false, + Value: 5 * time.Second, + } + InternalGetBlobTimeoutFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "internal-get-blob-timeout"), + Usage: "Timeout for internal blob fetch", + EnvVar: common.PrefixEnvVar(envVarPrefix, "INTERNAL_GET_BLOB_TIMEOUT"), + Required: false, + Value: 20 * time.Second, + } + InternalGetProofsTimeoutFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "internal-get-proofs-timeout"), + Usage: "Timeout for internal proofs fetch", + EnvVar: common.PrefixEnvVar(envVarPrefix, "INTERNAL_GET_PROOFS_TIMEOUT"), + Required: false, + Value: 5 * time.Second, + } + InternalGetCoefficientsTimeoutFlag = cli.DurationFlag{ + Name: common.PrefixFlag(FlagPrefix, "internal-get-coefficients-timeout"), + Usage: "Timeout for internal coefficients fetch", + EnvVar: common.PrefixEnvVar(envVarPrefix, "INTERNAL_GET_COEFFICIENTS_TIMEOUT"), + Required: false, + Value: 20 * time.Second, + } OnchainStateRefreshIntervalFlag = cli.DurationFlag{ Name: common.PrefixFlag(FlagPrefix, "onchain-state-refresh-interval"), Usage: "The interval at which to refresh the onchain state", @@ -247,6 +289,8 @@ var requiredFlags = []cli.Flag{ RelayIDsFlag, BlsOperatorStateRetrieverAddrFlag, EigenDAServiceManagerAddrFlag, + AuthenticationTimeoutFlag, + AuthenticationDisabledFlag, } var optionalFlags = []cli.Flag{ @@ -276,6 +320,12 @@ var optionalFlags = []cli.Flag{ AuthenticationKeyCacheSizeFlag, AuthenticationTimeoutFlag, AuthenticationDisabledFlag, + GetChunksTimeoutFlag, + GetBlobTimeoutFlag, + InternalGetMetadataTimeoutFlag, + InternalGetBlobTimeoutFlag, + InternalGetProofsTimeoutFlag, + InternalGetCoefficientsTimeoutFlag, OnchainStateRefreshIntervalFlag, } diff --git a/relay/metadata_provider.go b/relay/metadata_provider.go index f86bccfddd..8f3f43ed86 100644 --- a/relay/metadata_provider.go +++ b/relay/metadata_provider.go @@ -10,6 +10,7 @@ import ( "github.com/Layr-Labs/eigenda/encoding" "github.com/Layr-Labs/eigenda/relay/cache" "github.com/Layr-Labs/eigensdk-go/logging" + "time" ) // Metadata about a blob. The relay only needs a small subset of a blob's metadata. @@ -41,6 +42,9 @@ type metadataProvider struct { // that are not assigned to one of these IDs. relayIDSet map[v2.RelayKey]struct{} + // fetchTimeout is the maximum time to wait for a metadata fetch operation to complete. + fetchTimeout time.Duration + // blobParamsMap is a map of blob version to blob version parameters. blobParamsMap atomic.Pointer[v2.BlobVersionParameterMap] } @@ -53,8 +57,8 @@ func newMetadataProvider( metadataCacheSize int, maxIOConcurrency int, relayIDs []v2.RelayKey, - blobParamsMap *v2.BlobVersionParameterMap, -) (*metadataProvider, error) { + fetchTimeout time.Duration, + blobParamsMap *v2.BlobVersionParameterMap) (*metadataProvider, error) { relayIDSet := make(map[v2.RelayKey]struct{}, len(relayIDs)) for _, id := range relayIDs { @@ -66,6 +70,7 @@ func newMetadataProvider( logger: logger, metadataStore: metadataStore, relayIDSet: relayIDSet, + fetchTimeout: fetchTimeout, } server.blobParamsMap.Store(blobParamsMap) @@ -89,7 +94,8 @@ type metadataMap map[v2.BlobKey]*blobMetadata // If any of the blobs do not exist, an error is returned. // Note that resulting metadata map may not have the same length as the input // keys slice if the input keys slice has duplicate items. -func (m *metadataProvider) GetMetadataForBlobs(keys []v2.BlobKey) (metadataMap, error) { +func (m *metadataProvider) GetMetadataForBlobs(ctx context.Context, keys []v2.BlobKey) (metadataMap, error) { + // blobMetadataResult is the result of a metadata fetch operation. type blobMetadataResult struct { key v2.BlobKey @@ -116,7 +122,7 @@ func (m *metadataProvider) GetMetadataForBlobs(keys []v2.BlobKey) (metadataMap, boundKey := key go func() { - metadata, err := m.metadataCache.Get(boundKey) + metadata, err := m.metadataCache.Get(ctx, boundKey) if err != nil { // Intentionally log at debug level. External users can force this condition to trigger // by requesting metadata for a blob that does not exist, and so it's important to avoid @@ -153,13 +159,16 @@ func (m *metadataProvider) UpdateBlobVersionParameters(blobParamsMap *v2.BlobVer // fetchMetadata retrieves metadata about a blob. Fetches from the cache if available, otherwise from the store. func (m *metadataProvider) fetchMetadata(key v2.BlobKey) (*blobMetadata, error) { + ctx, cancel := context.WithTimeout(m.ctx, m.fetchTimeout) + defer cancel() + blobParamsMap := m.blobParamsMap.Load() if blobParamsMap == nil { return nil, fmt.Errorf("blob version parameters is nil") } // Retrieve the metadata from the store. - cert, fragmentInfo, err := m.metadataStore.GetBlobCertificate(m.ctx, key) + cert, fragmentInfo, err := m.metadataStore.GetBlobCertificate(ctx, key) if err != nil { return nil, fmt.Errorf("error retrieving metadata for blob %s: %w", key.Hex(), err) } diff --git a/relay/metadata_provider_test.go b/relay/metadata_provider_test.go index 228ec83264..b48e157ec0 100644 --- a/relay/metadata_provider_test.go +++ b/relay/metadata_provider_test.go @@ -11,6 +11,7 @@ import ( "github.com/Layr-Labs/eigenda/encoding" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "time" ) func TestGetNonExistentBlob(t *testing.T) { @@ -23,12 +24,20 @@ func TestGetNonExistentBlob(t *testing.T) { defer teardown() metadataStore := buildMetadataStore(t) - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) + server, err := newMetadataProvider( + context.Background(), + logger, + metadataStore, + 1024*1024, + 32, + nil, + 10*time.Second, + v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Try to fetch a non-existent blobs for i := 0; i < 10; i++ { - _, err := server.GetMetadataForBlobs([]v2.BlobKey{v2.BlobKey(tu.RandomBytes(32))}) + _, err := server.GetMetadataForBlobs(context.Background(), []v2.BlobKey{v2.BlobKey(tu.RandomBytes(32))}) require.Error(t, err) } } @@ -81,12 +90,21 @@ func TestFetchingIndividualMetadata(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) + server, err := newMetadataProvider( + context.Background(), + logger, + metadataStore, + 1024*1024, + 32, + nil, + 10*time.Second, + v2.NewBlobVersionParameterMap(mockBlobParamsMap())) + require.NoError(t, err) // Fetch the metadata from the server. for blobKey, totalChunkSizeBytes := range totalChunkSizeMap { - mMap, err := server.GetMetadataForBlobs([]v2.BlobKey{blobKey}) + mMap, err := server.GetMetadataForBlobs(context.Background(), []v2.BlobKey{blobKey}) require.NoError(t, err) require.Equal(t, 1, len(mMap)) metadata := mMap[blobKey] @@ -97,7 +115,7 @@ func TestFetchingIndividualMetadata(t *testing.T) { // Read it back again. This uses a different code pathway due to the cache. for blobKey, totalChunkSizeBytes := range totalChunkSizeMap { - mMap, err := server.GetMetadataForBlobs([]v2.BlobKey{blobKey}) + mMap, err := server.GetMetadataForBlobs(context.Background(), []v2.BlobKey{blobKey}) require.NoError(t, err) require.Equal(t, 1, len(mMap)) metadata := mMap[blobKey] @@ -157,7 +175,15 @@ func TestBatchedFetch(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, nil, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) + server, err := newMetadataProvider( + context.Background(), + logger, + metadataStore, + 1024*1024, + 32, + nil, + 10*time.Second, + v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Each iteration, choose a random subset of the keys to fetch @@ -171,7 +197,7 @@ func TestBatchedFetch(t *testing.T) { } } - mMap, err := server.GetMetadataForBlobs(keys) + mMap, err := server.GetMetadataForBlobs(context.Background(), keys) require.NoError(t, err) assert.Equal(t, keyCount, len(mMap)) @@ -184,7 +210,7 @@ func TestBatchedFetch(t *testing.T) { } // Test fetching with duplicate keys - mMap, err := server.GetMetadataForBlobs([]v2.BlobKey{blobKeys[0], blobKeys[0]}) + mMap, err := server.GetMetadataForBlobs(context.Background(), []v2.BlobKey{blobKeys[0], blobKeys[0]}) require.NoError(t, err) require.Equal(t, 1, len(mMap)) } @@ -255,7 +281,15 @@ func TestIndividualFetchWithSharding(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, shardList, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) + server, err := newMetadataProvider( + context.Background(), + logger, + metadataStore, + 1024*1024, + 32, + shardList, + 10*time.Second, + v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Fetch the metadata from the server. @@ -269,7 +303,7 @@ func TestIndividualFetchWithSharding(t *testing.T) { } } - mMap, err := server.GetMetadataForBlobs([]v2.BlobKey{blobKey}) + mMap, err := server.GetMetadataForBlobs(context.Background(), []v2.BlobKey{blobKey}) if isBlobInCorrectShard { // The blob is in the relay's shard, should be returned like normal @@ -296,7 +330,7 @@ func TestIndividualFetchWithSharding(t *testing.T) { } } - mMap, err := server.GetMetadataForBlobs([]v2.BlobKey{blobKey}) + mMap, err := server.GetMetadataForBlobs(context.Background(), []v2.BlobKey{blobKey}) if isBlobInCorrectShard { // The blob is in the relay's shard, should be returned like normal @@ -379,7 +413,15 @@ func TestBatchedFetchWithSharding(t *testing.T) { require.Equal(t, fragmentSizeMap[blobKey], fragmentInfo.FragmentSizeBytes) } - server, err := newMetadataProvider(context.Background(), logger, metadataStore, 1024*1024, 32, shardList, v2.NewBlobVersionParameterMap(mockBlobParamsMap())) + server, err := newMetadataProvider( + context.Background(), + logger, + metadataStore, + 1024*1024, + 32, + shardList, + 10*time.Second, + v2.NewBlobVersionParameterMap(mockBlobParamsMap())) require.NoError(t, err) // Each iteration, choose two random keys to fetch. There will be a 25% chance that both blobs map to valid shards. @@ -409,7 +451,7 @@ func TestBatchedFetchWithSharding(t *testing.T) { } } - mMap, err := server.GetMetadataForBlobs(keys) + mMap, err := server.GetMetadataForBlobs(context.Background(), keys) if areKeysInCorrectShard { require.NoError(t, err) assert.Equal(t, keyCount, len(mMap)) diff --git a/relay/relay_test_utils.go b/relay/relay_test_utils.go index 2a075a8294..1e5120f700 100644 --- a/relay/relay_test_utils.go +++ b/relay/relay_test_utils.go @@ -3,15 +3,6 @@ package relay import ( "context" "fmt" - "log" - "math/big" - "os" - "path/filepath" - "runtime" - "strings" - "testing" - "time" - pbcommon "github.com/Layr-Labs/eigenda/api/grpc/common" pbcommonv2 "github.com/Layr-Labs/eigenda/api/grpc/common/v2" "github.com/Layr-Labs/eigenda/common" @@ -36,6 +27,13 @@ import ( "github.com/ory/dockertest/v3" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "log" + "math/big" + "os" + "path/filepath" + "runtime" + "strings" + "testing" ) var ( @@ -158,12 +156,10 @@ func buildBlobStore(t *testing.T, logger logging.Logger) *blobstore.BlobStore { func buildChunkStore(t *testing.T, logger logging.Logger) (chunkstore.ChunkReader, chunkstore.ChunkWriter) { cfg := aws.ClientConfig{ - Region: "us-east-1", - AccessKey: "localstack", - SecretAccessKey: "localstack", - EndpointURL: localstackHost, - FragmentWriteTimeout: time.Duration(10) * time.Second, - FragmentReadTimeout: time.Duration(10) * time.Second, + Region: "us-east-1", + AccessKey: "localstack", + SecretAccessKey: "localstack", + EndpointURL: localstackHost, } client, err := s3.NewClient(context.Background(), cfg, logger) @@ -199,7 +195,7 @@ func mockBlobParamsMap() map[uint8]*core.BlobVersionParameters { func randomBlob(t *testing.T) (*v2.BlobHeader, []byte) { - data := tu.RandomBytes(225) // TODO talk to Ian about this + data := tu.RandomBytes(225) data = codec.ConvertByPaddingEmptyByte(data) commitments, err := prover.GetCommitmentsForPaddedLength(data) diff --git a/relay/server.go b/relay/server.go index 32267de763..540b46b0b0 100644 --- a/relay/server.go +++ b/relay/server.go @@ -108,6 +108,9 @@ type Config struct { // AuthenticationDisabled will disable authentication if set to true. AuthenticationDisabled bool + // Timeouts contains configuration for relay timeouts. + Timeouts TimeoutConfig + // OnchainStateRefreshInterval is the interval at which the onchain state is refreshed. OnchainStateRefreshInterval time.Duration } @@ -139,8 +142,9 @@ func NewServer( config.MetadataCacheSize, config.MetadataMaxConcurrency, config.RelayIDs, - v2.NewBlobVersionParameterMap(blobParams), - ) + config.Timeouts.InternalGetMetadataTimeout, + v2.NewBlobVersionParameterMap(blobParams)) + if err != nil { return nil, fmt.Errorf("error creating metadata provider: %w", err) } @@ -150,7 +154,8 @@ func NewServer( logger, blobStore, config.BlobCacheSize, - config.BlobMaxConcurrency) + config.BlobMaxConcurrency, + config.Timeouts.InternalGetBlobTimeout) if err != nil { return nil, fmt.Errorf("error creating blob provider: %w", err) } @@ -160,7 +165,9 @@ func NewServer( logger, chunkReader, config.ChunkCacheSize, - config.ChunkMaxConcurrency) + config.ChunkMaxConcurrency, + config.Timeouts.InternalGetProofsTimeout, + config.Timeouts.InternalGetCoefficientsTimeout) if err != nil { return nil, fmt.Errorf("error creating chunk provider: %w", err) } @@ -168,6 +175,7 @@ func NewServer( var authenticator auth.RequestAuthenticator if !config.AuthenticationDisabled { authenticator, err = auth.NewRequestAuthenticator( + ctx, ics, config.AuthenticationKeyCacheSize, config.AuthenticationTimeout) @@ -190,9 +198,11 @@ func NewServer( // GetBlob retrieves a blob stored by the relay. func (s *Server) GetBlob(ctx context.Context, request *pb.GetBlobRequest) (*pb.GetBlobReply, error) { - - // TODO(cody-littley): - // - timeouts + if s.config.Timeouts.GetBlobTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, s.config.Timeouts.GetBlobTimeout) + defer cancel() + } err := s.blobRateLimiter.BeginGetBlobOperation(time.Now()) if err != nil { @@ -206,7 +216,7 @@ func (s *Server) GetBlob(ctx context.Context, request *pb.GetBlobRequest) (*pb.G } keys := []v2.BlobKey{key} - mMap, err := s.metadataProvider.GetMetadataForBlobs(keys) + mMap, err := s.metadataProvider.GetMetadataForBlobs(ctx, keys) if err != nil { return nil, fmt.Errorf( "error fetching metadata for blob, check if blob exists and is assigned to this relay: %w", err) @@ -221,7 +231,7 @@ func (s *Server) GetBlob(ctx context.Context, request *pb.GetBlobRequest) (*pb.G return nil, err } - data, err := s.blobProvider.GetBlob(key) + data, err := s.blobProvider.GetBlob(ctx, key) if err != nil { return nil, fmt.Errorf("error fetching blob %s: %w", key.Hex(), err) } @@ -235,9 +245,11 @@ func (s *Server) GetBlob(ctx context.Context, request *pb.GetBlobRequest) (*pb.G // GetChunks retrieves chunks from blobs stored by the relay. func (s *Server) GetChunks(ctx context.Context, request *pb.GetChunksRequest) (*pb.GetChunksReply, error) { - - // TODO(cody-littley): - // - timeouts + if s.config.Timeouts.GetChunksTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, s.config.Timeouts.GetChunksTimeout) + defer cancel() + } if len(request.ChunkRequests) <= 0 { return nil, fmt.Errorf("no chunk requests provided") @@ -254,7 +266,7 @@ func (s *Server) GetChunks(ctx context.Context, request *pb.GetChunksRequest) (* } clientAddress := client.Addr.String() - err := s.authenticator.AuthenticateGetChunksRequest(clientAddress, request, time.Now()) + err := s.authenticator.AuthenticateGetChunksRequest(ctx, clientAddress, request, time.Now()) if err != nil { return nil, fmt.Errorf("auth failed: %w", err) } @@ -274,7 +286,7 @@ func (s *Server) GetChunks(ctx context.Context, request *pb.GetChunksRequest) (* return nil, err } - mMap, err := s.metadataProvider.GetMetadataForBlobs(keys) + mMap, err := s.metadataProvider.GetMetadataForBlobs(ctx, keys) if err != nil { return nil, fmt.Errorf( "error fetching metadata for blob, check if blob exists and is assigned to this relay: %w", err) diff --git a/relay/server_test.go b/relay/server_test.go index baaf873150..3e16c624c3 100644 --- a/relay/server_test.go +++ b/relay/server_test.go @@ -4,6 +4,7 @@ import ( "context" "math/rand" "testing" + "time" "github.com/Layr-Labs/eigenda/relay/limiter" @@ -47,6 +48,14 @@ func defaultConfig() *Config { MaxConcurrentGetChunkOpsClient: 1, }, AuthenticationDisabled: true, + Timeouts: TimeoutConfig{ + GetBlobTimeout: 10 * time.Second, + GetChunksTimeout: 10 * time.Second, + InternalGetMetadataTimeout: 10 * time.Second, + InternalGetBlobTimeout: 10 * time.Second, + InternalGetProofsTimeout: 10 * time.Second, + InternalGetCoefficientsTimeout: 10 * time.Second, + }, } } diff --git a/relay/timeout_config.go b/relay/timeout_config.go new file mode 100644 index 0000000000..64c6be96ff --- /dev/null +++ b/relay/timeout_config.go @@ -0,0 +1,26 @@ +package relay + +import "time" + +// TimeoutConfig encapsulates the timeout configuration for the relay server. +type TimeoutConfig struct { + + // The maximum time permitted for a GetChunks GRPC to complete. If zero then no timeout is enforced. + GetChunksTimeout time.Duration + + // The maximum time permitted for a GetBlob GRPC to complete. If zero then no timeout is enforced. + GetBlobTimeout time.Duration + + // The maximum time permitted for a single request to the metadata store to fetch the metadata + // for an individual blob. + InternalGetMetadataTimeout time.Duration + + // The maximum time permitted for a single request to the blob store to fetch a blob. + InternalGetBlobTimeout time.Duration + + // The maximum time permitted for a single request to the chunk store to fetch chunk proofs. + InternalGetProofsTimeout time.Duration + + // The maximum time permitted for a single request to the chunk store to fetch chunk coefficients. + InternalGetCoefficientsTimeout time.Duration +} From dee3f54a4f29e1972b35a66d5d7a5dabfaa0bb1f Mon Sep 17 00:00:00 2001 From: Jian Xiao <99709935+jianoaix@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:30:18 -0800 Subject: [PATCH 06/15] Pull out the pprof server (#933) --- disperser/apiserver/pprof.go => common/pprof/server.go | 2 +- disperser/apiserver/server.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) rename disperser/apiserver/pprof.go => common/pprof/server.go (97%) diff --git a/disperser/apiserver/pprof.go b/common/pprof/server.go similarity index 97% rename from disperser/apiserver/pprof.go rename to common/pprof/server.go index db3847b3d3..70a6ea1bf8 100644 --- a/disperser/apiserver/pprof.go +++ b/common/pprof/server.go @@ -1,4 +1,4 @@ -package apiserver +package pprof import ( "fmt" diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 6c9be3c54f..831b0e6350 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -17,6 +17,7 @@ import ( pb "github.com/Layr-Labs/eigenda/api/grpc/disperser" "github.com/Layr-Labs/eigenda/common" "github.com/Layr-Labs/eigenda/common/healthcheck" + "github.com/Layr-Labs/eigenda/common/pprof" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/core/auth" "github.com/Layr-Labs/eigenda/core/meterer" @@ -819,7 +820,7 @@ func (s *DispersalServer) GetRateConfig() *RateConfig { } func (s *DispersalServer) Start(ctx context.Context) error { - pprofProfiler := NewPprofProfiler(s.serverConfig.PprofHttpPort, s.logger) + pprofProfiler := pprof.NewPprofProfiler(s.serverConfig.PprofHttpPort, s.logger) if s.serverConfig.EnablePprof { go pprofProfiler.Start() s.logger.Info("Enabled pprof for disperser apiserver", "port", s.serverConfig.PprofHttpPort) From 2cbfaa40b1c0db22c4e2bfdca9ccf978fbb4bb6b Mon Sep 17 00:00:00 2001 From: Jian Xiao <99709935+jianoaix@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:40:11 -0800 Subject: [PATCH 07/15] Do not fail the object fetch when object size is unknown (#932) --- common/aws/s3/client.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/common/aws/s3/client.go b/common/aws/s3/client.go index c3ae159d41..9dcaa346f4 100644 --- a/common/aws/s3/client.go +++ b/common/aws/s3/client.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "errors" - "fmt" "runtime" "sync" @@ -19,6 +18,10 @@ import ( "golang.org/x/sync/errgroup" ) +const ( + defaultBlobBufferSizeByte = 128 * 1024 +) + var ( once sync.Once ref *client @@ -106,24 +109,13 @@ func NewClient(ctx context.Context, cfg commonaws.ClientConfig, logger logging.L return ref, err } -func PeekObjectSize(ctx context.Context, s3Client *s3.Client, bucket, key string) (int64, error) { - input := &s3.HeadObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), - } - result, err := s3Client.HeadObject(ctx, input) - if err != nil { - return 0, fmt.Errorf("failed to head object: %w", err) - } - return *result.ContentLength, nil -} - func (s *client) DownloadObject(ctx context.Context, bucket string, key string) ([]byte, error) { - size, err := PeekObjectSize(ctx, s.s3Client, bucket, key) - if err != nil { - return nil, err + objectSize := defaultBlobBufferSizeByte + size, err := s.HeadObject(ctx, bucket, key) + if err == nil { + objectSize = int(*size) } - buffer := manager.NewWriteAtBuffer(make([]byte, 0, size)) + buffer := manager.NewWriteAtBuffer(make([]byte, 0, objectSize)) var partMiBs int64 = 10 downloader := manager.NewDownloader(s.s3Client, func(d *manager.Downloader) { From c28f42f233adf5c7edd4875095bf5a4651cb4846 Mon Sep 17 00:00:00 2001 From: Cody Littley <56973212+cody-littley@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:17:58 -0600 Subject: [PATCH 08/15] Metrics framework (#926) Signed-off-by: Cody Littley --- common/metrics/config.go | 10 + common/metrics/count_metric.go | 101 ++++++++ common/metrics/gauge_metric.go | 103 ++++++++ common/metrics/label_maker.go | 73 ++++++ common/metrics/latency_metric.go | 102 ++++++++ common/metrics/metrics.go | 142 ++++++++++ common/metrics/metrics_server.go | 430 +++++++++++++++++++++++++++++++ common/metrics/mock_metrics.go | 154 +++++++++++ common/metrics/test/main.go | 137 ++++++++++ common/metrics/test/metrics.md | 71 +++++ 10 files changed, 1323 insertions(+) create mode 100644 common/metrics/config.go create mode 100644 common/metrics/count_metric.go create mode 100644 common/metrics/gauge_metric.go create mode 100644 common/metrics/label_maker.go create mode 100644 common/metrics/latency_metric.go create mode 100644 common/metrics/metrics.go create mode 100644 common/metrics/metrics_server.go create mode 100644 common/metrics/mock_metrics.go create mode 100644 common/metrics/test/main.go create mode 100644 common/metrics/test/metrics.md diff --git a/common/metrics/config.go b/common/metrics/config.go new file mode 100644 index 0000000000..1bc8c0e4d9 --- /dev/null +++ b/common/metrics/config.go @@ -0,0 +1,10 @@ +package metrics + +// Config provides configuration for a Metrics instance. +type Config struct { + // Namespace is the namespace for the metrics. + Namespace string + + // HTTPPort is the port to serve metrics on. + HTTPPort int +} diff --git a/common/metrics/count_metric.go b/common/metrics/count_metric.go new file mode 100644 index 0000000000..f52b942cb6 --- /dev/null +++ b/common/metrics/count_metric.go @@ -0,0 +1,101 @@ +package metrics + +import ( + "fmt" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var _ CountMetric = &countMetric{} + +// countMetric a standard implementation of the CountMetric. +type countMetric struct { + Metric + + // logger is the logger used to log errors. + logger logging.Logger + + // name is the name of the metric. + name string + + // description is the description of the metric. + description string + + // counter is the prometheus counter used to report this metric. + vec *prometheus.CounterVec + + // labeler is the label maker used to create labels for this metric. + labeler *labelMaker +} + +// newCountMetric creates a new CountMetric instance. +func newCountMetric( + logger logging.Logger, + registry *prometheus.Registry, + namespace string, + name string, + description string, + labelTemplate any) (CountMetric, error) { + + labeler, err := newLabelMaker(labelTemplate) + if err != nil { + return nil, err + } + + vec := promauto.With(registry).NewCounterVec( + prometheus.CounterOpts{ + Namespace: namespace, + Name: fmt.Sprintf("%s_count", name), + }, + labeler.getKeys(), + ) + + return &countMetric{ + logger: logger, + name: name, + description: description, + vec: vec, + labeler: labeler, + }, nil +} + +func (m *countMetric) Name() string { + return m.name +} + +func (m *countMetric) Unit() string { + return "count" +} + +func (m *countMetric) Description() string { + return m.description +} + +func (m *countMetric) Type() string { + return "counter" +} + +func (m *countMetric) LabelFields() []string { + return m.labeler.getKeys() +} + +func (m *countMetric) Increment(label ...any) { + m.Add(1, label...) +} + +func (m *countMetric) Add(value float64, label ...any) { + var l any + if len(label) > 0 { + l = label[0] + } + + values, err := m.labeler.extractValues(l) + if err != nil { + m.logger.Errorf("error extracting values from label for metric %s: %v", m.name, err) + return + } + + observer := m.vec.WithLabelValues(values...) + observer.Add(value) +} diff --git a/common/metrics/gauge_metric.go b/common/metrics/gauge_metric.go new file mode 100644 index 0000000000..ca3c80ae74 --- /dev/null +++ b/common/metrics/gauge_metric.go @@ -0,0 +1,103 @@ +package metrics + +import ( + "fmt" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var _ GaugeMetric = &gaugeMetric{} + +// gaugeMetric is a standard implementation of the GaugeMetric interface via prometheus. +type gaugeMetric struct { + Metric + + // logger is the logger used to log errors. + logger logging.Logger + + // name is the name of the metric. + name string + + // unit is the unit of the metric. + unit string + + // description is the description of the metric. + description string + + // gauge is the prometheus gauge used to report this metric. + vec *prometheus.GaugeVec + + // labeler is the label maker used to create labels for this metric. + labeler *labelMaker +} + +// newGaugeMetric creates a new GaugeMetric instance. +func newGaugeMetric( + logger logging.Logger, + registry *prometheus.Registry, + namespace string, + name string, + unit string, + description string, + labelTemplate any) (GaugeMetric, error) { + + labeler, err := newLabelMaker(labelTemplate) + if err != nil { + return nil, err + } + + vec := promauto.With(registry).NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: namespace, + Name: fmt.Sprintf("%s_%s", name, unit), + }, + labeler.getKeys(), + ) + + return &gaugeMetric{ + logger: logger, + name: name, + unit: unit, + description: description, + vec: vec, + labeler: labeler, + }, nil +} + +func (m *gaugeMetric) Name() string { + return m.name +} + +func (m *gaugeMetric) Unit() string { + return m.unit +} + +func (m *gaugeMetric) Description() string { + return m.description +} + +func (m *gaugeMetric) Type() string { + return "gauge" +} + +func (m *gaugeMetric) LabelFields() []string { + return m.labeler.getKeys() +} + +func (m *gaugeMetric) Set(value float64, label ...any) { + var l any + if len(label) > 0 { + l = label[0] + } + + values, err := m.labeler.extractValues(l) + if err != nil { + m.logger.Errorf("failed to extract values from label: %v", err) + return + } + + observer := m.vec.WithLabelValues(values...) + + observer.Set(value) +} diff --git a/common/metrics/label_maker.go b/common/metrics/label_maker.go new file mode 100644 index 0000000000..cb56ecdfc7 --- /dev/null +++ b/common/metrics/label_maker.go @@ -0,0 +1,73 @@ +package metrics + +import ( + "fmt" + "reflect" +) + +// labelMaker encapsulates logic for creating labels for metrics. +type labelMaker struct { + keys []string + emptyValues []string + templateType reflect.Type + labelCount int +} + +// newLabelMaker creates a new labelMaker instance given a label template. The label template may be nil. +func newLabelMaker(labelTemplate any) (*labelMaker, error) { + labeler := &labelMaker{ + keys: make([]string, 0), + } + + if labelTemplate == nil { + return labeler, nil + } + + v := reflect.ValueOf(labelTemplate) + if v.Kind() != reflect.Struct { + return nil, fmt.Errorf("label template must be a struct") + } + + t := v.Type() + labeler.templateType = t + for i := 0; i < t.NumField(); i++ { + + fieldType := t.Field(i).Type + if fieldType.Kind() != reflect.String { + return nil, fmt.Errorf( + "field %s has type %v, only string fields are supported", t.Field(i).Name, fieldType) + } + + labeler.keys = append(labeler.keys, t.Field(i).Name) + } + + labeler.emptyValues = make([]string, len(labeler.keys)) + labeler.labelCount = len(labeler.keys) + + return labeler, nil +} + +// getKeys provides the keys for the label struct. +func (l *labelMaker) getKeys() []string { + return l.keys +} + +// extractValues extracts the values from the given label struct. +func (l *labelMaker) extractValues(label any) ([]string, error) { + if l.templateType == nil || label == nil { + return l.emptyValues, nil + } + + if l.templateType != reflect.TypeOf(label) { + return nil, fmt.Errorf( + "label type mismatch, expected %v, got %v", l.templateType, reflect.TypeOf(label)) + } + + values := make([]string, 0, l.labelCount) + for i := 0; i < l.labelCount; i++ { + v := reflect.ValueOf(label) + values = append(values, v.Field(i).String()) + } + + return values, nil +} diff --git a/common/metrics/latency_metric.go b/common/metrics/latency_metric.go new file mode 100644 index 0000000000..1309a9b33d --- /dev/null +++ b/common/metrics/latency_metric.go @@ -0,0 +1,102 @@ +package metrics + +import ( + "fmt" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "time" +) + +var _ LatencyMetric = &latencyMetric{} + +// latencyMetric is a standard implementation of the LatencyMetric interface via prometheus. +type latencyMetric struct { + Metric + + // logger is the logger used to log errors. + logger logging.Logger + + // name is the name of the metric. + name string + + // description is the description of the metric. + description string + + // vec is the prometheus summary vector used to report this metric. + vec *prometheus.SummaryVec + + // lm is the label maker used to create labels for this metric. + labeler *labelMaker +} + +// newLatencyMetric creates a new LatencyMetric instance. +func newLatencyMetric( + logger logging.Logger, + registry *prometheus.Registry, + namespace string, + name string, + description string, + objectives map[float64]float64, + labelTemplate any) (LatencyMetric, error) { + + labeler, err := newLabelMaker(labelTemplate) + if err != nil { + return nil, err + } + + vec := promauto.With(registry).NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: namespace, + Name: fmt.Sprintf("%s_ms", name), + Objectives: objectives, + }, + labeler.getKeys(), + ) + + return &latencyMetric{ + logger: logger, + name: name, + description: description, + vec: vec, + labeler: labeler, + }, nil +} + +func (m *latencyMetric) Name() string { + return m.name +} + +func (m *latencyMetric) Unit() string { + return "ms" +} + +func (m *latencyMetric) Description() string { + return m.description +} + +func (m *latencyMetric) Type() string { + return "latency" +} + +func (m *latencyMetric) LabelFields() []string { + return m.labeler.getKeys() +} + +func (m *latencyMetric) ReportLatency(latency time.Duration, label ...any) { + var l any + if len(label) > 0 { + l = label[0] + } + + values, err := m.labeler.extractValues(l) + if err != nil { + m.logger.Errorf("error extracting values from label: %v", err) + } + + observer := m.vec.WithLabelValues(values...) + + nanoseconds := float64(latency.Nanoseconds()) + milliseconds := nanoseconds / float64(time.Millisecond) + observer.Observe(milliseconds) +} diff --git a/common/metrics/metrics.go b/common/metrics/metrics.go new file mode 100644 index 0000000000..ed63a1c6a5 --- /dev/null +++ b/common/metrics/metrics.go @@ -0,0 +1,142 @@ +package metrics + +import "time" + +// Metrics provides a convenient interface for reporting metrics. +type Metrics interface { + // Start starts the metrics server. + Start() error + + // Stop stops the metrics server. + Stop() error + + // GenerateMetricsDocumentation generates documentation for all currently registered metrics. + // Documentation is returned as a string in markdown format. + GenerateMetricsDocumentation() string + + // WriteMetricsDocumentation writes documentation for all currently registered metrics to a file. + // Documentation is written in markdown format. + WriteMetricsDocumentation(fileName string) error + + // NewLatencyMetric creates a new LatencyMetric instance. Useful for reporting the latency of an operation. + // Metric name and label may only contain alphanumeric characters and underscores. + // + // The labelTemplate parameter is the label type that will be used for this metric. Each field becomes a label for + // the metric. Each field type must be a string. If no labels are needed, pass nil. + NewLatencyMetric( + name string, + description string, + labelTemplate any, + quantiles ...*Quantile) (LatencyMetric, error) + + // NewCountMetric creates a new CountMetric instance. Useful for tracking the count of a type of event. + // Metric name and label may only contain alphanumeric characters and underscores. + // + // The labelTemplate parameter is the label type that will be used for this metric. Each field becomes a label for + // the metric. Each field type must be a string. If no labels are needed, pass nil. + NewCountMetric( + name string, + description string, + labelTemplate any) (CountMetric, error) + + // NewGaugeMetric creates a new GaugeMetric instance. Useful for reporting specific values. + // Metric name and label may only contain alphanumeric characters and underscores. + // + // The labelTemplate parameter is the label type that will be used for this metric. Each field becomes a label for + // the metric. Each field type must be a string. If no labels are needed, pass nil. + NewGaugeMetric( + name string, + unit string, + description string, + labelTemplate any) (GaugeMetric, error) + + // NewAutoGauge creates a new GaugeMetric instance that is automatically updated by the given source function. + // The function is polled at the given period. This produces a gauge type metric internally. + // Metric name and label may only contain alphanumeric characters and underscores. + // + // The label parameter accepts zero or one label. + NewAutoGauge( + name string, + unit string, + description string, + pollPeriod time.Duration, + source func() float64, + label ...any) error +} + +// Metric represents a metric that can be reported. +type Metric interface { + + // Name returns the name of the metric. + Name() string + + // Unit returns the unit of the metric. + Unit() string + + // Description returns the description of the metric. Should be a one or two sentence human-readable description. + Description() string + + // Type returns the type of the metric. + Type() string + + // LabelFields returns the fields of the label template. + LabelFields() []string +} + +// GaugeMetric allows specific values to be reported. +type GaugeMetric interface { + Metric + + // Set sets the value of a gauge metric. + // + // The label parameter accepts zero or one label. If the label type does not match the template label type provided + // when creating the metric, an error will be returned. + Set(value float64, label ...any) +} + +// CountMetric allows the count of a type of event to be tracked. +type CountMetric interface { + Metric + + // Increment increments the count by 1. + // + // The label parameter accepts zero or one label. If the label type does not match the template label type provided + // when creating the metric, an error will be returned. + Increment(label ...any) + + // Add increments the count by the given value. + // + // The label parameter accepts zero or one label. If the label type does not match the template label type provided + // when creating the metric, an error will be returned. + Add(value float64, label ...any) +} + +// Quantile describes a quantile of a latency metric that should be reported. For a description of how +// to interpret a quantile, see the prometheus documentation +// https://github.com/prometheus/client_golang/blob/v1.20.5/prometheus/summary.go#L126 +type Quantile struct { + Quantile float64 + Error float64 +} + +// NewQuantile creates a new Quantile instance. Error is set to 1% of the quantile. +func NewQuantile(quantile float64) *Quantile { + return &Quantile{ + Quantile: quantile, + Error: quantile / 100.0, + } +} + +// LatencyMetric allows the latency of an operation to be tracked. Similar to a gauge metric, but specialized for time. +// +// The label parameter accepts zero or one label. If the label type does not match the template label type provided +// when creating the metric, an error will be returned. +type LatencyMetric interface { + Metric + + // ReportLatency reports a latency value. + // + // The label parameter accepts zero or one label. If the label type does not match the template label type provided + // when creating the metric, an error will be returned. + ReportLatency(latency time.Duration, label ...any) +} diff --git a/common/metrics/metrics_server.go b/common/metrics/metrics_server.go new file mode 100644 index 0000000000..f18fd02acd --- /dev/null +++ b/common/metrics/metrics_server.go @@ -0,0 +1,430 @@ +package metrics + +import ( + "errors" + "fmt" + "github.com/Layr-Labs/eigensdk-go/logging" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" + "net/http" + "os" + "regexp" + "slices" + "strings" + "sync" + "sync/atomic" + "time" +) + +var _ Metrics = &metrics{} + +// metrics is a standard implementation of the Metrics interface via prometheus. +type metrics struct { + // logger is the logger used to log messages. + logger logging.Logger + + // config is the configuration for the metrics. + config *Config + + // registry is the prometheus registry used to report metrics. + registry *prometheus.Registry + + // A map from metricID to Metric instance. If a metric is requested but that metric + // already exists, the existing metric will be returned instead of a new one being created. + metricMap map[metricID]Metric + + // autoGaugesToStart is a list of functions that will start auto-gauges. If an auto-gauge is created + // before the metrics server is started, we don't actually start the goroutine until the server is started. + autoGaugesToStart []func() + + // lock is a lock used to ensure that metrics are not created concurrently. + lock sync.Mutex + + // started is true if the metrics server has been started. + started bool + + // isAlize is true if the metrics server has not been stopped. + isAlive atomic.Bool + + // server is the metrics server + server *http.Server + + // quantilesMap contains a string describing the quantiles for each latency metric. Used to generate documentation. + quantilesMap map[metricID]string +} + +// NewMetrics creates a new Metrics instance. +func NewMetrics(logger logging.Logger, config *Config) Metrics { + reg := prometheus.NewRegistry() + reg.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})) + reg.MustRegister(collectors.NewGoCollector()) + + logger.Infof("Starting metrics server at port %d", config.HTTPPort) + addr := fmt.Sprintf(":%d", config.HTTPPort) + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.HandlerFor( + reg, + promhttp.HandlerOpts{}, + )) + server := &http.Server{ + Addr: addr, + Handler: mux, + } + + m := &metrics{ + logger: logger, + config: config, + registry: reg, + metricMap: make(map[metricID]Metric), + isAlive: atomic.Bool{}, + server: server, + quantilesMap: make(map[metricID]string), + } + m.isAlive.Store(true) + return m +} + +// metricID is a unique identifier for a metric. +type metricID struct { + name string + unit string +} + +var legalCharactersRegex = regexp.MustCompile(`^[a-zA-Z0-9_]+$`) + +// containsLegalCharacters returns true if the string contains only legal characters (alphanumeric and underscore). +func containsLegalCharacters(s string) bool { + return legalCharactersRegex.MatchString(s) +} + +// newMetricID creates a new metricID instance. +func newMetricID(name string, unit string) (metricID, error) { + if !containsLegalCharacters(name) { + return metricID{}, fmt.Errorf("invalid metric name: %s", name) + } + if !containsLegalCharacters(unit) { + return metricID{}, fmt.Errorf("invalid metric unit: %s", unit) + } + return metricID{ + name: name, + unit: unit, + }, nil +} + +// NameWithUnit returns the name of the metric with the unit appended. +func (i *metricID) NameWithUnit() string { + return fmt.Sprintf("%s_%s", i.name, i.unit) +} + +// Start starts the metrics server. +func (m *metrics) Start() error { + m.lock.Lock() + defer m.lock.Unlock() + + if m.started { + return errors.New("metrics server already started") + } + m.started = true + + go func() { + err := m.server.ListenAndServe() + if err != nil && !strings.Contains(err.Error(), "http: Server closed") { + m.logger.Errorf("metrics server error: %v", err) + } + }() + + // start the auto-gauges that were created before the server was started + for _, autoGauge := range m.autoGaugesToStart { + go autoGauge() + } + + return nil +} + +// Stop stops the metrics server. +func (m *metrics) Stop() error { + m.lock.Lock() + defer m.lock.Unlock() + + if !m.started { + return errors.New("metrics server not started") + } + + if !m.isAlive.Load() { + return errors.New("metrics server already stopped") + } + + m.isAlive.Store(false) + return m.server.Close() +} + +// NewLatencyMetric creates a new LatencyMetric instance. +func (m *metrics) NewLatencyMetric( + name string, + description string, + labelTemplate any, + quantiles ...*Quantile) (LatencyMetric, error) { + + m.lock.Lock() + defer m.lock.Unlock() + + if !m.isAlive.Load() { + return nil, errors.New("metrics server is not alive") + } + + id, err := newMetricID(name, "ms") + if err != nil { + return nil, err + } + + preExistingMetric, ok := m.metricMap[id] + if ok { + return preExistingMetric.(LatencyMetric), nil + } + + quantilesString := "" + objectives := make(map[float64]float64, len(quantiles)) + for i, q := range quantiles { + objectives[q.Quantile] = q.Error + + quantilesString += fmt.Sprintf("`%.3f`", q.Quantile) + if i < len(quantiles)-1 { + quantilesString += ", " + } + } + m.quantilesMap[id] = quantilesString + + metric, err := newLatencyMetric( + m.logger, + m.registry, + m.config.Namespace, + name, + description, + objectives, + labelTemplate) + + if err != nil { + return nil, err + } + + m.metricMap[id] = metric + return metric, nil +} + +// NewCountMetric creates a new CountMetric instance. +func (m *metrics) NewCountMetric( + name string, + description string, + labelTemplate any) (CountMetric, error) { + + m.lock.Lock() + defer m.lock.Unlock() + + if !m.isAlive.Load() { + return nil, errors.New("metrics server is not alive") + } + + id, err := newMetricID(name, "count") + if err != nil { + return nil, err + } + + preExistingMetric, ok := m.metricMap[id] + if ok { + return preExistingMetric.(CountMetric), nil + } + + metric, err := newCountMetric( + m.logger, + m.registry, + m.config.Namespace, + name, description, + labelTemplate) + + if err != nil { + return nil, err + } + + m.metricMap[id] = metric + + return metric, nil +} + +// NewGaugeMetric creates a new GaugeMetric instance. +func (m *metrics) NewGaugeMetric( + name string, + unit string, + description string, + labelTemplate any) (GaugeMetric, error) { + + m.lock.Lock() + defer m.lock.Unlock() + return m.newGaugeMetricUnsafe(name, unit, description, labelTemplate) +} + +// newGaugeMetricUnsafe creates a new GaugeMetric instance without locking. +func (m *metrics) newGaugeMetricUnsafe( + name string, + unit string, + description string, + labelTemplate any) (GaugeMetric, error) { + + if !m.isAlive.Load() { + return nil, errors.New("metrics server is not alive") + } + + id, err := newMetricID(name, unit) + if err != nil { + return nil, err + } + + preExistingMetric, ok := m.metricMap[id] + if ok { + return preExistingMetric.(GaugeMetric), nil + } + + metric, err := newGaugeMetric( + m.logger, + m.registry, + m.config.Namespace, + name, + unit, + description, + labelTemplate) + + if err != nil { + return nil, err + } + + m.metricMap[id] = metric + return metric, nil +} + +func (m *metrics) NewAutoGauge( + name string, + unit string, + description string, + pollPeriod time.Duration, + source func() float64, + label ...any) error { + + m.lock.Lock() + defer m.lock.Unlock() + + if !m.isAlive.Load() { + return errors.New("metrics server is not alive") + } + + if len(label) > 1 { + return fmt.Errorf("too many labels provided, expected 1, got %d", len(label)) + } + var l any + if len(label) == 1 { + l = label[0] + } + + gauge, err := m.newGaugeMetricUnsafe(name, unit, description, l) + if err != nil { + return err + } + + pollingAgent := func() { + ticker := time.NewTicker(pollPeriod) + for m.isAlive.Load() { + value := source() + + gauge.Set(value, l) + <-ticker.C + } + } + + if m.started { + // start the polling agent immediately + go pollingAgent() + } else { + // the polling agent will be started when the metrics server is started + m.autoGaugesToStart = append(m.autoGaugesToStart, pollingAgent) + } + + return nil +} + +func (m *metrics) GenerateMetricsDocumentation() string { + sb := &strings.Builder{} + + metricIDs := make([]*metricID, 0, len(m.metricMap)) + for id := range m.metricMap { + boundID := id + metricIDs = append(metricIDs, &boundID) + } + + // sort the metric IDs alphabetically + sortFunc := func(a *metricID, b *metricID) int { + if a.name != b.name { + return strings.Compare(a.name, b.name) + } + return strings.Compare(a.unit, b.unit) + } + slices.SortFunc(metricIDs, sortFunc) + + sb.Write([]byte(fmt.Sprintf("# Metrics Documentation for namespace '%s'\n\n", m.config.Namespace))) + sb.Write([]byte(fmt.Sprintf("This documentation was automatically generated at time `%s`\n\n", + time.Now().Format(time.RFC3339)))) + + sb.Write([]byte(fmt.Sprintf("There are a total of `%d` registered metrics.\n\n", len(m.metricMap)))) + + for _, id := range metricIDs { + metric := m.metricMap[*id] + + sb.Write([]byte("---\n\n")) + sb.Write([]byte(fmt.Sprintf("## %s\n\n", id.NameWithUnit()))) + + sb.Write([]byte(fmt.Sprintf("%s\n\n", metric.Description()))) + + sb.Write([]byte("| | |\n")) + sb.Write([]byte("|---|---|\n")) + sb.Write([]byte(fmt.Sprintf("| **Name** | `%s` |\n", metric.Name()))) + sb.Write([]byte(fmt.Sprintf("| **Unit** | `%s` |\n", metric.Unit()))) + labels := metric.LabelFields() + if len(labels) > 0 { + sb.Write([]byte("| **Labels** | ")) + for i, label := range labels { + sb.Write([]byte(fmt.Sprintf("`%s`", label))) + if i < len(labels)-1 { + sb.Write([]byte(", ")) + } + } + sb.Write([]byte(" |\n")) + } + sb.Write([]byte(fmt.Sprintf("| **Type** | `%s` |\n", metric.Type()))) + if metric.Type() == "latency" { + sb.Write([]byte(fmt.Sprintf("| **Quantiles** | %s |\n", m.quantilesMap[*id]))) + } + sb.Write([]byte(fmt.Sprintf("| **Fully Qualified Name** | `%s_%s_%s` |\n", + m.config.Namespace, id.name, id.unit))) + } + + return sb.String() +} + +func (m *metrics) WriteMetricsDocumentation(fileName string) error { + doc := m.GenerateMetricsDocumentation() + + file, err := os.Create(fileName) + if err != nil { + return fmt.Errorf("error creating file: %v", err) + } + + _, err = file.Write([]byte(doc)) + if err != nil { + return fmt.Errorf("error writing to file: %v", err) + } + + err = file.Close() + if err != nil { + return fmt.Errorf("error closing file: %v", err) + } + + return nil +} diff --git a/common/metrics/mock_metrics.go b/common/metrics/mock_metrics.go new file mode 100644 index 0000000000..695a2662ef --- /dev/null +++ b/common/metrics/mock_metrics.go @@ -0,0 +1,154 @@ +package metrics + +import ( + "time" +) + +var _ Metrics = &mockMetrics{} + +// mockMetrics is a mock implementation of the Metrics interface. +type mockMetrics struct { +} + +// NewMockMetrics creates a new mock Metrics instance. +// Suitable for testing or for when you just want to disable all metrics. +func NewMockMetrics() Metrics { + return &mockMetrics{} +} + +func (m *mockMetrics) GenerateMetricsDocumentation() string { + return "" +} + +func (m *mockMetrics) WriteMetricsDocumentation(fileName string) error { + return nil +} + +func (m *mockMetrics) Start() error { + return nil +} + +func (m *mockMetrics) Stop() error { + return nil +} + +func (m *mockMetrics) NewLatencyMetric( + name string, + description string, + templateLabel any, + quantiles ...*Quantile) (LatencyMetric, error) { + return &mockLatencyMetric{}, nil +} + +func (m *mockMetrics) NewCountMetric(name string, description string, templateLabel any) (CountMetric, error) { + return &mockCountMetric{}, nil +} + +func (m *mockMetrics) NewGaugeMetric( + name string, + unit string, + description string, + labelTemplate any) (GaugeMetric, error) { + return &mockGaugeMetric{}, nil +} + +func (m *mockMetrics) NewAutoGauge( + name string, + unit string, + description string, + pollPeriod time.Duration, + source func() float64, + label ...any) error { + return nil +} + +var _ CountMetric = &mockCountMetric{} + +type mockCountMetric struct { +} + +func (m *mockCountMetric) Name() string { + return "" +} + +func (m *mockCountMetric) Unit() string { + return "" +} + +func (m *mockCountMetric) Description() string { + return "" +} + +func (m *mockCountMetric) Type() string { + return "" +} + +func (m *mockCountMetric) LabelFields() []string { + return make([]string, 0) +} + +func (m *mockCountMetric) Increment(label ...any) { + +} + +func (m *mockCountMetric) Add(value float64, label ...any) { + +} + +var _ GaugeMetric = &mockGaugeMetric{} + +type mockGaugeMetric struct { +} + +func (m *mockGaugeMetric) Name() string { + return "" +} + +func (m *mockGaugeMetric) Unit() string { + return "" +} + +func (m *mockGaugeMetric) Description() string { + return "" +} + +func (m *mockGaugeMetric) Type() string { + return "" +} + +func (m *mockGaugeMetric) LabelFields() []string { + return make([]string, 0) +} + +func (m *mockGaugeMetric) Set(value float64, label ...any) { + +} + +var _ LatencyMetric = &mockLatencyMetric{} + +type mockLatencyMetric struct { +} + +func (m *mockLatencyMetric) Name() string { + return "" +} + +func (m *mockLatencyMetric) Unit() string { + return "" +} + +func (m *mockLatencyMetric) Description() string { + return "" +} + +func (m *mockLatencyMetric) Type() string { + return "" +} + +func (m *mockLatencyMetric) LabelFields() []string { + return make([]string, 0) +} + +func (m *mockLatencyMetric) ReportLatency(latency time.Duration, label ...any) { + +} diff --git a/common/metrics/test/main.go b/common/metrics/test/main.go new file mode 100644 index 0000000000..bdd1050b2b --- /dev/null +++ b/common/metrics/test/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "fmt" + "github.com/Layr-Labs/eigenda/common" + "github.com/Layr-Labs/eigenda/common/metrics" + "math/rand" + "sync/atomic" + "time" +) + +// This is a simple test bed for validating the metrics server (since it's not straight forward to unit test). + +type LabelType1 struct { + foo string + bar string + baz string +} + +type LabelType2 struct { + X string + Y string + Z string +} + +func main() { + + metricsConfig := &metrics.Config{ + Namespace: "test", + HTTPPort: 9101, + } + + logger, err := common.NewLogger(common.DefaultLoggerConfig()) + if err != nil { + panic(err) + } + + metricsServer := metrics.NewMetrics(logger, metricsConfig) + + l1, err := metricsServer.NewLatencyMetric( + "l1", + "this metric shows the latency of the sleep cycle", + LabelType1{}, + metrics.NewQuantile(0.5), + metrics.NewQuantile(0.9), + metrics.NewQuantile(0.99)) + if err != nil { + panic(err) + } + + c1, err := metricsServer.NewCountMetric( + "c1", + "this metric shows the number of times the sleep cycle has been executed", + LabelType2{}) + if err != nil { + panic(err) + } + + c2, err := metricsServer.NewCountMetric( + "c2", + "the purpose of this counter is to test what happens if we don't provide a label template", + nil) + if err != nil { + panic(err) + } + + g1, err := metricsServer.NewGaugeMetric( + "g1", + "milliseconds", + "this metric shows the duration of the most recent sleep cycle", + LabelType1{}) + if err != nil { + panic(err) + } + + sum := atomic.Int64{} + err = metricsServer.NewAutoGauge( + "g2", + "milliseconds", + "this metric shows the sum of all sleep cycles", + 1*time.Second, + func() float64 { + return float64(sum.Load()) + }, + LabelType2{X: "sum"}) + if err != nil { + panic(err) + } + + err = metricsServer.WriteMetricsDocumentation("metrics.md") + if err != nil { + panic(err) + } + + err = metricsServer.Start() + if err != nil { + panic(err) + } + + prev := time.Now() + for i := 0; i < 100; i++ { + fmt.Printf("Iteration %d\n", i) + time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) + now := time.Now() + elapsed := now.Sub(prev) + prev = now + + l1.ReportLatency(elapsed) + + l1.ReportLatency(elapsed/2, + LabelType1{ + foo: "half of the normal value", + bar: "42", + baz: "true", + }) + + c1.Increment() + c1.Add(2, LabelType2{ + X: "2x", + }) + c2.Increment() + + g1.Set(float64(elapsed.Milliseconds()), + LabelType1{ + foo: "bar", + bar: "baz", + baz: "foo", + }) + + sum.Store(sum.Load() + elapsed.Milliseconds()) + } + + err = metricsServer.Stop() + if err != nil { + panic(err) + } +} diff --git a/common/metrics/test/metrics.md b/common/metrics/test/metrics.md new file mode 100644 index 0000000000..dfb98804a5 --- /dev/null +++ b/common/metrics/test/metrics.md @@ -0,0 +1,71 @@ +# Metrics Documentation for namespace 'test' + +This documentation was automatically generated at time `2024-11-25T12:46:49-06:00` + +There are a total of `5` registered metrics. + +--- + +## c1_count + +this metric shows the number of times the sleep cycle has been executed + +| | | +|---|---| +| **Name** | `c1` | +| **Unit** | `count` | +| **Labels** | `X`, `Y`, `Z` | +| **Type** | `counter` | +| **Fully Qualified Name** | `test_c1_count` | +--- + +## c2_count + +the purpose of this counter is to test what happens if we don't provide a label template + +| | | +|---|---| +| **Name** | `c2` | +| **Unit** | `count` | +| **Type** | `counter` | +| **Fully Qualified Name** | `test_c2_count` | +--- + +## g1_milliseconds + +this metric shows the duration of the most recent sleep cycle + +| | | +|---|---| +| **Name** | `g1` | +| **Unit** | `milliseconds` | +| **Labels** | `foo`, `bar`, `baz` | +| **Type** | `gauge` | +| **Fully Qualified Name** | `test_g1_milliseconds` | +--- + +## g2_milliseconds + +this metric shows the sum of all sleep cycles + +| | | +|---|---| +| **Name** | `g2` | +| **Unit** | `milliseconds` | +| **Labels** | `X`, `Y`, `Z` | +| **Type** | `gauge` | +| **Fully Qualified Name** | `test_g2_milliseconds` | +--- + +## l1_ms + +this metric shows the latency of the sleep cycle + +| | | +|---|---| +| **Name** | `l1` | +| **Unit** | `ms` | +| **Labels** | `foo`, `bar`, `baz` | +| **Type** | `latency` | +| **Quantiles** | `0.500`, `0.900`, `0.990` | +| **Fully Qualified Name** | `test_l1_ms` | From f6732a5be3b020cb7fc1ba657540379a9729175f Mon Sep 17 00:00:00 2001 From: hopeyen <60078528+hopeyen@users.noreply.github.com> Date: Wed, 27 Nov 2024 03:34:14 +0700 Subject: [PATCH 09/15] [SocketRegistry] get operator socket (#863) --- core/chainio.go | 3 ++ core/eth/reader.go | 34 +++++++++++++++++++ core/eth/state.go | 8 +++++ core/mock/state.go | 7 ++++ core/mock/writer.go | 6 ++++ core/state.go | 1 + .../dataapi/queried_operators_handlers.go | 13 +++++++ node/node.go | 10 +++++- node/node_test.go | 3 ++ test/integration_test.go | 2 ++ tools/semverscan/cmd/main.go | 14 ++++++++ 11 files changed, 100 insertions(+), 1 deletion(-) diff --git a/core/chainio.go b/core/chainio.go index 340e9e6b18..cb76848efa 100644 --- a/core/chainio.go +++ b/core/chainio.go @@ -72,6 +72,9 @@ type Reader interface { // GetOperatorSetParams returns operator set params for the quorum. GetOperatorSetParams(ctx context.Context, quorumID QuorumID) (*OperatorSetParam, error) + // GetOperatorSocket returns a operator's socket. + GetOperatorSocket(ctx context.Context, operatorID OperatorID) (string, error) + // GetNumberOfRegisteredOperatorForQuorum returns the number of registered operators for the quorum. GetNumberOfRegisteredOperatorForQuorum(ctx context.Context, quorumID QuorumID) (uint32, error) diff --git a/core/eth/reader.go b/core/eth/reader.go index 3f47e3c3cb..bf5aa5bb0d 100644 --- a/core/eth/reader.go +++ b/core/eth/reader.go @@ -15,6 +15,7 @@ import ( indexreg "github.com/Layr-Labs/eigenda/contracts/bindings/IIndexRegistry" opstateretriever "github.com/Layr-Labs/eigenda/contracts/bindings/OperatorStateRetriever" regcoordinator "github.com/Layr-Labs/eigenda/contracts/bindings/RegistryCoordinator" + socketreg "github.com/Layr-Labs/eigenda/contracts/bindings/SocketRegistry" stakereg "github.com/Layr-Labs/eigenda/contracts/bindings/StakeRegistry" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigensdk-go/logging" @@ -37,6 +38,7 @@ type ContractBindings struct { EigenDAServiceManager *eigendasrvmg.ContractEigenDAServiceManager EjectionManager *ejectionmg.ContractEjectionManager AVSDirectory *avsdir.ContractAVSDirectory + SocketRegistry *socketreg.ContractSocketRegistry } type Reader struct { @@ -164,10 +166,23 @@ func (t *Reader) updateContractBindings(blsOperatorStateRetrieverAddr, eigenDASe return err } + socketRegistryAddr, err := contractIRegistryCoordinator.SocketRegistry(&bind.CallOpts{}) + if err != nil { + t.logger.Error("Failed to fetch SocketRegistry address", "err", err) + return err + } + + contractSocketRegistry, err := socketreg.NewContractSocketRegistry(socketRegistryAddr, t.ethClient) + if err != nil { + t.logger.Error("Failed to fetch SocketRegistry contract", "err", err) + return err + } + t.bindings = &ContractBindings{ ServiceManagerAddr: eigenDAServiceManagerAddr, RegCoordinatorAddr: registryCoordinatorAddr, AVSDirectory: contractAVSDirectory, + SocketRegistry: contractSocketRegistry, OpStateRetriever: contractBLSOpStateRetr, BLSApkRegistry: contractBLSPubkeyReg, IndexRegistry: contractIIndexReg, @@ -377,6 +392,12 @@ func (t *Reader) StakeRegistry(ctx context.Context) (gethcommon.Address, error) }) } +func (t *Reader) SocketRegistry(ctx context.Context) (gethcommon.Address, error) { + return t.bindings.RegistryCoordinator.SocketRegistry(&bind.CallOpts{ + Context: ctx, + }) +} + func (t *Reader) OperatorIDToAddress(ctx context.Context, operatorId core.OperatorID) (gethcommon.Address, error) { return t.bindings.BLSApkRegistry.PubkeyHashToOperator(&bind.CallOpts{ Context: ctx, @@ -655,3 +676,16 @@ func (t *Reader) GetReservationWindow(ctx context.Context) (uint32, error) { // contract is not implemented yet return 0, nil } + +func (t *Reader) GetOperatorSocket(ctx context.Context, operatorId core.OperatorID) (string, error) { + socket, err := t.bindings.SocketRegistry.GetOperatorSocket(&bind.CallOpts{ + Context: ctx, + }, [32]byte(operatorId)) + if err != nil { + return "", err + } + if socket == "" { + return "", errors.New("operator socket string is empty, check operator with id: " + operatorId.Hex()) + } + return socket, nil +} diff --git a/core/eth/state.go b/core/eth/state.go index 8b24842ae9..fd65d7298d 100644 --- a/core/eth/state.go +++ b/core/eth/state.go @@ -51,6 +51,14 @@ func (cs *ChainState) GetCurrentBlockNumber() (uint, error) { return uint(header.Number.Uint64()), nil } +func (cs *ChainState) GetOperatorSocket(ctx context.Context, blockNumber uint, operator core.OperatorID) (string, error) { + socket, err := cs.Tx.GetOperatorSocket(ctx, operator) + if err != nil { + return "", err + } + return socket, nil +} + func getOperatorState(operatorsByQuorum core.OperatorStakes, blockNumber uint32) (*core.OperatorState, error) { operators := make(map[core.QuorumID]map[core.OperatorID]*core.OperatorInfo) totals := make(map[core.QuorumID]*core.OperatorInfo) diff --git a/core/mock/state.go b/core/mock/state.go index f182441ca0..2c2934357c 100644 --- a/core/mock/state.go +++ b/core/mock/state.go @@ -238,6 +238,13 @@ func (d *ChainDataMock) GetOperatorStateByOperator(ctx context.Context, blockNum } +func (d *ChainDataMock) GetOperatorSocket(ctx context.Context, blockNumber uint, operator core.OperatorID) (string, error) { + + state := d.GetTotalOperatorState(ctx, blockNumber) + + return state.IndexedOperatorState.IndexedOperators[operator].Socket, nil +} + func (d *ChainDataMock) GetIndexedOperatorState(ctx context.Context, blockNumber uint, quorums []core.QuorumID) (*core.IndexedOperatorState, error) { state := d.GetTotalOperatorStateWithQuorums(ctx, blockNumber, quorums) diff --git a/core/mock/writer.go b/core/mock/writer.go index b700b8cd71..c70db8fc0b 100644 --- a/core/mock/writer.go +++ b/core/mock/writer.go @@ -241,3 +241,9 @@ func (t *MockWriter) GetOnDemandPaymentByAccount(ctx context.Context, blockNumbe result := args.Get(0) return result.(core.OnDemandPayment), args.Error(1) } + +func (t *MockWriter) GetOperatorSocket(ctx context.Context, operatorID core.OperatorID) (string, error) { + args := t.Called() + result := args.Get(0) + return result.(string), args.Error(1) +} diff --git a/core/state.go b/core/state.go index 61cda9f30b..2bbf08d90b 100644 --- a/core/state.go +++ b/core/state.go @@ -128,6 +128,7 @@ type ChainState interface { GetCurrentBlockNumber() (uint, error) GetOperatorState(ctx context.Context, blockNumber uint, quorums []QuorumID) (*OperatorState, error) GetOperatorStateByOperator(ctx context.Context, blockNumber uint, operator OperatorID) (*OperatorState, error) + GetOperatorSocket(ctx context.Context, blockNumber uint, operator OperatorID) (string, error) } // ChainState is an interface for getting information about the current chain state. diff --git a/disperser/dataapi/queried_operators_handlers.go b/disperser/dataapi/queried_operators_handlers.go index a3a56662f9..b9b5bdf7e6 100644 --- a/disperser/dataapi/queried_operators_handlers.go +++ b/disperser/dataapi/queried_operators_handlers.go @@ -295,6 +295,19 @@ func (s *server) scanOperatorsHostInfo(ctx context.Context) (*SemverReportRespon if err != nil { return nil, fmt.Errorf("failed to fetch indexed operator info - %s", err) } + + // check operator socket registration against the indexed state + for operatorID, operatorInfo := range operators { + socket, err := s.chainState.GetOperatorSocket(context.Background(), currentBlock, operatorID) + if err != nil { + s.logger.Warn("failed to get operator socket", "operatorId", operatorID.Hex(), "error", err) + continue + } + if socket != operatorInfo.Socket { + s.logger.Warn("operator socket mismatch", "operatorId", operatorID.Hex(), "socket", socket, "operatorInfo", operatorInfo.Socket) + } + } + s.logger.Info("Queried indexed operators", "operators", len(operators), "block", currentBlock) operatorState, err := s.chainState.GetOperatorState(context.Background(), currentBlock, []core.QuorumID{0, 1, 2}) if err != nil { diff --git a/node/node.go b/node/node.go index 925fbe4517..550228e9c9 100644 --- a/node/node.go +++ b/node/node.go @@ -305,7 +305,6 @@ func (n *Node) Start(ctx context.Context) error { n.Logger.Info("Registering node on chain with the following parameters:", "operatorId", n.Config.ID.Hex(), "hostname", n.Config.Hostname, "dispersalPort", n.Config.DispersalPort, "retrievalPort", n.Config.RetrievalPort, "churnerUrl", n.Config.ChurnerUrl, "quorumIds", fmt.Sprint(n.Config.QuorumIDList)) - socket := string(core.MakeOperatorSocket(n.Config.Hostname, n.Config.DispersalPort, n.Config.RetrievalPort)) privateKey, err := crypto.HexToECDSA(n.Config.EthClientConfig.PrivateKeyString) if err != nil { return fmt.Errorf("NewClient: cannot parse private key: %w", err) @@ -326,6 +325,15 @@ func (n *Node) Start(ctx context.Context) error { return fmt.Errorf("failed to register the operator: %w", err) } } else { + registeredSocket, err := n.Transactor.GetOperatorSocket(ctx, n.Config.ID) + // Error out if registration on-chain is a requirement + if err != nil { + n.Logger.Warnf("failed to get operator socket: %w", err) + } + if registeredSocket != socket { + n.Logger.Warnf("registered socket %s does not match expected socket %s", registeredSocket, socket) + } + eigenDAUrl, ok := eigenDAUIMap[n.ChainID.String()] if ok { n.Logger.Infof("The node has successfully started. Note: if it's not opted in on %s, then please follow the EigenDA operator guide section in docs.eigenlayer.xyz to register", eigenDAUrl) diff --git a/node/node_test.go b/node/node_test.go index f2607362f0..e66a287b93 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -2,6 +2,7 @@ package node_test import ( "context" + "errors" "os" "runtime" "testing" @@ -105,6 +106,8 @@ func TestNodeStartNoAddress(t *testing.T) { c := newComponents(t) c.node.Config.RegisterNodeAtStart = false + c.tx.On("GetOperatorSocket", mock.Anything).Return("", errors.New("failed to get operator socket")) + err := c.node.Start(context.Background()) assert.NoError(t, err) } diff --git a/test/integration_test.go b/test/integration_test.go index aebb546f4a..3df7de45ed 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -376,6 +376,8 @@ func mustMakeOperators(t *testing.T, cst *coremock.ChainDataMock, logger logging tx.On("GetBlockStaleMeasure").Return(nil) tx.On("GetStoreDurationBlocks").Return(nil) tx.On("OperatorIDToAddress").Return(gethcommon.Address{1}, nil) + socket := core.MakeOperatorSocket(config.Hostname, config.DispersalPort, config.RetrievalPort) + tx.On("GetOperatorSocket", mock.Anything, mock.Anything).Return(socket.String(), nil) noopMetrics := metrics.NewNoopMetrics() reg := prometheus.NewRegistry() diff --git a/tools/semverscan/cmd/main.go b/tools/semverscan/cmd/main.go index f567d8f210..aeb2ba4575 100644 --- a/tools/semverscan/cmd/main.go +++ b/tools/semverscan/cmd/main.go @@ -87,6 +87,20 @@ func RunScan(ctx *cli.Context) error { } } } + + // check operator socket registration against the indexed state + for operatorID, operatorInfo := range operators { + socket, err := chainState.GetOperatorSocket(context.Background(), currentBlock, operatorID) + if err != nil { + logger.Warn("failed to get operator socket", "operatorId", operatorID.Hex(), "error", err) + continue + } + if socket != operatorInfo.Socket { + // delete operator from operators if there's a mistmatch? + logger.Warn("operator socket mismatch", "operatorId", operatorID.Hex(), "socket", socket, "operatorInfo", operatorInfo.Socket) + } + } + logger.Info("Queried operator state", "count", len(operators)) semvers := semver.ScanOperators(operators, operatorState, config.UseRetrievalClient, config.Workers, config.Timeout, logger) From b3a90d1e716cba8a0bcddaa6d62ce2b157a08af1 Mon Sep 17 00:00:00 2001 From: Jian Xiao <99709935+jianoaix@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:58:50 -0800 Subject: [PATCH 10/15] Integrate pprof to encoder and node (#935) --- disperser/cmd/encoder/config.go | 2 ++ disperser/cmd/encoder/flags/flags.go | 15 ++++++++++++++ disperser/encoder/config.go | 2 ++ disperser/encoder/server.go | 29 ++++++++++++++++------------ node/config.go | 5 +++++ node/flags/flags.go | 15 ++++++++++++++ node/node.go | 6 ++++++ 7 files changed, 62 insertions(+), 12 deletions(-) diff --git a/disperser/cmd/encoder/config.go b/disperser/cmd/encoder/config.go index 69c0ff6400..4003adcf98 100644 --- a/disperser/cmd/encoder/config.go +++ b/disperser/cmd/encoder/config.go @@ -58,6 +58,8 @@ func NewConfig(ctx *cli.Context) (Config, error) { RequestPoolSize: ctx.GlobalInt(flags.RequestPoolSizeFlag.Name), EnableGnarkChunkEncoding: ctx.Bool(flags.EnableGnarkChunkEncodingFlag.Name), PreventReencoding: ctx.Bool(flags.PreventReencodingFlag.Name), + PprofHttpPort: ctx.GlobalString(flags.PprofHttpPort.Name), + EnablePprof: ctx.GlobalBool(flags.EnablePprof.Name), }, MetricsConfig: encoder.MetrisConfig{ HTTPPort: ctx.GlobalString(flags.MetricsHTTPPort.Name), diff --git a/disperser/cmd/encoder/flags/flags.go b/disperser/cmd/encoder/flags/flags.go index d14b45e04d..8c9399a399 100644 --- a/disperser/cmd/encoder/flags/flags.go +++ b/disperser/cmd/encoder/flags/flags.go @@ -73,6 +73,19 @@ var ( Required: false, EnvVar: common.PrefixEnvVar(envVarPrefix, "PREVENT_REENCODING"), } + PprofHttpPort = cli.StringFlag{ + Name: common.PrefixFlag(FlagPrefix, "pprof-http-port"), + Usage: "the http port which the pprof server is listening", + Required: false, + Value: "6060", + EnvVar: common.PrefixEnvVar(envVarPrefix, "PPROF_HTTP_PORT"), + } + EnablePprof = cli.BoolFlag{ + Name: common.PrefixFlag(FlagPrefix, "enable-pprof"), + Usage: "start prrof server", + Required: false, + EnvVar: common.PrefixEnvVar(envVarPrefix, "ENABLE_PPROF"), + } ) var requiredFlags = []cli.Flag{ @@ -88,6 +101,8 @@ var optionalFlags = []cli.Flag{ EncoderVersionFlag, S3BucketNameFlag, PreventReencodingFlag, + PprofHttpPort, + EnablePprof, } // Flags contains the list of configuration options available to the binary. diff --git a/disperser/encoder/config.go b/disperser/encoder/config.go index 8fcba36cd1..b543efe7b2 100644 --- a/disperser/encoder/config.go +++ b/disperser/encoder/config.go @@ -10,4 +10,6 @@ type ServerConfig struct { RequestPoolSize int EnableGnarkChunkEncoding bool PreventReencoding bool + PprofHttpPort string + EnablePprof bool } diff --git a/disperser/encoder/server.go b/disperser/encoder/server.go index 4eb0c39f61..f7f06e682c 100644 --- a/disperser/encoder/server.go +++ b/disperser/encoder/server.go @@ -10,12 +10,13 @@ import ( "time" "github.com/Layr-Labs/eigenda/common/healthcheck" + commonpprof "github.com/Layr-Labs/eigenda/common/pprof" "github.com/Layr-Labs/eigenda/disperser" pb "github.com/Layr-Labs/eigenda/disperser/api/grpc/encoder" - grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" "github.com/Layr-Labs/eigenda/disperser/common" "github.com/Layr-Labs/eigenda/encoding" "github.com/Layr-Labs/eigensdk-go/logging" + grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" "google.golang.org/grpc" "google.golang.org/grpc/reflection" ) @@ -23,12 +24,12 @@ import ( type EncoderServer struct { pb.UnimplementedEncoderServer - config ServerConfig - logger logging.Logger - prover encoding.Prover - metrics *Metrics + config ServerConfig + logger logging.Logger + prover encoding.Prover + metrics *Metrics grpcMetrics *grpcprom.ServerMetrics - close func() + close func() runningRequests chan struct{} requestPool chan blobRequest @@ -46,10 +47,10 @@ func NewEncoderServer(config ServerConfig, logger logging.Logger, prover encodin metrics.SetQueueCapacity(config.RequestPoolSize) return &EncoderServer{ - config: config, - logger: logger.With("component", "EncoderServer"), - prover: prover, - metrics: metrics, + config: config, + logger: logger.With("component", "EncoderServer"), + prover: prover, + metrics: metrics, grpcMetrics: grpcMetrics, runningRequests: make(chan struct{}, config.MaxConcurrentRequests), @@ -59,6 +60,12 @@ func NewEncoderServer(config ServerConfig, logger logging.Logger, prover encodin } func (s *EncoderServer) Start() error { + pprofProfiler := commonpprof.NewPprofProfiler(s.config.PprofHttpPort, s.logger) + if s.config.EnablePprof { + go pprofProfiler.Start() + s.logger.Info("Enabled pprof for encoder server", "port", s.config.PprofHttpPort) + } + // Serve grpc requests addr := fmt.Sprintf("%s:%s", disperser.Localhost, s.config.GrpcPort) listener, err := net.Listen("tcp", addr) @@ -104,8 +111,6 @@ func (s *EncoderServer) EncodeBlob(ctx context.Context, req *pb.EncodeBlobReques blobSize := len(req.GetData()) sizeBucket := common.BlobSizeBucket(blobSize) - - select { case s.requestPool <- blobRequest{blobSizeByte: blobSize}: s.queueLock.Lock() diff --git a/node/config.go b/node/config.go index 7d73bdcb20..c5244e55bd 100644 --- a/node/config.go +++ b/node/config.go @@ -91,6 +91,9 @@ type Config struct { EnableV2 bool OnchainStateRefreshInterval time.Duration + + PprofHttpPort string + EnablePprof bool } // NewConfig parses the Config from the provided flags or environment variables and @@ -237,5 +240,7 @@ func NewConfig(ctx *cli.Context) (*Config, error) { BLSRemoteSignerEnabled: blsRemoteSignerEnabled, EnableV2: ctx.GlobalBool(flags.EnableV2Flag.Name), OnchainStateRefreshInterval: ctx.GlobalDuration(flags.OnchainStateRefreshIntervalFlag.Name), + PprofHttpPort: ctx.GlobalString(flags.PprofHttpPort.Name), + EnablePprof: ctx.GlobalBool(flags.EnablePprof.Name), }, nil } diff --git a/node/flags/flags.go b/node/flags/flags.go index b16e2709e9..40c1237a7d 100644 --- a/node/flags/flags.go +++ b/node/flags/flags.go @@ -313,6 +313,19 @@ var ( Required: false, EnvVar: common.PrefixEnvVar(EnvVarPrefix, "BLS_SIGNER_CERT_FILE"), } + PprofHttpPort = cli.StringFlag{ + Name: common.PrefixFlag(FlagPrefix, "pprof-http-port"), + Usage: "the http port which the pprof server is listening", + Required: false, + Value: "6060", + EnvVar: common.PrefixEnvVar(EnvVarPrefix, "PPROF_HTTP_PORT"), + } + EnablePprof = cli.BoolFlag{ + Name: common.PrefixFlag(FlagPrefix, "enable-pprof"), + Usage: "start prrof server", + Required: false, + EnvVar: common.PrefixEnvVar(EnvVarPrefix, "ENABLE_PPROF"), + } ) var requiredFlags = []cli.Flag{ @@ -361,6 +374,8 @@ var optionalFlags = []cli.Flag{ BLSSignerCertFileFlag, EnableV2Flag, OnchainStateRefreshIntervalFlag, + PprofHttpPort, + EnablePprof, } func init() { diff --git a/node/node.go b/node/node.go index 550228e9c9..07055e55cb 100644 --- a/node/node.go +++ b/node/node.go @@ -18,6 +18,7 @@ import ( "time" "github.com/Layr-Labs/eigenda/common/kvstore/tablestore" + "github.com/Layr-Labs/eigenda/common/pprof" "github.com/Layr-Labs/eigenda/common/pubip" "github.com/Layr-Labs/eigenda/encoding/kzg/verifier" @@ -280,6 +281,11 @@ func NewNode( // Start starts the Node. If the node is not registered, register it on chain, otherwise just // update its socket on chain. func (n *Node) Start(ctx context.Context) error { + pprofProfiler := pprof.NewPprofProfiler(n.Config.PprofHttpPort, n.Logger) + if n.Config.EnablePprof { + go pprofProfiler.Start() + n.Logger.Info("Enabled pprof for Node", "port", n.Config.PprofHttpPort) + } if n.Config.EnableMetrics { n.Metrics.Start() n.Logger.Info("Enabled metrics", "socket", n.Metrics.socketAddr) From 53fd80dd8d9dadf30d563a47e5367fdaf01cab90 Mon Sep 17 00:00:00 2001 From: Cody Littley <56973212+cody-littley@users.noreply.github.com> Date: Wed, 27 Nov 2024 09:58:30 -0600 Subject: [PATCH 11/15] Metrics framework churner (#934) Signed-off-by: Cody Littley --- metrics.md | 4 + operators/churner/churner-metrics.md | 33 +++++++ operators/churner/churner_test.go | 3 +- operators/churner/cmd/main.go | 5 +- operators/churner/config.go | 2 +- operators/churner/flags/flags.go | 4 +- operators/churner/mdoc/main.go | 24 +++++ operators/churner/metrics.go | 124 ++++++++++++------------ operators/churner/server.go | 10 +- operators/churner/server_test.go | 3 +- operators/churner/tests/churner_test.go | 3 +- 11 files changed, 143 insertions(+), 72 deletions(-) create mode 100644 metrics.md create mode 100644 operators/churner/churner-metrics.md create mode 100644 operators/churner/mdoc/main.go diff --git a/metrics.md b/metrics.md new file mode 100644 index 0000000000..72c61a314b --- /dev/null +++ b/metrics.md @@ -0,0 +1,4 @@ +# EigenDA Metrics Documentation + +- [churner](operators/churner/churner-metrics.md) + diff --git a/operators/churner/churner-metrics.md b/operators/churner/churner-metrics.md new file mode 100644 index 0000000000..7a6b041805 --- /dev/null +++ b/operators/churner/churner-metrics.md @@ -0,0 +1,33 @@ +# Metrics Documentation for namespace 'eigenda_churner' + +This documentation was automatically generated at time `2024-11-26T14:29:13-06:00` + +There are a total of `2` registered metrics. + +--- + +## latency_ms + +latency summary in milliseconds + +| | | +|---|---| +| **Name** | `latency` | +| **Unit** | `ms` | +| **Labels** | `method` | +| **Type** | `latency` | +| **Quantiles** | `0.500`, `0.900`, `0.950`, `0.990` | +| **Fully Qualified Name** | `eigenda_churner_latency_ms` | +--- + +## request_count + +the number of requests + +| | | +|---|---| +| **Name** | `request` | +| **Unit** | `count` | +| **Labels** | `status`, `method`, `reason` | +| **Type** | `counter` | +| **Fully Qualified Name** | `eigenda_churner_request_count` | diff --git a/operators/churner/churner_test.go b/operators/churner/churner_test.go index 0854de7496..35c0269776 100644 --- a/operators/churner/churner_test.go +++ b/operators/churner/churner_test.go @@ -28,7 +28,8 @@ func TestProcessChurnRequest(t *testing.T) { NumRetries: numRetries, }, } - metrics := churner.NewMetrics("9001", logger) + metrics, err := churner.NewMetrics(9001, logger) + assert.NoError(t, err) cn, err := churner.NewChurner(config, mockIndexer, transactorMock, logger, metrics) assert.NoError(t, err) assert.NotNil(t, cn) diff --git a/operators/churner/cmd/main.go b/operators/churner/cmd/main.go index a9ecd76e87..33a8c422de 100644 --- a/operators/churner/cmd/main.go +++ b/operators/churner/cmd/main.go @@ -86,7 +86,10 @@ func run(ctx *cli.Context) error { logger.Info("Connecting to subgraph", "url", config.ChainStateConfig.Endpoint) indexer := thegraph.MakeIndexedChainState(config.ChainStateConfig, cs, logger) - metrics := churner.NewMetrics(config.MetricsConfig.HTTPPort, logger) + metrics, err := churner.NewMetrics(config.MetricsConfig.HTTPPort, logger) + if err != nil { + log.Fatalf("failed to create metrics: %v", err) + } cn, err := churner.NewChurner(config, indexer, tx, logger, metrics) if err != nil { diff --git a/operators/churner/config.go b/operators/churner/config.go index d35a72121b..fe2b1735a5 100644 --- a/operators/churner/config.go +++ b/operators/churner/config.go @@ -37,7 +37,7 @@ func NewConfig(ctx *cli.Context) (*Config, error) { PerPublicKeyRateLimit: ctx.GlobalDuration(flags.PerPublicKeyRateLimit.Name), ChurnApprovalInterval: ctx.GlobalDuration(flags.ChurnApprovalInterval.Name), MetricsConfig: MetricsConfig{ - HTTPPort: ctx.GlobalString(flags.MetricsHTTPPort.Name), + HTTPPort: ctx.GlobalInt(flags.MetricsHTTPPort.Name), EnableMetrics: ctx.GlobalBool(flags.EnableMetrics.Name), }, }, nil diff --git a/operators/churner/flags/flags.go b/operators/churner/flags/flags.go index 906096c490..507a352762 100644 --- a/operators/churner/flags/flags.go +++ b/operators/churner/flags/flags.go @@ -58,11 +58,11 @@ var ( EnvVar: common.PrefixEnvVar(envPrefix, "ENABLE_METRICS"), } /* Optional Flags*/ - MetricsHTTPPort = cli.StringFlag{ + MetricsHTTPPort = cli.IntFlag{ Name: common.PrefixFlag(FlagPrefix, "metrics-http-port"), Usage: "the http port which the metrics prometheus server is listening", Required: false, - Value: "9100", + Value: 9100, EnvVar: common.PrefixEnvVar(envPrefix, "METRICS_HTTP_PORT"), } ChurnApprovalInterval = cli.DurationFlag{ diff --git a/operators/churner/mdoc/main.go b/operators/churner/mdoc/main.go new file mode 100644 index 0000000000..db022d61f4 --- /dev/null +++ b/operators/churner/mdoc/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/Layr-Labs/eigenda/common" + "github.com/Layr-Labs/eigenda/operators/churner" +) + +// main generates documentation for churner metrics. +func main() { + logger, err := common.NewLogger(common.DefaultLoggerConfig()) + if err != nil { + panic(err) + } + + metrics, err := churner.NewMetrics(0, logger) + if err != nil { + panic(err) + } + + err = metrics.WriteMetricsDocumentation() + if err != nil { + panic(err) + } +} diff --git a/operators/churner/metrics.go b/operators/churner/metrics.go index 2cece57ad9..1f586e7ef7 100644 --- a/operators/churner/metrics.go +++ b/operators/churner/metrics.go @@ -1,15 +1,12 @@ package churner import ( - "context" - "fmt" - "net/http" + "github.com/Layr-Labs/eigenda/common/metrics" + "time" "github.com/Layr-Labs/eigensdk-go/logging" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc/codes" ) @@ -28,7 +25,7 @@ const ( ) // Note: statusCodeMap must be maintained in sync with failure reason constants. -var statusCodeMap map[FailReason]string = map[FailReason]string{ +var statusCodeMap = map[FailReason]string{ FailReasonRateLimitExceeded: codes.ResourceExhausted.String(), FailReasonInsufficientStakeToRegister: codes.InvalidArgument.String(), FailReasonInsufficientStakeToChurn: codes.InvalidArgument.String(), @@ -40,63 +37,80 @@ var statusCodeMap map[FailReason]string = map[FailReason]string{ } type MetricsConfig struct { - HTTPPort string + HTTPPort int EnableMetrics bool } type Metrics struct { - registry *prometheus.Registry + metricsServer metrics.Metrics - NumRequests *prometheus.CounterVec - Latency *prometheus.SummaryVec + numRequests metrics.CountMetric + latency metrics.LatencyMetric - httpPort string - logger logging.Logger + logger logging.Logger } -func NewMetrics(httpPort string, logger logging.Logger) *Metrics { - namespace := "eigenda_churner" +type latencyLabel struct { + method string +} + +type numRequestsLabel struct { + status string + method string + reason string +} + +func NewMetrics(httpPort int, logger logging.Logger) (*Metrics, error) { reg := prometheus.NewRegistry() reg.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})) reg.MustRegister(collectors.NewGoCollector()) - metrics := &Metrics{ - NumRequests: promauto.With(reg).NewCounterVec( - prometheus.CounterOpts{ - Namespace: namespace, - Name: "requests", - Help: "the number of requests", - }, - []string{"status", "reason", "method"}, - ), - Latency: promauto.With(reg).NewSummaryVec( - prometheus.SummaryOpts{ - Namespace: namespace, - Name: "latency_ms", - Help: "latency summary in milliseconds", - Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.01, 0.99: 0.001}, - }, - []string{"method"}, - ), - registry: reg, - httpPort: httpPort, - logger: logger.With("component", "ChurnerMetrics"), + metricsServer := metrics.NewMetrics(logger, &metrics.Config{ + Namespace: "eigenda_churner", + HTTPPort: httpPort, + }) + + numRequests, err := metricsServer.NewCountMetric( + "request", + "the number of requests", + numRequestsLabel{}) + if err != nil { + return nil, err } - return metrics + + latency, err := metricsServer.NewLatencyMetric( + "latency", + "latency summary in milliseconds", + latencyLabel{}, + &metrics.Quantile{Quantile: 0.5, Error: 0.05}, + &metrics.Quantile{Quantile: 0.9, Error: 0.01}, + &metrics.Quantile{Quantile: 0.95, Error: 0.01}, + &metrics.Quantile{Quantile: 0.99, Error: 0.001}) + if err != nil { + return nil, err + } + + return &Metrics{ + metricsServer: metricsServer, + numRequests: numRequests, + latency: latency, + logger: logger.With("component", "ChurnerMetrics"), + }, nil } -// ObserveLatency observes the latency of a stage in 'stage -func (g *Metrics) ObserveLatency(method string, latencyMs float64) { - g.Latency.WithLabelValues(method).Observe(latencyMs) +// WriteMetricsDocumentation writes the metrics for the churner to a markdown file. +func (g *Metrics) WriteMetricsDocumentation() error { + return g.metricsServer.WriteMetricsDocumentation("operators/churner/churner-metrics.md") +} + +// ObserveLatency observes the latency of a stage +func (g *Metrics) ObserveLatency(method string, latency time.Duration) { + g.latency.ReportLatency(latency, latencyLabel{method: method}) } // IncrementSuccessfulRequestNum increments the number of successful requests func (g *Metrics) IncrementSuccessfulRequestNum(method string) { - g.NumRequests.With(prometheus.Labels{ - "status": "success", - "method": method, - "reason": "", - }).Inc() + g.numRequests.Increment(numRequestsLabel{status: "success", method: method}) } // IncrementFailedRequestNum increments the number of failed requests @@ -108,25 +122,11 @@ func (g *Metrics) IncrementFailedRequestNum(method string, reason FailReason) { // handle a negligence of mapping from failure reason to status code. code = codes.Internal.String() } - g.NumRequests.With(prometheus.Labels{ - "status": code, - "reason": string(reason), - "method": method, - }).Inc() + + g.numRequests.Increment(numRequestsLabel{status: code, reason: string(reason), method: method}) } // Start starts the metrics server -func (g *Metrics) Start(ctx context.Context) { - g.logger.Info("Starting metrics server at ", "port", g.httpPort) - addr := fmt.Sprintf(":%s", g.httpPort) - go func() { - log := g.logger - mux := http.NewServeMux() - mux.Handle("/metrics", promhttp.HandlerFor( - g.registry, - promhttp.HandlerOpts{}, - )) - err := http.ListenAndServe(addr, mux) - log.Error("Prometheus server failed", "err", err) - }() +func (g *Metrics) Start() error { + return g.metricsServer.Start() } diff --git a/operators/churner/server.go b/operators/churner/server.go index fc8ba93103..83f62bf7fe 100644 --- a/operators/churner/server.go +++ b/operators/churner/server.go @@ -47,8 +47,12 @@ func NewServer( func (s *Server) Start(metricsConfig MetricsConfig) error { // Enable Metrics Block if metricsConfig.EnableMetrics { - httpSocket := fmt.Sprintf(":%s", metricsConfig.HTTPPort) - s.metrics.Start(context.Background()) + httpSocket := fmt.Sprintf(":%d", metricsConfig.HTTPPort) + err := s.metrics.Start() + if err != nil { + return fmt.Errorf("failed to start metrics server: %w", err) + } + s.logger.Info("Enabled metrics for Churner", "socket", httpSocket) } return nil @@ -62,7 +66,7 @@ func (s *Server) Churn(ctx context.Context, req *pb.ChurnRequest) (*pb.ChurnRepl } timer := prometheus.NewTimer(prometheus.ObserverFunc(func(f float64) { - s.metrics.ObserveLatency("Churn", f*1000) // make milliseconds + s.metrics.ObserveLatency("Churn", time.Duration(f*float64(time.Second))) })) defer timer.ObserveDuration() s.logger.Info("Received request: ", "QuorumIds", req.GetQuorumIds()) diff --git a/operators/churner/server_test.go b/operators/churner/server_test.go index 5c7c471b7f..e2b0fb6a2d 100644 --- a/operators/churner/server_test.go +++ b/operators/churner/server_test.go @@ -181,7 +181,8 @@ func newTestServer(t *testing.T) *churner.Server { setupMockWriter() - metrics := churner.NewMetrics("9001", logger) + metrics, err := churner.NewMetrics(9001, logger) + assert.NoError(t, err) cn, err := churner.NewChurner(config, mockIndexer, transactorMock, logger, metrics) if err != nil { log.Fatalln("cannot create churner", err) diff --git a/operators/churner/tests/churner_test.go b/operators/churner/tests/churner_test.go index ba9f11c522..5625c537c7 100644 --- a/operators/churner/tests/churner_test.go +++ b/operators/churner/tests/churner_test.go @@ -225,7 +225,8 @@ func newTestServer(t *testing.T) *churner.Server { ) assert.NoError(t, err) - metrics := churner.NewMetrics("9001", logger) + metrics, err := churner.NewMetrics(9001, logger) + assert.NoError(t, err) cn, err := churner.NewChurner(config, mockIndexer, operatorTransactorChurner, logger, metrics) assert.NoError(t, err) From e8ffa50c14f03d982d532d7c2989da88752f693d Mon Sep 17 00:00:00 2001 From: Cody Littley <56973212+cody-littley@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:21:09 -0600 Subject: [PATCH 12/15] Size aware cache (#924) Signed-off-by: Cody Littley --- go.mod | 1 + go.sum | 2 + relay/auth/authenticator.go | 21 +-- relay/blob_provider.go | 16 +- relay/blob_provider_test.go | 4 +- relay/cache/cache.go | 25 ++++ .../{cached_accessor.go => cache_accessor.go} | 41 +++--- ...ccessor_test.go => cache_accessor_test.go} | 49 +++++-- relay/cache/fifo-cache.go | 73 +++++++++ relay/cache/fifo_cache_test.go | 138 ++++++++++++++++++ relay/chunk_provider.go | 18 ++- relay/chunk_provider_test.go | 4 +- relay/cmd/config.go | 4 +- relay/cmd/flags/flags.go | 16 +- relay/metadata_provider.go | 11 +- relay/server.go | 10 +- relay/server_test.go | 4 +- 17 files changed, 360 insertions(+), 77 deletions(-) create mode 100644 relay/cache/cache.go rename relay/cache/{cached_accessor.go => cache_accessor.go} (81%) rename relay/cache/{cached_accessor_test.go => cache_accessor_test.go} (89%) create mode 100644 relay/cache/fifo-cache.go create mode 100644 relay/cache/fifo_cache_test.go diff --git a/go.mod b/go.mod index 45e0bbe49a..dc262e397b 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.13.12 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6 github.com/consensys/gnark-crypto v0.12.1 + github.com/emirpasic/gods v1.18.1 github.com/ethereum/go-ethereum v1.14.8 github.com/fxamacker/cbor/v2 v2.5.0 github.com/gin-contrib/logger v0.2.6 diff --git a/go.sum b/go.sum index 4762b276fb..d3b4dde0bf 100644 --- a/go.sum +++ b/go.sum @@ -165,6 +165,8 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.14.8 h1:NgOWvXS+lauK+zFukEvi85UmmsS/OkV0N23UZ1VTIig= diff --git a/relay/auth/authenticator.go b/relay/auth/authenticator.go index 2e89c83d18..c45ee4da47 100644 --- a/relay/auth/authenticator.go +++ b/relay/auth/authenticator.go @@ -6,6 +6,8 @@ import ( "fmt" pb "github.com/Layr-Labs/eigenda/api/grpc/relay" "github.com/Layr-Labs/eigenda/core" + "github.com/emirpasic/gods/queues" + "github.com/emirpasic/gods/queues/linkedlistqueue" lru "github.com/hashicorp/golang-lru/v2" "sync" "time" @@ -38,7 +40,7 @@ type requestAuthenticator struct { authenticatedClients map[string]struct{} // authenticationTimeouts is a list of authentications that have been performed, along with their expiration times. - authenticationTimeouts []*authenticationTimeout + authenticationTimeouts queues.Queue // authenticationTimeoutDuration is the duration for which an auth is valid. // If this is zero, then auth saving is disabled, and each request will be authenticated independently. @@ -67,7 +69,7 @@ func NewRequestAuthenticator( authenticator := &requestAuthenticator{ ics: ics, authenticatedClients: make(map[string]struct{}), - authenticationTimeouts: make([]*authenticationTimeout, 0), + authenticationTimeouts: linkedlistqueue.New(), authenticationTimeoutDuration: authenticationTimeoutDuration, keyCache: keyCache, } @@ -170,7 +172,7 @@ func (a *requestAuthenticator) saveAuthenticationResult(now time.Time, origin st defer a.savedAuthLock.Unlock() a.authenticatedClients[origin] = struct{}{} - a.authenticationTimeouts = append(a.authenticationTimeouts, + a.authenticationTimeouts.Enqueue( &authenticationTimeout{ origin: origin, expiration: now.Add(a.authenticationTimeoutDuration), @@ -195,14 +197,13 @@ func (a *requestAuthenticator) isAuthenticationStillValid(now time.Time, address // removeOldAuthentications removes any authentications that have expired. // This method is not thread safe and should be called with the savedAuthLock held. func (a *requestAuthenticator) removeOldAuthentications(now time.Time) { - index := 0 - for ; index < len(a.authenticationTimeouts); index++ { - if a.authenticationTimeouts[index].expiration.After(now) { + for a.authenticationTimeouts.Size() > 0 { + val, _ := a.authenticationTimeouts.Peek() + next := val.(*authenticationTimeout) + if next.expiration.After(now) { break } - delete(a.authenticatedClients, a.authenticationTimeouts[index].origin) - } - if index > 0 { - a.authenticationTimeouts = a.authenticationTimeouts[index:] + delete(a.authenticatedClients, next.origin) + a.authenticationTimeouts.Dequeue() } } diff --git a/relay/blob_provider.go b/relay/blob_provider.go index 9b9863bfda..70cc310665 100644 --- a/relay/blob_provider.go +++ b/relay/blob_provider.go @@ -20,7 +20,7 @@ type blobProvider struct { blobStore *blobstore.BlobStore // blobCache is an LRU cache of blobs. - blobCache cache.CachedAccessor[v2.BlobKey, []byte] + blobCache cache.CacheAccessor[v2.BlobKey, []byte] // fetchTimeout is the maximum time to wait for a blob fetch operation to complete. fetchTimeout time.Duration @@ -31,7 +31,7 @@ func newBlobProvider( ctx context.Context, logger logging.Logger, blobStore *blobstore.BlobStore, - blobCacheSize int, + blobCacheSize uint64, maxIOConcurrency int, fetchTimeout time.Duration) (*blobProvider, error) { @@ -42,15 +42,23 @@ func newBlobProvider( fetchTimeout: fetchTimeout, } - c, err := cache.NewCachedAccessor[v2.BlobKey, []byte](blobCacheSize, maxIOConcurrency, server.fetchBlob) + c := cache.NewFIFOCache[v2.BlobKey, []byte](blobCacheSize, computeBlobCacheWeight) + + cacheAccessor, err := cache.NewCacheAccessor[v2.BlobKey, []byte](c, maxIOConcurrency, server.fetchBlob) if err != nil { return nil, fmt.Errorf("error creating blob cache: %w", err) } - server.blobCache = c + server.blobCache = cacheAccessor return server, nil } +// computeChunkCacheWeight computes the 'weight' of the blob for the cache. The weight of a blob +// is equal to its size, in bytes. +func computeBlobCacheWeight(_ v2.BlobKey, value []byte) uint64 { + return uint64(len(value)) +} + // GetBlob retrieves a blob from the blob store. func (s *blobProvider) GetBlob(ctx context.Context, blobKey v2.BlobKey) ([]byte, error) { data, err := s.blobCache.Get(ctx, blobKey) diff --git a/relay/blob_provider_test.go b/relay/blob_provider_test.go index 9309461c65..22368a5d5b 100644 --- a/relay/blob_provider_test.go +++ b/relay/blob_provider_test.go @@ -39,7 +39,7 @@ func TestReadWrite(t *testing.T) { context.Background(), logger, blobStore, - 10, + 1024*1024*32, 32, 10*time.Second) require.NoError(t, err) @@ -76,7 +76,7 @@ func TestNonExistentBlob(t *testing.T) { context.Background(), logger, blobStore, - 10, + 1024*1024*32, 32, 10*time.Second) require.NoError(t, err) diff --git a/relay/cache/cache.go b/relay/cache/cache.go new file mode 100644 index 0000000000..1d3c7f1a04 --- /dev/null +++ b/relay/cache/cache.go @@ -0,0 +1,25 @@ +package cache + +// WeightCalculator is a function that calculates the weight of a key-value pair in a Cache. +// By default, the weight of a key-value pair is 1. Cache capacity is always specified in terms of +// the weight of the key-value pairs it can hold, rather than the number of key-value pairs. +type WeightCalculator[K comparable, V any] func(key K, value V) uint64 + +// Cache is an interface for a generic cache. +// +// Unless otherwise noted, Cache implementations are not required to be thread safe. +type Cache[K comparable, V any] interface { + // Get returns the value associated with the key, and a boolean indicating whether the key was found in the cache. + Get(key K) (V, bool) + + // Put adds a key-value pair to the cache. After this operation, values may be dropped if the total weight + // exceeds the configured maximum weight. Will ignore the new value if it exceeds the maximum weight + // of the cache in and of itself. + Put(key K, value V) + + // Size returns the number of key-value pairs in the cache. + Size() int + + // Weight returns the total weight of the key-value pairs in the cache. + Weight() uint64 +} diff --git a/relay/cache/cached_accessor.go b/relay/cache/cache_accessor.go similarity index 81% rename from relay/cache/cached_accessor.go rename to relay/cache/cache_accessor.go index d131229082..a6389538b4 100644 --- a/relay/cache/cached_accessor.go +++ b/relay/cache/cache_accessor.go @@ -2,21 +2,20 @@ package cache import ( "context" - lru "github.com/hashicorp/golang-lru/v2" "golang.org/x/sync/semaphore" "sync" ) -// CachedAccessor is an interface for accessing a resource that is cached. It assumes that cache misses +// CacheAccessor is an interface for accessing a resource that is cached. It assumes that cache misses // are expensive, and prevents multiple concurrent cache misses for the same key. -type CachedAccessor[K comparable, V any] interface { +type CacheAccessor[K comparable, V any] interface { // Get returns the value for the given key. If the value is not in the cache, it will be fetched using the Accessor. // If the context is cancelled, the function may abort early. If multiple goroutines request the same key, // cancellation of one request will not affect the others. Get(ctx context.Context, key K) (V, error) } -// Accessor is function capable of fetching a value from a resource. Used by CachedAccessor when there is a cache miss. +// Accessor is function capable of fetching a value from a resource. Used by CacheAccessor when there is a cache miss. type Accessor[K comparable, V any] func(key K) (V, error) // accessResult is a struct that holds the result of an Accessor call. @@ -29,23 +28,24 @@ type accessResult[V any] struct { err error } -var _ CachedAccessor[string, string] = &cachedAccessor[string, string]{} +var _ CacheAccessor[string, string] = &cacheAccessor[string, string]{} // Future work: the cache used in this implementation is suboptimal when storing items that have a large // variance in size. The current implementation uses a fixed size cache, which requires the cached to be // sized to the largest item that will be stored. This cache should be replaced with an implementation // whose size can be specified by memory footprint in bytes. -// cachedAccessor is an implementation of CachedAccessor. -type cachedAccessor[K comparable, V any] struct { +// cacheAccessor is an implementation of CacheAccessor. +type cacheAccessor[K comparable, V any] struct { + // lookupsInProgress has an entry for each key that is currently being looked up via the accessor. The value // is written into the channel when it is eventually fetched. If a key is requested more than once while a // lookup in progress, the second (and following) requests will wait for the result of the first lookup // to be written into the channel. lookupsInProgress map[K]*accessResult[V] - // cache is the LRU cache used to store values fetched by the accessor. - cache *lru.Cache[K, V] + // cache is the underlying cache that this wrapper manages. + cache Cache[K, V] // concurrencyLimiter is a channel used to limit the number of concurrent lookups that can be in progress. concurrencyLimiter chan struct{} @@ -57,20 +57,15 @@ type cachedAccessor[K comparable, V any] struct { accessor Accessor[K, V] } -// NewCachedAccessor creates a new CachedAccessor. The cacheSize parameter specifies the maximum number of items +// NewCacheAccessor creates a new CacheAccessor. The cacheSize parameter specifies the maximum number of items // that can be stored in the cache. The concurrencyLimit parameter specifies the maximum number of concurrent // lookups that can be in progress at any given time. If a greater number of lookups are requested, the excess // lookups will block until a lookup completes. If concurrencyLimit is zero, then no limits are imposed. The accessor // parameter is the function used to fetch values that are not in the cache. -func NewCachedAccessor[K comparable, V any]( - cacheSize int, +func NewCacheAccessor[K comparable, V any]( + cache Cache[K, V], concurrencyLimit int, - accessor Accessor[K, V]) (CachedAccessor[K, V], error) { - - cache, err := lru.New[K, V](cacheSize) - if err != nil { - return nil, err - } + accessor Accessor[K, V]) (CacheAccessor[K, V], error) { lookupsInProgress := make(map[K]*accessResult[V]) @@ -79,7 +74,7 @@ func NewCachedAccessor[K comparable, V any]( concurrencyLimiter = make(chan struct{}, concurrencyLimit) } - return &cachedAccessor[K, V]{ + return &cacheAccessor[K, V]{ cache: cache, concurrencyLimiter: concurrencyLimiter, accessor: accessor, @@ -95,7 +90,7 @@ func newAccessResult[V any]() *accessResult[V] { return result } -func (c *cachedAccessor[K, V]) Get(ctx context.Context, key K) (V, error) { +func (c *cacheAccessor[K, V]) Get(ctx context.Context, key K) (V, error) { c.cacheLock.Lock() // first, attempt to get the value from the cache @@ -126,7 +121,7 @@ func (c *cachedAccessor[K, V]) Get(ctx context.Context, key K) (V, error) { // waitForResult waits for the result of a lookup that was initiated by another requester and returns it // when it becomes is available. This method will return quickly if the provided context is cancelled. // Doing so does not disrupt the other requesters that are also waiting for this result. -func (c *cachedAccessor[K, V]) waitForResult(ctx context.Context, result *accessResult[V]) (V, error) { +func (c *cacheAccessor[K, V]) waitForResult(ctx context.Context, result *accessResult[V]) (V, error) { err := result.sem.Acquire(ctx, 1) if err != nil { var zeroValue V @@ -139,7 +134,7 @@ func (c *cachedAccessor[K, V]) waitForResult(ctx context.Context, result *access // fetchResult fetches the value for the given key and returns it. If the context is cancelled before the value // is fetched, the function will return early. If the fetch is successful, the value will be added to the cache. -func (c *cachedAccessor[K, V]) fetchResult(ctx context.Context, key K, result *accessResult[V]) (V, error) { +func (c *cacheAccessor[K, V]) fetchResult(ctx context.Context, key K, result *accessResult[V]) (V, error) { // Perform the work in a background goroutine. This allows us to return early if the context is cancelled // without disrupting the fetch operation that other requesters may be waiting for. @@ -159,7 +154,7 @@ func (c *cachedAccessor[K, V]) fetchResult(ctx context.Context, key K, result *a // Update the cache if the fetch was successful. if err == nil { - c.cache.Add(key, value) + c.cache.Put(key, value) } // Provide the result to all other goroutines that may be waiting for it. diff --git a/relay/cache/cached_accessor_test.go b/relay/cache/cache_accessor_test.go similarity index 89% rename from relay/cache/cached_accessor_test.go rename to relay/cache/cache_accessor_test.go index 9048e3d88a..0f2ac501d4 100644 --- a/relay/cache/cached_accessor_test.go +++ b/relay/cache/cache_accessor_test.go @@ -32,8 +32,11 @@ func TestRandomOperationsSingleThread(t *testing.T) { return &str, nil } cacheSize := rand.Intn(dataSize) + 1 + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) - ca, err := NewCachedAccessor(cacheSize, 0, accessor) + ca, err := NewCacheAccessor[int, *string](c, 0, accessor) require.NoError(t, err) for i := 0; i < dataSize; i++ { @@ -80,7 +83,11 @@ func TestCacheMisses(t *testing.T) { return &str, nil } - ca, err := NewCachedAccessor(cacheSize, 0, accessor) + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) + + ca, err := NewCacheAccessor[int, *string](c, 0, accessor) require.NoError(t, err) // Get the first cacheSize keys. This should fill the cache. @@ -143,7 +150,11 @@ func ParallelAccessTest(t *testing.T, sleepEnabled bool) { } cacheSize := rand.Intn(dataSize) + 1 - ca, err := NewCachedAccessor(cacheSize, 0, accessor) + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) + + ca, err := NewCacheAccessor[int, *string](c, 0, accessor) require.NoError(t, err) // Lock the accessor. This will cause all cache misses to block. @@ -184,7 +195,7 @@ func ParallelAccessTest(t *testing.T, sleepEnabled bool) { require.Equal(t, uint64(1), cacheMissCount.Load()) // The internal lookupsInProgress map should no longer contain the key. - require.Equal(t, 0, len(ca.(*cachedAccessor[int, *string]).lookupsInProgress)) + require.Equal(t, 0, len(ca.(*cacheAccessor[int, *string]).lookupsInProgress)) } func TestParallelAccess(t *testing.T) { @@ -212,7 +223,11 @@ func TestParallelAccessWithError(t *testing.T) { } cacheSize := 100 - ca, err := NewCachedAccessor(cacheSize, 0, accessor) + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) + + ca, err := NewCacheAccessor[int, *string](c, 0, accessor) require.NoError(t, err) // Lock the accessor. This will cause all cache misses to block. @@ -253,7 +268,7 @@ func TestParallelAccessWithError(t *testing.T) { require.Equal(t, count+1, cacheMissCount.Load()) // The internal lookupsInProgress map should no longer contain the key. - require.Equal(t, 0, len(ca.(*cachedAccessor[int, *string]).lookupsInProgress)) + require.Equal(t, 0, len(ca.(*cacheAccessor[int, *string]).lookupsInProgress)) } func TestConcurrencyLimiter(t *testing.T) { @@ -284,7 +299,11 @@ func TestConcurrencyLimiter(t *testing.T) { } cacheSize := 100 - ca, err := NewCachedAccessor(cacheSize, maxConcurrency, accessor) + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) + + ca, err := NewCacheAccessor[int, *string](c, maxConcurrency, accessor) require.NoError(t, err) wg := sync.WaitGroup{} @@ -338,7 +357,11 @@ func TestOriginalRequesterTimesOut(t *testing.T) { } cacheSize := rand.Intn(dataSize) + 1 - ca, err := NewCachedAccessor(cacheSize, 0, accessor) + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) + + ca, err := NewCacheAccessor[int, *string](c, 0, accessor) require.NoError(t, err) // Lock the accessor. This will cause all cache misses to block. @@ -397,7 +420,7 @@ func TestOriginalRequesterTimesOut(t *testing.T) { require.Equal(t, uint64(1), cacheMissCount.Load()) // The internal lookupsInProgress map should no longer contain the key. - require.Equal(t, 0, len(ca.(*cachedAccessor[int, *string]).lookupsInProgress)) + require.Equal(t, 0, len(ca.(*cacheAccessor[int, *string]).lookupsInProgress)) } func TestSecondaryRequesterTimesOut(t *testing.T) { @@ -426,7 +449,11 @@ func TestSecondaryRequesterTimesOut(t *testing.T) { } cacheSize := rand.Intn(dataSize) + 1 - ca, err := NewCachedAccessor(cacheSize, 0, accessor) + c := NewFIFOCache[int, *string](uint64(cacheSize), func(key int, value *string) uint64 { + return 1 + }) + + ca, err := NewCacheAccessor[int, *string](c, 0, accessor) require.NoError(t, err) // Lock the accessor. This will cause all cache misses to block. @@ -489,5 +516,5 @@ func TestSecondaryRequesterTimesOut(t *testing.T) { require.Equal(t, uint64(1), cacheMissCount.Load()) // The internal lookupsInProgress map should no longer contain the key. - require.Equal(t, 0, len(ca.(*cachedAccessor[int, *string]).lookupsInProgress)) + require.Equal(t, 0, len(ca.(*cacheAccessor[int, *string]).lookupsInProgress)) } diff --git a/relay/cache/fifo-cache.go b/relay/cache/fifo-cache.go new file mode 100644 index 0000000000..1c2e7c6abd --- /dev/null +++ b/relay/cache/fifo-cache.go @@ -0,0 +1,73 @@ +package cache + +import ( + "github.com/emirpasic/gods/queues" + "github.com/emirpasic/gods/queues/linkedlistqueue" +) + +var _ Cache[string, string] = &FIFOCache[string, string]{} + +// FIFOCache is a cache that evicts the least recently added item when the cache is full. Useful for situations +// where time of addition is a better predictor of future access than time of most recent access. +type FIFOCache[K comparable, V any] struct { + weightCalculator WeightCalculator[K, V] + + currentWeight uint64 + maxWeight uint64 + data map[K]V + expirationQueue queues.Queue +} + +// NewFIFOCache creates a new FIFOCache. +func NewFIFOCache[K comparable, V any](maxWeight uint64, calculator WeightCalculator[K, V]) *FIFOCache[K, V] { + return &FIFOCache[K, V]{ + maxWeight: maxWeight, + data: make(map[K]V), + weightCalculator: calculator, + expirationQueue: linkedlistqueue.New(), + } +} + +func (f *FIFOCache[K, V]) Get(key K) (V, bool) { + val, ok := f.data[key] + return val, ok +} + +func (f *FIFOCache[K, V]) Put(key K, value V) { + weight := f.weightCalculator(key, value) + if weight > f.maxWeight { + // this item won't fit in the cache no matter what we evict + return + } + + old, ok := f.data[key] + f.currentWeight += weight + f.data[key] = value + if ok { + oldWeight := f.weightCalculator(key, old) + f.currentWeight -= oldWeight + } else { + f.expirationQueue.Enqueue(key) + } + + if f.currentWeight < f.maxWeight { + // no need to evict anything + return + } + + for f.currentWeight > f.maxWeight { + val, _ := f.expirationQueue.Dequeue() + keyToEvict := val.(K) + weightToEvict := f.weightCalculator(keyToEvict, f.data[keyToEvict]) + delete(f.data, keyToEvict) + f.currentWeight -= weightToEvict + } +} + +func (f *FIFOCache[K, V]) Size() int { + return len(f.data) +} + +func (f *FIFOCache[K, V]) Weight() uint64 { + return f.currentWeight +} diff --git a/relay/cache/fifo_cache_test.go b/relay/cache/fifo_cache_test.go new file mode 100644 index 0000000000..da4de5ad1f --- /dev/null +++ b/relay/cache/fifo_cache_test.go @@ -0,0 +1,138 @@ +package cache + +import ( + tu "github.com/Layr-Labs/eigenda/common/testutils" + "github.com/stretchr/testify/require" + "golang.org/x/exp/rand" + "testing" +) + +func TestExpirationOrder(t *testing.T) { + tu.InitializeRandom() + + maxWeight := uint64(10 + rand.Intn(10)) + c := NewFIFOCache[int, int](maxWeight, func(key int, value int) uint64 { + return 1 + }) + + require.Equal(t, uint64(0), c.Weight()) + require.Equal(t, 0, c.Size()) + + expectedValues := make(map[int]int) + + // Fill up the cache. Everything should have weight 1. + for i := 1; i <= int(maxWeight); i++ { + + value := rand.Int() + expectedValues[i] = value + + // The value shouldn't be present yet + v, ok := c.Get(i) + require.False(t, ok) + require.Equal(t, 0, v) + + c.Put(i, value) + + require.Equal(t, uint64(i), c.Weight()) + require.Equal(t, i, c.Size()) + } + + // Verify that all expected values are present. + for k, v := range expectedValues { + value, ok := c.Get(k) + require.True(t, ok) + require.Equal(t, v, value) + } + + // Push the old values out of the queue one at a time. + for i := 1; i <= int(maxWeight); i++ { + value := rand.Int() + expectedValues[-i] = value + delete(expectedValues, i) + + // The value shouldn't be present yet + v, ok := c.Get(-i) + require.False(t, ok) + require.Equal(t, 0, v) + + c.Put(-i, value) + + require.Equal(t, maxWeight, c.Weight()) + require.Equal(t, int(maxWeight), c.Size()) + + // verify that the purged value is specifically not present + _, ok = c.Get(i) + require.False(t, ok) + + // verify that only the expected values have been purged. Has the added benefit of randomly + // reading all the values in the cache, which for a FIFO cache should not influence the order + // that we purge values. + for kk, vv := range expectedValues { + value, ok = c.Get(kk) + require.True(t, ok) + require.Equal(t, vv, value) + } + } +} + +func TestWeightedValues(t *testing.T) { + tu.InitializeRandom() + + maxWeight := uint64(100 + rand.Intn(100)) + + // For this test, weight is simply the key. + weightCalculator := func(key int, value int) uint64 { + return uint64(key) + } + + c := NewFIFOCache[int, int](maxWeight, weightCalculator) + + expectedValues := make(map[int]int) + + require.Equal(t, uint64(0), c.Weight()) + require.Equal(t, 0, c.Size()) + + highestUndeletedKey := 0 + expectedWeight := uint64(0) + for nextKey := 0; nextKey <= int(maxWeight); nextKey++ { + value := rand.Int() + c.Put(nextKey, value) + expectedValues[nextKey] = value + expectedWeight += uint64(nextKey) + + // simulate the expected removal + for expectedWeight > maxWeight { + delete(expectedValues, highestUndeletedKey) + expectedWeight -= uint64(highestUndeletedKey) + highestUndeletedKey++ + } + + require.Equal(t, expectedWeight, c.Weight()) + require.Equal(t, len(expectedValues), c.Size()) + + // Update a random existing key. Shouldn't affect the weight or removal order. + for k := range expectedValues { + value = rand.Int() + c.Put(k, value) + expectedValues[k] = value + break + } + + // verify that all expected values are present + for k, v := range expectedValues { + var ok bool + value, ok = c.Get(k) + require.True(t, ok) + require.Equal(t, v, value) + } + } + + // Attempting to insert a value that exceeds the max weight should have no effect. + c.Put(int(maxWeight)+1, rand.Int()) + + for k, v := range expectedValues { + value, ok := c.Get(k) + require.True(t, ok) + require.Equal(t, v, value) + } +} diff --git a/relay/chunk_provider.go b/relay/chunk_provider.go index 48ece7c3cd..5bc2926732 100644 --- a/relay/chunk_provider.go +++ b/relay/chunk_provider.go @@ -20,7 +20,7 @@ type chunkProvider struct { // metadataCache is an LRU cache of blob metadata. Each relay is authorized to serve data assigned to one or more // relay IDs. Blobs that do not belong to one of the relay IDs assigned to this server will not be in the cache. - frameCache cache.CachedAccessor[blobKeyWithMetadata, []*encoding.Frame] + frameCache cache.CacheAccessor[blobKeyWithMetadata, []*encoding.Frame] // chunkReader is used to read chunks from the chunk store. chunkReader chunkstore.ChunkReader @@ -47,7 +47,7 @@ func newChunkProvider( ctx context.Context, logger logging.Logger, chunkReader chunkstore.ChunkReader, - cacheSize int, + cacheSize uint64, maxIOConcurrency int, proofFetchTimeout time.Duration, coefficientFetchTimeout time.Duration) (*chunkProvider, error) { @@ -60,14 +60,16 @@ func newChunkProvider( coefficientFetchTimeout: coefficientFetchTimeout, } - c, err := cache.NewCachedAccessor[blobKeyWithMetadata, []*encoding.Frame]( - cacheSize, + c := cache.NewFIFOCache[blobKeyWithMetadata, []*encoding.Frame](cacheSize, computeFramesCacheWeight) + + cacheAccessor, err := cache.NewCacheAccessor[blobKeyWithMetadata, []*encoding.Frame]( + c, maxIOConcurrency, server.fetchFrames) if err != nil { return nil, err } - server.frameCache = c + server.frameCache = cacheAccessor return server, nil } @@ -75,6 +77,12 @@ func newChunkProvider( // frameMap is a map of blob keys to frames. type frameMap map[v2.BlobKey][]*encoding.Frame +// computeFramesCacheWeight computes the 'weight' of the frames for the cache. The weight of a list of frames +// is equal to the size required to store the data, in bytes. +func computeFramesCacheWeight(key blobKeyWithMetadata, frames []*encoding.Frame) uint64 { + return uint64(len(frames)) * uint64(key.metadata.chunkSizeBytes) +} + // GetFrames retrieves the frames for a blob. func (s *chunkProvider) GetFrames(ctx context.Context, mMap metadataMap) (frameMap, error) { diff --git a/relay/chunk_provider_test.go b/relay/chunk_provider_test.go index 8615ad7d23..06ec215b80 100644 --- a/relay/chunk_provider_test.go +++ b/relay/chunk_provider_test.go @@ -49,7 +49,7 @@ func TestFetchingIndividualBlobs(t *testing.T) { context.Background(), logger, chunkReader, - 10, + 1024*1024*32, 32, 10*time.Second, 10*time.Second) @@ -136,7 +136,7 @@ func TestFetchingBatchedBlobs(t *testing.T) { context.Background(), logger, chunkReader, - 10, + 1024*1024*32, 32, 10*time.Second, 10*time.Second) diff --git a/relay/cmd/config.go b/relay/cmd/config.go index 154c4c2bd2..ff1513d172 100644 --- a/relay/cmd/config.go +++ b/relay/cmd/config.go @@ -60,9 +60,9 @@ func NewConfig(ctx *cli.Context) (Config, error) { MaxGRPCMessageSize: ctx.Int(flags.MaxGRPCMessageSizeFlag.Name), MetadataCacheSize: ctx.Int(flags.MetadataCacheSizeFlag.Name), MetadataMaxConcurrency: ctx.Int(flags.MetadataMaxConcurrencyFlag.Name), - BlobCacheSize: ctx.Int(flags.BlobCacheSizeFlag.Name), + BlobCacheBytes: ctx.Uint64(flags.BlobCacheBytes.Name), BlobMaxConcurrency: ctx.Int(flags.BlobMaxConcurrencyFlag.Name), - ChunkCacheSize: ctx.Int(flags.ChunkCacheSizeFlag.Name), + ChunkCacheSize: ctx.Uint64(flags.ChunkCacheSizeFlag.Name), ChunkMaxConcurrency: ctx.Int(flags.ChunkMaxConcurrencyFlag.Name), RateLimits: limiter.Config{ MaxGetBlobOpsPerSecond: ctx.Float64(flags.MaxGetBlobOpsPerSecondFlag.Name), diff --git a/relay/cmd/flags/flags.go b/relay/cmd/flags/flags.go index baed1fbcf4..0bb24ce2ae 100644 --- a/relay/cmd/flags/flags.go +++ b/relay/cmd/flags/flags.go @@ -60,12 +60,12 @@ var ( EnvVar: common.PrefixEnvVar(envVarPrefix, "METADATA_MAX_CONCURRENCY"), Value: 32, } - BlobCacheSizeFlag = cli.IntFlag{ - Name: common.PrefixFlag(FlagPrefix, "blob-cache-size"), - Usage: "Max number of items in the blob cache", + BlobCacheBytes = cli.Uint64Flag{ + Name: common.PrefixFlag(FlagPrefix, "blob-cache-bytes"), + Usage: "The size of the blob cache, in bytes.", Required: false, EnvVar: common.PrefixEnvVar(envVarPrefix, "BLOB_CACHE_SIZE"), - Value: 32, + Value: 1024 * 1024 * 1024, } BlobMaxConcurrencyFlag = cli.IntFlag{ Name: common.PrefixFlag(FlagPrefix, "blob-max-concurrency"), @@ -74,12 +74,12 @@ var ( EnvVar: common.PrefixEnvVar(envVarPrefix, "BLOB_MAX_CONCURRENCY"), Value: 32, } - ChunkCacheSizeFlag = cli.IntFlag{ + ChunkCacheSizeFlag = cli.Int64Flag{ Name: common.PrefixFlag(FlagPrefix, "chunk-cache-size"), - Usage: "Max number of items in the chunk cache", + Usage: "Size of the chunk cache, in bytes.", Required: false, EnvVar: common.PrefixEnvVar(envVarPrefix, "CHUNK_CACHE_SIZE"), - Value: 32, + Value: 4 * 1024 * 1024 * 1024, } ChunkMaxConcurrencyFlag = cli.IntFlag{ Name: common.PrefixFlag(FlagPrefix, "chunk-max-concurrency"), @@ -297,7 +297,7 @@ var optionalFlags = []cli.Flag{ MaxGRPCMessageSizeFlag, MetadataCacheSizeFlag, MetadataMaxConcurrencyFlag, - BlobCacheSizeFlag, + BlobCacheBytes, BlobMaxConcurrencyFlag, ChunkCacheSizeFlag, ChunkMaxConcurrencyFlag, diff --git a/relay/metadata_provider.go b/relay/metadata_provider.go index 8f3f43ed86..e1f188bb9e 100644 --- a/relay/metadata_provider.go +++ b/relay/metadata_provider.go @@ -36,7 +36,7 @@ type metadataProvider struct { // metadataCache is an LRU cache of blob metadata. Blobs that do not belong to one of the relay shards // assigned to this server will not be in the cache. - metadataCache cache.CachedAccessor[v2.BlobKey, *blobMetadata] + metadataCache cache.CacheAccessor[v2.BlobKey, *blobMetadata] // relayIDSet is the set of relay IDs assigned to this relay. This relay will refuse to serve metadata for blobs // that are not assigned to one of these IDs. @@ -74,8 +74,13 @@ func newMetadataProvider( } server.blobParamsMap.Store(blobParamsMap) - metadataCache, err := cache.NewCachedAccessor[v2.BlobKey, *blobMetadata]( - metadataCacheSize, + c := cache.NewFIFOCache[v2.BlobKey, *blobMetadata](uint64(metadataCacheSize), + func(key v2.BlobKey, value *blobMetadata) uint64 { + return uint64(1) + }) + + metadataCache, err := cache.NewCacheAccessor[v2.BlobKey, *blobMetadata]( + c, maxIOConcurrency, server.fetchMetadata) if err != nil { diff --git a/relay/server.go b/relay/server.go index 540b46b0b0..eb00709e9f 100644 --- a/relay/server.go +++ b/relay/server.go @@ -78,14 +78,14 @@ type Config struct { // goroutines. MetadataMaxConcurrency int - // BlobCacheSize is the maximum number of items in the blob cache. - BlobCacheSize int + // BlobCacheBytes is the maximum size of the blob cache, in bytes. + BlobCacheBytes uint64 // BlobMaxConcurrency puts a limit on the maximum number of concurrent blob fetches actively running on goroutines. BlobMaxConcurrency int - // ChunkCacheSize is the maximum number of items in the chunk cache. - ChunkCacheSize int + // ChunkCacheSize is the maximum size of the chunk cache, in bytes. + ChunkCacheSize uint64 // ChunkMaxConcurrency is the size of the work pool for fetching chunks. Note that this does not // impact concurrency utilized by the s3 client to upload/download fragmented files. @@ -153,7 +153,7 @@ func NewServer( ctx, logger, blobStore, - config.BlobCacheSize, + config.BlobCacheBytes, config.BlobMaxConcurrency, config.Timeouts.InternalGetBlobTimeout) if err != nil { diff --git a/relay/server_test.go b/relay/server_test.go index 3e16c624c3..58b8893714 100644 --- a/relay/server_test.go +++ b/relay/server_test.go @@ -25,9 +25,9 @@ func defaultConfig() *Config { MaxGRPCMessageSize: 1024 * 1024 * 300, MetadataCacheSize: 1024 * 1024, MetadataMaxConcurrency: 32, - BlobCacheSize: 32, + BlobCacheBytes: 1024 * 1024, BlobMaxConcurrency: 32, - ChunkCacheSize: 32, + ChunkCacheSize: 1024 * 1024, ChunkMaxConcurrency: 32, MaxKeysPerGetChunksRequest: 1024, RateLimits: limiter.Config{ From 035f844dbde020302eda9011093cadf092df3b74 Mon Sep 17 00:00:00 2001 From: anupsv Date: Thu, 28 Nov 2024 02:02:45 +0530 Subject: [PATCH 13/15] Security.md creation (#905) --- SECURITY.md | 20 ++++++++++++++++++ ...DA_Offchain_Security_Assessment_Report.pdf | Bin 0 -> 520068 bytes 2 files changed, 20 insertions(+) create mode 100644 SECURITY.md create mode 100644 docs/audits/Sigma_Prime_EigenDA_Offchain_Security_Assessment_Report.pdf diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..97a6ab3f6a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,20 @@ +# Security Policy + +## Version Information + +Please see [Releases](https://github.com/Layr-Labs/eigenda/releases) and we recommend using the [most recently released version](https://github.com/Layr-Labs/eigenda/releases/latest). + +## Audit reports + +Audit reports are published in the `docs` folder: https://github.com/Layr-Labs/eigenda/master/docs/audits + +| Date | Report Link | +| ------- | ----------- | +| 202404 | [pdf](https://github.com/Layr-Labs/eigenda/blob/security-doc/docs/audits/Sigma_Prime_EigenDA_Offchain_Security_Assessment_Report.pdf) | + +## Reporting a Vulnerability + +**Please do not file a public ticket** mentioning the vulnerability. + +Please report security vulnerabilities to security@eigenlabs.org with the all the relavent details included in the email. + diff --git a/docs/audits/Sigma_Prime_EigenDA_Offchain_Security_Assessment_Report.pdf b/docs/audits/Sigma_Prime_EigenDA_Offchain_Security_Assessment_Report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6a5a166e02ce9b640ca09c18ba8c3db3c762fd50 GIT binary patch literal 520068 zcmeFYWpG?gmnJBd#Y`46Gcz+YGc%Q#43cFrGcz+&$zo<^iVE4TgiFyIp^fPnfVmCl9&WNGXpy;`Q&WhA}lu%6Op5d4J;oYETf#cgC)R)27U>JbHdIGmnp|xT|B)PnsIdCNQEmQY&#bR`X|roDQEH8o|1SYvNKtJ8%*_vR5ANwH`hv6 zTP@~P0*{B<4qFmBvF39jVk$#lcW@RF zUf{6i4rc!i)sNU8jd1>pX4Jf#%!wGa6isZ*O#!fss%|ELzc~_)F7_Wv`gs1W!3@i& zq$aM#@S!zx1!H@2A}U5JM|*QdTWc3vMu54ey~Up=;~!mmGOAiz+8ZmmSbvmT+grN+ zOIqI8^+V}$j+TxhcE+Z*3{GYi)c>t#C1Xo-1vh(>51aV6!K5859L20n0YuDyBvyfC z6cKUsB+_O2NU*W8GH^06adNT~F|%+ou(NYBv9svIGD^BQx;cGh{Zn7X+||*|#njxD z=#LSKdjcd?0Ur|nO&K%&{Sg)ZGn}dM$MeJb1O)yKiob=P97N1qf4dU+2>))z?A-sS z=9|u{#sngwFG^%=WmaivV`FV(lOLTvqCSXGtn`Ttp$nFXOi4>{N{F~aOSrRJu8Ta2 z7WorsoeM(#e^u9C5&n}WG5_(d4@CY)Uc~r6*XchXel-7sBHIU6Tpzgo2U0A53RM2p z71RCFq$|m!QGVPzhqen*3LsGmiI{-Wp}@r#3m?pZX*v0wJdg3Qw3R~A$D3mk5S($m za5Q%Y=pUvW({%`*5R%{5+(xarc)eUUMQyyW^S`}i(Vklx`c1q&oF@=;*1f-9KV2Kz znR&mQ4j*1V4|Ebd#+-C!z3ktf4tohKltyLg1XQjOZV==NXby93A5R^*&U&#Pc_!LT zNcxX^6(1LAXZp+!9Qy;8StqWnwz-L2Yu)O-6ax+xOv%&k$65$hup2|NG@4%H)7m?o zu*VWJgDWl+qXhMqGMC@&Xx}^h&C}TV%L49F?8Y6V(q@KT=TPfj2)W;%&yk)N>hd2K zk6RW@P)%=`348=4GgDdT-i#<)G^R+o*K8XL_EWRG^tVoET;`0;{1dw&c9-^1*RH1F zZmr9{=cL&96t0O)s4+56$}rtX1T zPs`G1MfY}5KhwE#CZ!MAQnG%2W+~p#FBm<;VT~9R=*w=OG|(#(rm-SNI&+sE z%E3B%Sy;Bhc??+B&ZQnfXX-IPPEW~>IZbw9pJ7|Jh&^N(JE4G0DFD(9Cz!eWtVQj+ zvW@Nf*JicYmTG7&{yG5fw`-ix&{AhkF&8Cu4Ih!pYG$7~u~3`|r@)n(n_s-d4!`RI zWj3{Gwr56=4xh4knrZyWr-`x_HnK8jxO6QLUbRwx8Wbd=-5fGqm}b$ARr$35SN~{< z)4f^F(RPSaxF=y(g(Ba?1~BZWZ}=U!dW+ym#J+5g?t+BSRK?b@?vo@?P2)G*kmq5) zUF*|B@+C9F)LP=MJV6trxOE1H`wo$_E6OhKvqL`jdrlJbPbQ#n z`4*F^n7Ald5u1sgSGv2-Z_x&2)22jBI(ZGtG><@XfU3tEsOouTMD7(*0Bql}X{ zm%bk^amiLAtRya{)hNUlHT01#1#M_$mq^-Q8h5tS<)Gs*=JbzF3{X$@v0AJ$V8yAq(64v>raBn)YyJ4KKNr+|Qf7Yk1L9`G`G+tvK(^)(aq`5o1ksV2B8kP-VcOj- zYESznDp6dsyrSw?!@Pb>Pl#4v?<8R4-h#}iwy}s!fkyV6Id#BHtVh!0&8d#9>jR}or zWBts5_?pO2CFJqSyXpnF zR?b8r)!>*N>(vFQOfWOx#RA+=;t)<@3Z=Us8og%5x>;R(+D0}&mL^N&VB}&cheYPf zIP{k9(x#o#_YB;dI7S-POkUU``zXcZlCfWU>AJwx)a8C5n)y*rIg*$Y=XBnR0>7gHd?BV3kHSbh&9y=nzw z0|)%d)O3SYiS5_zkT8^nO1Bl4whPEJBK(j+D9+cR3%Tc0XKdw2{}AQD>kassz=Flb z6qA^i#d}F+TMkYL0@+-?+4+vtT3>162p(qUb?1>?tqT=&WDy1^i4?grK8LHpXqO>_ zMbcenHs4YeIBs2?63;K`r`$V*RH}6{GgwjTYN_So1rH{NgC$ztFcO>brK@4)`S}WT zYhq3qD)W9-8LQRz_sg~_L_dqv)zeGOMTelU%T-8ZlBd)}KMk60T!?EE zE?uSF0_MXDCHhWH_M*~PE%BS=G&`(+&bPhG_x4`*JtaTMm6;fudC5J zR?)F$XJNCj+&Pi&8Qajk)ZqzJJLO$94KI(4TiBem>5B0N5LO;idF`jIf(i6q2DsnYC3B9s>i_O9OL3`VX=|~BT z3Nd}2o$f*~8~q(xPgFeuO6t97KHPUorpJo1ouL3G1}nWUR1OY0YCWxI=-{E7S$8UG zB0}?(XGqNu1}NN^!rF5JczW@3j$OC}y?YiIhnrNZG+z5S3!o+{D0?bdYGEpz9i-iO z{gTYhYxDj)zG~kEf7c4%4jPnNEPWNeRcadCDkm;fUXO`lpfY3U#|>#(7J0gR3al*A zhF}|P3#+cVA1ot8R6YA0 z|L<7;1Z#_eeye~C@sfhTj__T3nyn`I@^UW5FRA=bB(d*pSJf1D+V)18GCR(ALKd(pNoD|gI2ZT;xvySOS1<&n3X_6& z%D9Q)NG=}9&?2#b<4>ila8CE-fhVP@${r#`bvSzyLM5&`U+=m{B<~4Uz@mx=6)Z!w zULG%Sj6u>JwxAZvSDlSlm4?8Vl4|f=d;6xg2xk@v`i#iZ^($PZT_jYjf;cZHMA%J+ zJ{R_r!W|-^Irk3rPpZId^-5^1R*;wa(@1}GDsmelg*GG4Ak%50g=__R1J4+nN3wM( zyUa)BS+=T}Q7}f!UXc#5q@ev51M3Z&@74uc&D_x*jPmLZa~)+a%GxEIrN~e9avT0< z^`=3Q>Ek~eJJPo0=VaYKUA4EBVlyZ>x0YhxO)r@ywV6C}h29ASV#tqG%hIU;eEZsp zc^Y~fe)=B3KX`@Ync~Ux>WPM6Xyhtkk`ZNwXaJWLQ^LtVS?7>Ps&3mp#;_I*6S3-P~t2NttLe(5XBX# zgQn1})lVF%p#@#4II=}y@sN!bJ5P{}k(EjLot@P()*#&X*vs5wgQKV_qU7|cvi z+=Spv**-Y8ATxi&0=Th~#yRq-@%z?#;YxWZy8F31-;SvM0>SK{^5 ztyssBlHh5Gi*^hm9u8{Y>y#yvpRl4B|NMp8jTC!HP<3@^f-ii*((JM= zXW*3FX(wpT9u+)n0NZb~!*Gm;jTQS?YSJ&}79!E>od4^Ag52p&szYL`JrKEhgxGNk zTJ$2Q>d37&O^P4oQo{uYhge;0CI-DLan5{#5QF@Hqv>o(->m2>qKMh|)ZEXNBUd1L zJF0x`;%7it06`5Gi&m}68X|Y&tL$-BIEgd?2wYPL#M6iK4n{Qe9U= z=`@A;rkzuRDA4R%9gxt6WrQ9k#pe$06Dx@vIeFo&iRTwvrzakMgF)vf-~0F-FaJqV zVO4r}O=x}9JSkT`<9b5CLOmJs6PYZ!?C)CX5zfcWg|1>2pyv|O_B78-oF?Jo#RM(A zA+Y%MRBSMUQPc6aD~2f0pvCuC}qSC`$AP6 zN+|a7i#Yh~_H{nZ7-h%j{^7B7DXQ$y1zw9O9*1jN7JgGICSsni9VKQCr8pfi;>!6N z8qr^%DNVtkC`n#GPS1ypiKLEXoBGF_uRITgamnw`b;~|E0jQuodPGzX^+x#_%SDyfci+VVxQ3 z8LF3chH`~8qWmCOu289GoE}C*ZPV?x7M4niv}y(kH>bFdV9XC;+s{~JH?2CeD_iVV z=4h<7RM!+X5o7iTD49L^`1SH08?ng^{^)?9Jh@V&kb zM(m(U9LWPHl}Xr9?U>xglZCX{)je{kyP+|z@bCzv~8HMJu1*<@cTNv}WNGXv2TcL6Sz; z==G98`xSxB+q76J@>!W0r5MkDpM;5YE<;@#X(JQ%V9aJBN{M^1 zOyDR0{#-p{!2g9{KWresz1i$gp3P^wFA5JZg6$72}DMz7Ll zhqK%YKRqH;PL`WY5BbC`5{Dp9fm%;pg0Yc*l{k`BKMBzwtt$Tsw^Pa1#=k!#PT873 z3#eq+Qfa`;cyO!lp`O4dT;4t)KfS+}OYmOvmxJ7C#@s%nrniprlx*E{`^2TCsYd*G z;N3_6WjCgn!4bmcwTY*MruSX%`=vUVsPPYdx5t76@{=z|L+4Rm@;0r+ikmbAXL7zi zs{m!?r&|j(XmE>s`64%K(D+QOBD&T@RnmYJo0J-VjE1K?#M24KsJ(+3;xFjx%;dd6 zzE^j($@8#aJFwR+6k)w_C+~VE!r-UzJPk79=HthC3=&1;466^(_xWn_$x@fOW+l_s z`wpc9v$B{{y-~6@(IZvh&!?Lbt{zc652)XpYup+JPTNYR)BrQz84omI3M>3=WgW7c z5qZt01iH)UPs<3eU{_|$8-2u3V~g|S+!Nn#LB$PSPs5wZ=E&V|X7XP9t_nJKnzBA= zIw-ed2a^q=0@lk$e0sx6k6+{qY-bW0TVG_z282?XkN1Wm>E5Fs<6FCa8>JiNuAAP` z?#j=^0jCn3dN;5An$MrNG{P*3($=LjyS;wV#=>5G+eLV6@x4*e5U<%q(Wuz>eLDc# zoOkCW+$*b*W#Cvx))>WuKwGSk4$%iUYKd{BrU|T^gh~X#}xlujQA1&l5s(4H55; zPnlsBJ;~3sq|>R8?28fZyt%18K0fu_3Z_XHsQ=efY&N!!bLIbhip~6Sj{P_Mk597y z^*-oSTi$V-1G!^g^FS>cx@@ZnFxr|%B)*Jp+Z62JGbvL~UryKZ_T$^J4`MXUHC2-{w4q(0XyYPTuzT{K%BcfcFTg24hmXjj>KZEV z7M{35l7$2^e_pse4#VX*@du%XOMIbHqc~j_N6%Cuo`P3}RR+DB)JR6nAK)7LY4GwI zO2lUr+DHN8)-c9~dEk8FJkB`oM{l>2WMwCnjs{C6Cou{G^9?Yqp?wX3(}UAmX{*05 zAq}C*ikIWw5m{EmoER=sfb7GaaHos?V-%h>{uk=*9ucp0K7-M_r1qFW?A)|4071ES z3FJFead_OEu#BwxnJ@G$35H=p>LM!~?s(bP&=V#*I`f+b4G|P9#fwr1K~LLLPIBX%hKC}e z@OC$r^80TONjY)g&dJiWKC`VLeOc`q9y5i}pxOHc@*?hN&THxFn2!*{L|p_5s`j)v zsL&_fda#;-EEzQmAN}8m!l+^=E8A$9qe3J<2`^%PJYt}Mq97P|u&>#tTUy&eqC;37 z0S|c5w%ieS#%+*0%wdSv@E{mxm*Gf}7-*1xMzg967^~oBF)}Ip{aWHc@h1!;t4za> z3HK_LbcEsjC5eX*K^d`51G~=_c%LktA7);+eChWkJ(frrN?yO3(SjMG7f||KG$h-Kl{d#!zAgqCH7!$tvoJqYxQW1RHFc|y&0fVgFDO8A! zD-WfXX!ev4G)|g>&x!>UM*e2lI$6KPwZZx1fs?McVqoIXDKn@bFHC<==kwQCo!PY7 zBcQB}E zI{x}uQKb4B7ZakP<+4%avWRXYBWk?*kr9k-QCC&#_PXnkEh$M{exIcucRdS(&B+{Mqvli)-c z?sr_{;MbD-+`-qCuz0!%JyndE>;X$mF96z*bx`YXkA(lakOL7cfEJ+Tdla0FlbGKLFk9zTcAKvo<=rRBN)N^Wj?mQ6}v63Fo)8Xd3!F zt=uRtqZ)%lmc*IYFm>W!U-UZ05`42()eq5cA{amOu#`c68PjhO6h)4p`i)5{eHb1>?`G7_rOgpSZLS zADXuA<}YI8r2AVknI^Z8ryW_<;X|ovYKUIbp}_>EP3fDP&0tQqZ|2N77?cnv3U$KN zj-pCI&bB!o5GHA+rYuy_M^{7c{0a~;e%kL1w=<#80@Ia}ZKT)0g;es7;TW&jX)SbvT5afU>U6s} z$tFN!PZ4U#DpQs@2m`Z@y=QK+PtXn|TR~sRzD91RzY9An6$hAlaqw)1=_IB`)m|Zx zhyQ%CwaGVChM8M&gB!^kE>6v@V%^PThdcJ%Dw!7_>siJ2JAL6bABEA$x?Aw~ERgjiaRFSS zVU=#lXQ@YR?5kDDXwHbFp{=G{<*Sg-Jlg_{sqEyq*w)Vv`f*K<-(f@4ph-T-{7{B* z(4Myn!;bjszA!GogD4i-37T?1A;_+A62t@4Q)Ojgu z-+-FE=bC(#irR)}Ybm;mfmw;1uFQtk1kmGJ*5{Cck*mXjUgyKCo8*y@=c1!}B+N?L zU4hL5pw^UXS-R2YR>fiaAT(%H`$9GVQIY~~4gy1Nw53)Y#rIZ{E|9ZPCB%|pj3mIy zG#fsb3k7;CrntC6qO5y5SHmJwS5x(7o48nZpU>o{#b6o#o)oZpfQzzU-G1@uW@->) z7Q)LVVc=!GzD4PspI-ba%n~oS6U($`XaS0BH<{ghwElF>)^mR1kQdkGol17*m>H@? zk$@~B+b%X6K24fwYJgz$D4}TPKMlD3I#sg89&2RHv9V|T2^$@`yaJ3xU(@?Hd-;!c z@ZUfr!PSt1ClyQ)&aKMfttV{{DB@Qki)EpbaFDn$kSniH*EO}5J|7xi+!`O3%UT~2 zv^0>E%5}QvU(Ry}Eh!<@I3yG<&f|~U)3`Jd>gCoD5#UN#8j68X)NKD4=ZH zK@C7H^-M+Re&C|alpi6qvTE}ukmdAcg_n(#)*-?Cl2GIua&eYD=|kAFS~Ait)01`( zn+Yjk{zZvPbN?uWR86kwl^iQ2dod?v0$)5PFVzj`eQ#!B9|OeL+tYPb>k~^Snx6jL z#=|~*3>BXVmBd_d&^{MfDKY!O$w=IBdVG~zgAr6Uk5G~xTCj3SzPxisV`r!se%kiM z+s={{d`#BXud-~@oY{2DGHsk4a9IKMFkMDz)Ra44w#eL6;T4oWU#LYcBOr-3xj!5v z3#t==NiwQ=BrEv+tLn^3VZNi>io#ei<2;@?zndX^SWO>7g;*m~oKOV9z!fbHolp~1 zYm|}sPmsuQmYh%qBT;deHX+RBdZ9WAGODV08?WDin{X29p{0>O{Y!&ZOh8XgY9pv> z6U=OG+3GDa!w?R^)R>z>$#w>@Txgd|v*&$5I|rb0p3mQNNd=kYC))@NP1&)M=%dt7 z;z!{*M)eq6EBHh&W#NUXjeqQHtQeo1ZIJZmv->@c#y-^8HgbkTP(aBt!&YmIA{IIx zk_g|JV0GR0u+4vpql7vrZoZ(4ZT7PlL&$ytYLOaXyl!tzys9u!yF`0Cbp z0WFSOAJI--xCi@O_G>PRuMJV~2wcKs!5#T`g1b{EQL-aUtmkIOQp|`1*eEVHdS!O- z)34WcS(rQdu=Fx=fDc4$jANIvl3sXvL7NIT2k3*oYiRMDE_o;hnu9>`H@M#{uZ$<8 zDpMe!`kE%xeU7;H=iD^%RcUyr4_$bYMWt~I2U^L5+VF>>Su@~se4)--DpZ8D>yI%M3Z)t?h`e|X`=&-Rud_X^TBMijd#0Hg2reW zCMfBYhsjyP>w>FqWVnQ{7s;E9wT2%4 z#kG04k8{z5Cp5(EZ#5C=9?z%ijjEhc>mZ}0H?+=E6 zvZr^@6-bb_|N1S>@vl_S|2aAB|6#(RgrnmJ|L}j6cF4)`mkReUv_lRiE(T_HW+o

A&jg@4)|Q-^2M22lD?W*^q;Y`vWxYe@E*N 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 BeeM@qD)vL;Y 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�>d5NWan08lT^#l0YIZR>=Ue&c| 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ổN6phYIBo=4! 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 literal 0 HcmV?d00001 From 4ec69dc0cb88182bb6e6fb8054e8db4d6086200d Mon Sep 17 00:00:00 2001 From: Jian Xiao <99709935+jianoaix@users.noreply.github.com> Date: Wed, 27 Nov 2024 15:10:13 -0800 Subject: [PATCH 14/15] Add latency metric for dispersal/retrieval with blob size breakdown (#939) --- disperser/apiserver/server.go | 6 ++++++ disperser/metrics.go | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 831b0e6350..b0163a9423 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -269,6 +269,8 @@ func (s *DispersalServer) disperseBlob(ctx context.Context, blob *core.Blob, aut })) defer timer.ObserveDuration() + dispersalStart := time.Now() + securityParams := blob.RequestHeader.SecurityParams securityParamsStrings := make([]string, len(securityParams)) for i, sp := range securityParams { @@ -319,6 +321,7 @@ func (s *DispersalServer) disperseBlob(ctx context.Context, blob *core.Blob, aut for _, param := range securityParams { s.metrics.HandleSuccessfulRequest(fmt.Sprintf("%d", param.QuorumID), blobSize, apiMethodName) } + s.metrics.BlobLatency.WithLabelValues(apiMethodName, dispcommon.BlobSizeBucket(blobSize)).Set(float64(time.Since(dispersalStart).Milliseconds())) return &pb.DisperseBlobReply{ Result: pb.BlobStatus_PROCESSING, @@ -701,6 +704,8 @@ func (s *DispersalServer) RetrieveBlob(ctx context.Context, req *pb.RetrieveBlob })) defer timer.ObserveDuration() + retrievalStart := time.Now() + origin, err := common.GetClientAddress(ctx, s.rateConfig.ClientIPHeader, 2, true) if err != nil { s.metrics.HandleInvalidArgRpcRequest("RetrieveBlob") @@ -807,6 +812,7 @@ func (s *DispersalServer) RetrieveBlob(ctx context.Context, req *pb.RetrieveBlob } s.metrics.HandleSuccessfulRpcRequest("RetrieveBlob") s.metrics.HandleSuccessfulRequest("", len(data), "RetrieveBlob") + s.metrics.BlobLatency.WithLabelValues("RetrieveBlob", dispcommon.BlobSizeBucket(len(data))).Set(float64(time.Since(retrievalStart).Milliseconds())) s.logger.Debug("fetched blob content", "batchHeaderHash", req.BatchHeaderHash, "blobIndex", req.BlobIndex, "data size (bytes)", len(data), "duration", time.Since(stageTimer).String()) diff --git a/disperser/metrics.go b/disperser/metrics.go index 6a762344d9..43a5aef999 100644 --- a/disperser/metrics.go +++ b/disperser/metrics.go @@ -24,6 +24,7 @@ type Metrics struct { NumBlobRequests *prometheus.CounterVec NumRpcRequests *prometheus.CounterVec BlobSize *prometheus.GaugeVec + BlobLatency *prometheus.GaugeVec Latency *prometheus.SummaryVec httpPort string @@ -78,6 +79,15 @@ func NewMetrics(reg *prometheus.Registry, httpPort string, logger logging.Logger }, []string{"method"}, ), + BlobLatency: promauto.With(reg).NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: namespace, + Name: "blob_latency_ms", + Help: "blob dispersal or retrieval latency by size", + }, + []string{"method", "size_bucket"}, + ), + registry: reg, httpPort: httpPort, logger: logger.With("component", "DisperserMetrics"), From f3a9c527bba6b5c153218391429f79959a6b5fe4 Mon Sep 17 00:00:00 2001 From: Ian Shim <100327837+ian-shim@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:19:24 -0800 Subject: [PATCH 15/15] [v2][node] Construct relay client from relay address from chain (#931) --- api/clients/mock/relay_client.go | 9 ++++ api/clients/relay_client.go | 10 +++- common/read_only_map.go | 12 ++++- core/chainio.go | 6 +++ core/eth/reader.go | 54 ++++++++++++++++++++++ core/mock/writer.go | 19 ++++++++ core/v2/types.go | 2 +- disperser/controller/dispatcher.go | 1 + node/grpc/server_v2_test.go | 5 +- node/node.go | 68 +++++++++++++++++++++++---- node/node_test.go | 20 ++++---- node/node_v2.go | 5 +- node/node_v2_test.go | 74 +++++++++++++++++++++++++++++- node/store_v2.go | 4 +- node/store_v2_test.go | 3 +- 15 files changed, 262 insertions(+), 30 deletions(-) diff --git a/api/clients/mock/relay_client.go b/api/clients/mock/relay_client.go index b268a430fe..e97e1e5406 100644 --- a/api/clients/mock/relay_client.go +++ b/api/clients/mock/relay_client.go @@ -39,6 +39,15 @@ func (c *MockRelayClient) GetChunksByIndex(ctx context.Context, relayKey corev2. return args.Get(0).([][]byte), args.Error(1) } +func (c *MockRelayClient) GetSockets() map[corev2.RelayKey]string { + args := c.Called() + if args.Get(0) == nil { + return nil + } + + return args.Get(0).(map[corev2.RelayKey]string) +} + func (c *MockRelayClient) Close() error { args := c.Called() return args.Error(0) diff --git a/api/clients/relay_client.go b/api/clients/relay_client.go index 5ed6a0ead7..f43d747ab8 100644 --- a/api/clients/relay_client.go +++ b/api/clients/relay_client.go @@ -39,6 +39,8 @@ type RelayClient interface { // The returned slice has the same length and ordering as the input slice, and the i-th element is the bundle for the i-th request. // Each bundle is a sequence of frames in raw form (i.e., serialized core.Bundle bytearray). GetChunksByIndex(ctx context.Context, relayKey corev2.RelayKey, requests []*ChunkRequestByIndex) ([][]byte, error) + // GetSockets returns the relay sockets + GetSockets() map[corev2.RelayKey]string Close() error } @@ -65,6 +67,8 @@ func NewRelayClient(config *RelayClientConfig, logger logging.Logger) (*relayCli return nil, fmt.Errorf("invalid config: %v", config) } + logger.Info("creating relay client", "config", config) + initOnce := sync.Map{} for key := range config.Sockets { initOnce.Store(key, &sync.Once{}) @@ -73,7 +77,7 @@ func NewRelayClient(config *RelayClientConfig, logger logging.Logger) (*relayCli config: config, initOnce: &initOnce, - logger: logger, + logger: logger.With("component", "RelayClient"), }, nil } @@ -196,6 +200,10 @@ func (c *relayClient) initOnceGrpcConnection(key corev2.RelayKey) error { return initErr } +func (c *relayClient) GetSockets() map[corev2.RelayKey]string { + return c.config.Sockets +} + func (c *relayClient) Close() error { var errList *multierror.Error c.conns.Range(func(k, v interface{}) bool { diff --git a/common/read_only_map.go b/common/read_only_map.go index 3e6e097054..4469c46231 100644 --- a/common/read_only_map.go +++ b/common/read_only_map.go @@ -1,10 +1,14 @@ package common -type ReadOnlyMap[K comparable, V any] struct { +import ( + "maps" +) + +type ReadOnlyMap[K comparable, V comparable] struct { data map[K]V } -func NewReadOnlyMap[K comparable, V any](data map[K]V) *ReadOnlyMap[K, V] { +func NewReadOnlyMap[K comparable, V comparable](data map[K]V) *ReadOnlyMap[K, V] { return &ReadOnlyMap[K, V]{data: data} } @@ -24,3 +28,7 @@ func (m *ReadOnlyMap[K, V]) Keys() []K { func (m *ReadOnlyMap[K, V]) Len() int { return len(m.data) } + +func (m *ReadOnlyMap[K, V]) Equal(data map[K]V) bool { + return maps.Equal(m.data, data) +} diff --git a/core/chainio.go b/core/chainio.go index cb76848efa..e0f5e7db9c 100644 --- a/core/chainio.go +++ b/core/chainio.go @@ -120,6 +120,12 @@ type Reader interface { // GetOnDemandPaymentByAccount returns on-demand payment of an account GetOnDemandPaymentByAccount(ctx context.Context, blockNumber uint32, accountID string) (OnDemandPayment, error) + + // GetRelayURL returns the relay URL address for the given key. + GetRelayURL(ctx context.Context, key uint16) (string, error) + + // GetRelayURLs returns the relay URL addresses for all relays. + GetRelayURLs(ctx context.Context) (map[uint16]string, error) } type Writer interface { diff --git a/core/eth/reader.go b/core/eth/reader.go index bf5aa5bb0d..b224354681 100644 --- a/core/eth/reader.go +++ b/core/eth/reader.go @@ -12,6 +12,7 @@ import ( delegationmgr "github.com/Layr-Labs/eigenda/contracts/bindings/DelegationManager" eigendasrvmg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager" ejectionmg "github.com/Layr-Labs/eigenda/contracts/bindings/EjectionManager" + relayreg "github.com/Layr-Labs/eigenda/contracts/bindings/IEigenDARelayRegistry" indexreg "github.com/Layr-Labs/eigenda/contracts/bindings/IIndexRegistry" opstateretriever "github.com/Layr-Labs/eigenda/contracts/bindings/OperatorStateRetriever" regcoordinator "github.com/Layr-Labs/eigenda/contracts/bindings/RegistryCoordinator" @@ -39,6 +40,7 @@ type ContractBindings struct { EjectionManager *ejectionmg.ContractEjectionManager AVSDirectory *avsdir.ContractAVSDirectory SocketRegistry *socketreg.ContractSocketRegistry + RelayRegistry *relayreg.ContractIEigenDARelayRegistry } type Reader struct { @@ -178,6 +180,18 @@ func (t *Reader) updateContractBindings(blsOperatorStateRetrieverAddr, eigenDASe return err } + var contractRelayRegistry *relayreg.ContractIEigenDARelayRegistry + relayRegistryAddr, err := contractEigenDAServiceManager.EigenDARelayRegistry(&bind.CallOpts{}) + if err != nil { + t.logger.Error("Failed to fetch IEigenDARelayRegistry contract", "err", err) + // TODO(ian-shim): return err when the contract is deployed + } else { + contractRelayRegistry, err = relayreg.NewContractIEigenDARelayRegistry(relayRegistryAddr, t.ethClient) + if err != nil { + t.logger.Error("Failed to fetch IEigenDARelayRegistry contract", "err", err) + } + } + t.bindings = &ContractBindings{ ServiceManagerAddr: eigenDAServiceManagerAddr, RegCoordinatorAddr: registryCoordinatorAddr, @@ -191,6 +205,7 @@ func (t *Reader) updateContractBindings(blsOperatorStateRetrieverAddr, eigenDASe StakeRegistry: contractStakeRegistry, EigenDAServiceManager: contractEigenDAServiceManager, DelegationManager: contractDelegationManager, + RelayRegistry: contractRelayRegistry, } return nil } @@ -689,3 +704,42 @@ func (t *Reader) GetOperatorSocket(ctx context.Context, operatorId core.Operator } return socket, nil } + +func (t *Reader) GetRelayURL(ctx context.Context, key uint16) (string, error) { + if t.bindings.RelayRegistry == nil { + return "", errors.New("relay registry not deployed") + } + + return t.bindings.RelayRegistry.GetRelayURL(&bind.CallOpts{ + Context: ctx, + }, uint32(key)) +} + +func (t *Reader) GetRelayURLs(ctx context.Context) (map[uint16]string, error) { + if t.bindings.RelayRegistry == nil { + return nil, errors.New("relay registry not deployed") + } + + res := make(map[uint16]string) + relayKey := uint16(0) + for { + url, err := t.bindings.RelayRegistry.GetRelayURL(&bind.CallOpts{ + Context: ctx, + }, uint32(relayKey)) + + if err != nil && strings.Contains(err.Error(), "execution reverted") { + break + } else if err != nil { + return nil, err + } + + res[relayKey] = url + relayKey++ + } + + if len(res) == 0 { + return nil, errors.New("no relay URLs found") + } + + return res, nil +} diff --git a/core/mock/writer.go b/core/mock/writer.go index c70db8fc0b..bf729a5556 100644 --- a/core/mock/writer.go +++ b/core/mock/writer.go @@ -209,6 +209,9 @@ func (t *MockWriter) GetVersionedBlobParams(ctx context.Context, blobVersion uin func (t *MockWriter) GetAllVersionedBlobParams(ctx context.Context) (map[uint8]*core.BlobVersionParameters, error) { args := t.Called() result := args.Get(0) + if result == nil { + return nil, args.Error(1) + } return result.(map[uint8]*core.BlobVersionParameters), args.Error(1) } @@ -247,3 +250,19 @@ func (t *MockWriter) GetOperatorSocket(ctx context.Context, operatorID core.Oper result := args.Get(0) return result.(string), args.Error(1) } + +func (t *MockWriter) GetRelayURL(ctx context.Context, key uint16) (string, error) { + args := t.Called() + result := args.Get(0) + return result.(string), args.Error(1) +} + +func (t *MockWriter) GetRelayURLs(ctx context.Context) (map[uint16]string, error) { + args := t.Called() + result := args.Get(0) + if result == nil { + return nil, args.Error(1) + } + + return result.(map[uint16]string), args.Error(1) +} diff --git a/core/v2/types.go b/core/v2/types.go index 796ab06b51..fedf3fcce6 100644 --- a/core/v2/types.go +++ b/core/v2/types.go @@ -161,7 +161,7 @@ func (b *BlobHeader) GetEncodingParams(blobParams *core.BlobVersionParameters) ( }, nil } -type RelayKey uint16 +type RelayKey = uint16 type BlobCertificate struct { BlobHeader *BlobHeader diff --git a/disperser/controller/dispatcher.go b/disperser/controller/dispatcher.go index c5b58ca91b..cc7b7da403 100644 --- a/disperser/controller/dispatcher.go +++ b/disperser/controller/dispatcher.go @@ -107,6 +107,7 @@ func (d *Dispatcher) Start(ctx context.Context) error { if err != nil { d.logger.Error("failed to handle signatures", "err", err) } + // TODO(ian-shim): handle errors and mark failed }() } } diff --git a/node/grpc/server_v2_test.go b/node/grpc/server_v2_test.go index 249bd6bb77..11ef1fce3e 100644 --- a/node/grpc/server_v2_test.go +++ b/node/grpc/server_v2_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "os" + "sync/atomic" "testing" "github.com/Layr-Labs/eigenda/api/clients" @@ -68,6 +69,8 @@ func newTestComponents(t *testing.T, config *node.Config) *testComponents { s := nodemock.NewMockStoreV2() relay := clientsmock.NewRelayClient() + var atomicRelayClient atomic.Value + atomicRelayClient.Store(relay) node := &node.Node{ Config: config, Logger: logger, @@ -76,7 +79,7 @@ func newTestComponents(t *testing.T, config *node.Config) *testComponents { StoreV2: s, ChainState: chainState, ValidatorV2: val, - RelayClient: relay, + RelayClient: atomicRelayClient, } node.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParamsMap)) server := grpc.NewServerV2(config, node, logger, ratelimiter) diff --git a/node/node.go b/node/node.go index 07055e55cb..62845f1345 100644 --- a/node/node.go +++ b/node/node.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "maps" "math" "math/big" "net/http" @@ -78,7 +79,7 @@ type Node struct { ChainID *big.Int BLSSigner blssignerV1.SignerClient - RelayClient clients.RelayClient + RelayClient atomic.Value mu sync.Mutex CurrentSocket string @@ -223,8 +224,6 @@ func NewNode( "quorumIDs", fmt.Sprint(config.QuorumIDList), "registerNodeAtStart", config.RegisterNodeAtStart, "pubIPCheckInterval", config.PubIPCheckInterval, "eigenDAServiceManagerAddr", config.EigenDAServiceManagerAddr, "blockStaleMeasure", blockStaleMeasure, "storeDurationBlocks", storeDurationBlocks, "enableGnarkBundleEncoding", config.EnableGnarkBundleEncoding) - var relayClient clients.RelayClient - n := &Node{ Config: config, Logger: nodeLogger, @@ -239,7 +238,6 @@ func NewNode( PubIPProvider: pubIPProvider, OperatorSocketsFilterer: socketsFilterer, ChainID: chainID, - RelayClient: relayClient, BLSSigner: blsClient, } @@ -262,7 +260,8 @@ func NewNode( if err != nil { return nil, fmt.Errorf("failed to create new tablestore: %w", err) } - storeV2 = NewLevelDBStoreV2(dbV2, logger) + timeToExpire := (blockStaleMeasure + storeDurationBlocks) * 12 // 12s per block + storeV2 = NewLevelDBStoreV2(dbV2, logger, time.Duration(timeToExpire)*time.Second) blobParams, err := tx.GetAllVersionedBlobParams(context.Background()) if err != nil { @@ -270,7 +269,22 @@ func NewNode( } blobVersionParams = corev2.NewBlobVersionParameterMap(blobParams) - // TODO(ian-shim): Create a new relay client with relay addresses onchain + var relayClient clients.RelayClient + relayURLs, err := tx.GetRelayURLs(context.Background()) + if err != nil { + return nil, fmt.Errorf("failed to get relay URLs: %w", err) + } + + relayClient, err = clients.NewRelayClient(&clients.RelayClientConfig{ + Sockets: relayURLs, + UseSecureGrpcFlag: config.UseSecureGrpc, + }, logger) + + if err != nil { + return nil, fmt.Errorf("failed to create new relay client: %w", err) + } + + n.RelayClient.Store(relayClient) } n.StoreV2 = storeV2 @@ -395,6 +409,10 @@ func (n *Node) expireLoop() { } } +// RefreshOnchainState refreshes the onchain state of the node. +// It fetches the latest blob parameters from the chain and updates the BlobVersionParams. +// It runs periodically based on the OnchainStateRefreshInterval. +// WARNING: this method is not thread-safe and should not be called concurrently. func (n *Node) RefreshOnchainState(ctx context.Context) error { if !n.Config.EnableV2 || n.Config.OnchainStateRefreshInterval <= 0 { return nil @@ -406,13 +424,47 @@ func (n *Node) RefreshOnchainState(ctx context.Context) error { select { case <-ticker.C: n.Logger.Info("Refreshing onchain state") + existingBlobParams := n.BlobVersionParams.Load() blobParams, err := n.Transactor.GetAllVersionedBlobParams(ctx) - if err != nil { + if err == nil { + if existingBlobParams == nil || !existingBlobParams.Equal(blobParams) { + n.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParams)) + } + } else { n.Logger.Error("error fetching blob params", "err", err) + } + + existingRelayClient, ok := n.RelayClient.Load().(clients.RelayClient) + if !ok { + n.Logger.Error("error fetching relay client") + continue + } + + existingURLs := map[v2.RelayKey]string{} + if existingRelayClient != nil { + existingURLs = existingRelayClient.GetSockets() + } + relayURLs, err := n.Transactor.GetRelayURLs(ctx) + if err != nil { + n.Logger.Error("error fetching relay URLs", "err", err) + continue + } + + if maps.Equal(existingURLs, relayURLs) { + n.Logger.Info("No change in relay URLs") + continue + } + + relayClient, err := clients.NewRelayClient(&clients.RelayClientConfig{ + Sockets: relayURLs, + UseSecureGrpcFlag: n.Config.UseSecureGrpc, + }, n.Logger) + if err != nil { + n.Logger.Error("error creating relay client", "err", err) continue } - n.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParams)) + n.RelayClient.Store(clients.RelayClient(relayClient)) case <-ctx.Done(): return ctx.Err() } diff --git a/node/node_test.go b/node/node_test.go index e66a287b93..8000b2e2d4 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -82,23 +82,21 @@ func newComponents(t *testing.T) *components { panic("failed to create a new levelDB store") } defer os.Remove(dbPath) - relayClient := clientsmock.NewRelayClient() n := &node.Node{ - Config: config, - Logger: logger, - KeyPair: keyPair, - Metrics: nil, - Store: store, - ChainState: chainState, - Validator: mockVal, - Transactor: tx, - RelayClient: relayClient, + Config: config, + Logger: logger, + KeyPair: keyPair, + Metrics: nil, + Store: store, + ChainState: chainState, + Validator: mockVal, + Transactor: tx, } n.BlobVersionParams.Store(v2.NewBlobVersionParameterMap(blobParamsMap)) return &components{ node: n, tx: tx, - relayClient: relayClient, + relayClient: clientsmock.NewRelayClient(), } } diff --git a/node/node_v2.go b/node/node_v2.go index c37c4c4647..af9e9cf6ef 100644 --- a/node/node_v2.go +++ b/node/node_v2.go @@ -34,7 +34,8 @@ type RawBundles struct { } func (n *Node) DownloadBundles(ctx context.Context, batch *corev2.Batch, operatorState *core.OperatorState) ([]*corev2.BlobShard, []*RawBundles, error) { - if n.RelayClient == nil { + relayClient, ok := n.RelayClient.Load().(clients.RelayClient) + if !ok || relayClient == nil { return nil, nil, fmt.Errorf("relay client is not set") } @@ -102,7 +103,7 @@ func (n *Node) DownloadBundles(ctx context.Context, batch *corev2.Batch, operato relayKey := relayKey req := requests[relayKey] pool.Submit(func() { - bundles, err := n.RelayClient.GetChunksByRange(ctx, relayKey, req.chunkRequests) + bundles, err := relayClient.GetChunksByRange(ctx, relayKey, req.chunkRequests) if err != nil { n.Logger.Errorf("failed to get chunks from relays: %v", err) bundleChan <- response{ diff --git a/node/node_v2_test.go b/node/node_v2_test.go index cc56550439..14e1b0259b 100644 --- a/node/node_v2_test.go +++ b/node/node_v2_test.go @@ -11,12 +11,14 @@ import ( v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/encoding" nodemock "github.com/Layr-Labs/eigenda/node/mock" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestDownloadBundles(t *testing.T) { c := newComponents(t) + c.node.RelayClient.Store(c.relayClient) ctx := context.Background() blobKeys, batch, bundles := nodemock.MockBatch(t) blobCerts := batch.BlobCertificates @@ -89,6 +91,7 @@ func TestDownloadBundles(t *testing.T) { func TestDownloadBundlesFail(t *testing.T) { c := newComponents(t) + c.node.RelayClient.Store(c.relayClient) ctx := context.Background() blobKeys, batch, bundles := nodemock.MockBatch(t) @@ -123,9 +126,10 @@ func TestDownloadBundlesFail(t *testing.T) { require.Nil(t, rawBundles) } -func TestRefreshOnchainState(t *testing.T) { +func TestRefreshOnchainStateFailure(t *testing.T) { c := newComponents(t) c.node.Config.EnableV2 = true + c.node.RelayClient.Store(c.relayClient) c.node.Config.OnchainStateRefreshInterval = time.Millisecond ctx := context.Background() bp, ok := c.node.BlobVersionParams.Load().Get(0) @@ -133,9 +137,67 @@ func TestRefreshOnchainState(t *testing.T) { require.Equal(t, bp, blobParams) _, ok = c.node.BlobVersionParams.Load().Get(1) require.False(t, ok) + relayClient, ok := c.node.RelayClient.Load().(clients.RelayClient) + require.True(t, ok) + require.NotNil(t, relayClient) + + // Both updates fail + newCtx, cancel := context.WithTimeout(ctx, c.node.Config.OnchainStateRefreshInterval*2) + defer cancel() + + c.tx.On("GetAllVersionedBlobParams", mock.Anything).Return(nil, assert.AnError) + c.relayClient.On("GetSockets").Return(nil) + c.tx.On("GetRelayURLs", mock.Anything).Return(nil, assert.AnError) + err := c.node.RefreshOnchainState(newCtx) + require.ErrorIs(t, err, context.DeadlineExceeded) + bp, ok = c.node.BlobVersionParams.Load().Get(0) + require.True(t, ok) + require.Equal(t, bp, blobParams) + _, ok = c.node.BlobVersionParams.Load().Get(1) + require.False(t, ok) + newRelayClient := c.node.RelayClient.Load().(clients.RelayClient) + require.Same(t, relayClient, newRelayClient) + + // Same relay URLs shouldn't trigger update + newCtx1, cancel1 := context.WithTimeout(ctx, c.node.Config.OnchainStateRefreshInterval*2) + defer cancel1() + + c.tx.On("GetAllVersionedBlobParams", mock.Anything).Return(nil, assert.AnError) + relayURLs := map[v2.RelayKey]string{ + 0: "http://localhost:8080", + } + c.relayClient.On("GetSockets").Return(relayURLs).Once() + c.tx.On("GetRelayURLs", mock.Anything).Return(relayURLs, nil) + err = c.node.RefreshOnchainState(newCtx1) + require.ErrorIs(t, err, context.DeadlineExceeded) + newRelayClient = c.node.RelayClient.Load().(clients.RelayClient) + require.Same(t, relayClient, newRelayClient) +} + +func TestRefreshOnchainStateSuccess(t *testing.T) { + c := newComponents(t) + c.node.Config.EnableV2 = true + c.node.Config.OnchainStateRefreshInterval = time.Millisecond + relayURLs := map[v2.RelayKey]string{ + 0: "http://localhost:8080", + } + relayClient, err := clients.NewRelayClient(&clients.RelayClientConfig{ + Sockets: relayURLs, + }, c.node.Logger) + require.NoError(t, err) + // set up non-mock client + c.node.RelayClient.Store(relayClient) + ctx := context.Background() + bp, ok := c.node.BlobVersionParams.Load().Get(0) + require.True(t, ok) + require.Equal(t, bp, blobParams) + _, ok = c.node.BlobVersionParams.Load().Get(1) + require.False(t, ok) + // Blob params updated successfully newCtx, cancel := context.WithTimeout(ctx, c.node.Config.OnchainStateRefreshInterval*2) defer cancel() + blobParams2 := &core.BlobVersionParameters{ NumChunks: 111, CodingRate: 1, @@ -145,7 +207,12 @@ func TestRefreshOnchainState(t *testing.T) { 0: blobParams, 1: blobParams2, }, nil) - err := c.node.RefreshOnchainState(newCtx) + newRelayURLs := map[v2.RelayKey]string{ + 1: "http://localhost:8081", + 2: "http://localhost:8082", + } + c.tx.On("GetRelayURLs", mock.Anything).Return(newRelayURLs, nil) + err = c.node.RefreshOnchainState(newCtx) require.ErrorIs(t, err, context.DeadlineExceeded) bp, ok = c.node.BlobVersionParams.Load().Get(0) require.True(t, ok) @@ -153,6 +220,9 @@ func TestRefreshOnchainState(t *testing.T) { bp, ok = c.node.BlobVersionParams.Load().Get(1) require.True(t, ok) require.Equal(t, bp, blobParams2) + newRelayClient := c.node.RelayClient.Load().(clients.RelayClient) + require.NotSame(t, relayClient, newRelayClient) + require.Equal(t, newRelayURLs, newRelayClient.GetSockets()) } func bundleEqual(t *testing.T, expected, actual core.Bundle) { diff --git a/node/store_v2.go b/node/store_v2.go index 62da00f54d..7b435adebf 100644 --- a/node/store_v2.go +++ b/node/store_v2.go @@ -33,10 +33,12 @@ type storeV2 struct { var _ StoreV2 = &storeV2{} -func NewLevelDBStoreV2(db kvstore.TableStore, logger logging.Logger) *storeV2 { +func NewLevelDBStoreV2(db kvstore.TableStore, logger logging.Logger, ttl time.Duration) *storeV2 { return &storeV2{ db: db, logger: logger, + + ttl: ttl, } } diff --git a/node/store_v2_test.go b/node/store_v2_test.go index 2a78c80800..50fc74d4de 100644 --- a/node/store_v2_test.go +++ b/node/store_v2_test.go @@ -2,6 +2,7 @@ package node_test import ( "testing" + "time" "github.com/Layr-Labs/eigenda/common/kvstore" "github.com/Layr-Labs/eigenda/common/kvstore/tablestore" @@ -189,6 +190,6 @@ func createStoreV2(t *testing.T) (node.StoreV2, kvstore.TableStore) { config.Schema = []string{node.BatchHeaderTableName, node.BlobCertificateTableName, node.BundleTableName} tStore, err := tablestore.Start(logger, config) require.NoError(t, err) - s := node.NewLevelDBStoreV2(tStore, logger) + s := node.NewLevelDBStoreV2(tStore, logger, 10*time.Second) return s, tStore }