From 826533ebb36d5d51640e03eb88513734c6501a9f Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 15 Nov 2024 00:18:28 -0800 Subject: [PATCH 01/18] temp: add v1 back --- api/clients/accountant.go | 50 ++ api/clients/config.go | 7 + api/clients/disperser_client.go | 118 +++- api/clients/disperser_client_test.go | 2 +- api/clients/eigenda_client.go | 12 +- api/clients/eigenda_client_test.go | 52 ++ api/clients/mock/disperser_client.go | 26 + api/grpc/disperser/disperser.pb.go | 821 +++++++++++++++++++----- api/grpc/disperser/disperser_grpc.pb.go | 84 +++ api/proto/disperser/disperser.proto | 50 ++ core/auth.go | 1 + core/auth/payment_signer.go | 36 ++ core/data.go | 3 +- core/meterer/offchain_store.go | 76 +++ disperser/apiserver/server.go | 189 ++++++ inabox/tests/ratelimit_test.go | 4 +- 16 files changed, 1360 insertions(+), 171 deletions(-) diff --git a/api/clients/accountant.go b/api/clients/accountant.go index 122ec3eea..4b8b06967 100644 --- a/api/clients/accountant.go +++ b/api/clients/accountant.go @@ -9,6 +9,7 @@ import ( "time" commonpb "github.com/Layr-Labs/eigenda/api/grpc/common" + disperser_rpc "github.com/Layr-Labs/eigenda/api/grpc/disperser" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/core/meterer" ) @@ -18,6 +19,8 @@ var requiredQuorums = []uint8{0, 1} type Accountant interface { AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, []byte, error) + AuthenticatePaymentStateRequest() (*disperser_rpc.GetPaymentStateRequest, error) + SetPaymentState(paymentState *disperser_rpc.GetPaymentStateReply) } var _ Accountant = &accountant{} @@ -178,3 +181,50 @@ func QuorumCheck(quorumNumbers []uint8, allowedNumbers []uint8) error { } return nil } + +func (a *accountant) SetPaymentState(paymentState *disperser_rpc.GetPaymentStateReply) { + quorumNumbers := make([]uint8, len(paymentState.Reservation.QuorumNumbers)) + for i, quorum := range paymentState.Reservation.QuorumNumbers { + quorumNumbers[i] = uint8(quorum) + } + quorumSplit := make([]uint8, len(paymentState.Reservation.QuorumSplit)) + for i, quorum := range paymentState.Reservation.QuorumSplit { + quorumSplit[i] = uint8(quorum) + } + a.reservation.QuorumNumbers = quorumNumbers + a.reservation.QuorumSplit = quorumSplit + + a.onDemand.CumulativePayment = new(big.Int).SetBytes(paymentState.OnChainCumulativePayment) + + a.pricePerSymbol = uint32(paymentState.PaymentGlobalParams.PricePerSymbol) + a.minNumSymbols = uint32(paymentState.PaymentGlobalParams.MinNumSymbols) + a.reservationWindow = uint32(paymentState.PaymentGlobalParams.ReservationWindow) + + records := make([]BinRecord, len(paymentState.BinRecords)) + for i, record := range paymentState.BinRecords { + records[i] = BinRecord{ + Index: record.Index, + Usage: record.Usage, + } + } + a.binRecords = records + a.reservation.SymbolsPerSec = uint64(paymentState.Reservation.SymbolsPerSecond) + a.reservation.StartTimestamp = uint64(paymentState.Reservation.StartTimestamp) + a.reservation.EndTimestamp = uint64(paymentState.Reservation.EndTimestamp) +} + +func (a *accountant) AuthenticatePaymentStateRequest() (*disperser_rpc.GetPaymentStateRequest, error) { + accountID := a.paymentSigner.GetAccountID() + + signature, err := a.paymentSigner.SignAccountID(accountID) + if err != nil { + return nil, err + } + + request := &disperser_rpc.GetPaymentStateRequest{ + AccountId: accountID, + Signature: signature, + } + + return request, nil +} diff --git a/api/clients/config.go b/api/clients/config.go index f4d9caa9f..5dbd78de0 100644 --- a/api/clients/config.go +++ b/api/clients/config.go @@ -60,6 +60,10 @@ type EigenDAClientConfig struct { // that can retrieve blobs but cannot disperse blobs. SignerPrivateKeyHex string + // Payment signer private key in hex encoded format. This key connect to the wallet with payment registered on-chain + // if set to "", will result in a non-paying client and cannot disperse paid blobs. + PaymentSignerPrivateKeyHex string + // Whether to disable TLS for an insecure connection when connecting to a local EigenDA disperser instance. DisableTLS bool @@ -112,6 +116,9 @@ func (c *EigenDAClientConfig) CheckAndSetDefaults() error { if len(c.SignerPrivateKeyHex) > 0 && len(c.SignerPrivateKeyHex) != 64 { return fmt.Errorf("a valid length SignerPrivateKeyHex needs to have 64 bytes") } + if len(c.PaymentSignerPrivateKeyHex) > 0 && len(c.PaymentSignerPrivateKeyHex) != 64 { + return fmt.Errorf("a valid length PaymentSignerPrivateKeyHex needs to have 64 bytes") + } if len(c.RPC) == 0 { return fmt.Errorf("EigenDAClientConfig.RPC not set") diff --git a/api/clients/disperser_client.go b/api/clients/disperser_client.go index 219b85bb4..ff508d05e 100644 --- a/api/clients/disperser_client.go +++ b/api/clients/disperser_client.go @@ -3,6 +3,7 @@ package clients import ( "context" "crypto/tls" + "errors" "fmt" "sync" "time" @@ -54,8 +55,10 @@ type DisperserClient interface { // DisperseBlobAuthenticated disperses a blob with an authenticated request. // The BlobStatus returned will always be PROCESSSING if error is nil. DisperseBlobAuthenticated(ctx context.Context, data []byte, customQuorums []uint8) (*disperser.BlobStatus, []byte, error) + DispersePaidBlob(ctx context.Context, data []byte, customQuorums []uint8) (*disperser.BlobStatus, []byte, error) GetBlobStatus(ctx context.Context, key []byte) (*disperser_rpc.BlobStatusReply, error) RetrieveBlob(ctx context.Context, batchHeaderHash []byte, blobIndex uint32) ([]byte, error) + InitializePaymentState(ctx context.Context) error } // See the NewDisperserClient constructor's documentation for details and usage examples. @@ -76,8 +79,9 @@ type disperserClient struct { // TODO: we should refactor or make a new constructor which allows setting conn and/or client // via dependency injection. This would allow for testing via https://pkg.go.dev/google.golang.org/grpc/test/bufconn // instead of a real network connection for eg. - conn *grpc.ClientConn - client disperser_rpc.DisperserClient + conn *grpc.ClientConn + client disperser_rpc.DisperserClient + accountant Accountant } var _ DisperserClient = &disperserClient{} @@ -102,13 +106,16 @@ var _ DisperserClient = &disperserClient{} // // // Subsequent calls will use the existing connection // status2, requestId2, err := client.DisperseBlob(ctx, otherData, otherQuorums) -func NewDisperserClient(config *Config, signer core.BlobRequestSigner) (*disperserClient, error) { +func NewDisperserClient(config *Config, signer core.BlobRequestSigner, paymentSigner core.PaymentSigner) (*disperserClient, error) { if err := checkConfigAndSetDefaults(config); err != nil { return nil, fmt.Errorf("invalid config: %w", err) } + // initialize an empty accountant; update payment state after initialization + accountant := NewAccountant(&core.ActiveReservation{}, &core.OnDemandPayment{}, 0, 0, 0, paymentSigner, 0) return &disperserClient{ - config: config, - signer: signer, + config: config, + signer: signer, + accountant: accountant, // conn and client are initialized lazily }, nil } @@ -183,6 +190,59 @@ func (c *disperserClient) DisperseBlob(ctx context.Context, data []byte, quorums return blobStatus, reply.GetRequestId(), nil } +// DispersePaidBlob disperses a blob with a payment header and signature. Similar to DisperseBlob but with signed payment header. +func (c *disperserClient) DispersePaidBlob(ctx context.Context, data []byte, quorums []uint8) (*disperser.BlobStatus, []byte, error) { + if c.accountant == nil { + return nil, nil, api.NewErrorInternal("not implemented") + } + + err := c.initOnceGrpcConnection() + if err != nil { + return nil, nil, fmt.Errorf("error initializing connection: %w", err) + } + + ctxTimeout, cancel := context.WithTimeout(ctx, c.config.Timeout) + defer cancel() + + quorumNumbers := make([]uint32, len(quorums)) + for i, q := range quorums { + quorumNumbers[i] = uint32(q) + } + + // check every 32 bytes of data are within the valid range for a bn254 field element + _, err = rs.ToFrArray(data) + if err != nil { + return nil, nil, fmt.Errorf("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 %w", err) + } + + header, signature, err := c.accountant.AccountBlob(ctx, uint64(encoding.GetBlobLength(uint(len(data)))), quorums) + if header == nil { + return nil, nil, errors.New("accountant returned nil pointer to header") + } + if err != nil { + return nil, nil, err + } + + request := &disperser_rpc.DispersePaidBlobRequest{ + Data: data, + QuorumNumbers: quorumNumbers, + PaymentHeader: header, + PaymentSignature: signature, + } + + reply, err := c.client.DispersePaidBlob(ctxTimeout, request) + if err != nil { + return nil, nil, err + } + + blobStatus, err := disperser.FromBlobStatusProto(reply.GetResult()) + if err != nil { + return nil, nil, err + } + + return blobStatus, reply.GetRequestId(), nil +} + func (c *disperserClient) DisperseBlobAuthenticated(ctx context.Context, data []byte, quorums []uint8) (*disperser.BlobStatus, []byte, error) { err := c.initOnceGrpcConnection() if err != nil { @@ -324,6 +384,54 @@ func (c *disperserClient) RetrieveBlob(ctx context.Context, batchHeaderHash []by return reply.Data, nil } +func (c *disperserClient) getPaymentState(ctx context.Context) (*disperser_rpc.GetPaymentStateReply, error) { + err := c.initOnceGrpcConnection() + if err != nil { + return nil, fmt.Errorf("error initializing connection: %w", err) + } + + ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*60) + defer cancel() + + request, err := c.accountant.AuthenticatePaymentStateRequest() + if err != nil { + return nil, err + } + reply, err := c.client.GetPaymentState(ctxTimeout, request) + if err != nil { + return nil, err + } + + return reply, nil +} + +func (c *disperserClient) InitializePaymentState(ctx context.Context) error { + paymentState, err := c.getPaymentState(ctx) + if err != nil { + return fmt.Errorf("error getting payment state from disperser: %w", err) + } + c.accountant.SetPaymentState(paymentState) + // c.accountant.binUsages = []uint64{uint64(paymentState.CurrentBinUsage), uint64(paymentState.NextBinUsage), uint64(paymentState.OverflowBinUsage)} + // c.accountant.cumulativePayment = new(big.Int).SetBytes(paymentState.CumulativePayment) + // quorumNumbers := make([]uint8, len(paymentState.Reservation.QuorumNumbers)) + // for i, q := range paymentState.Reservation.QuorumNumbers { + // quorumNumbers[i] = uint8(q) + // } + // c.accountant.reservation = core.ActiveReservation{ + // StartTimestamp: uint64(paymentState.Reservation.StartTimestamp), + // EndTimestamp: uint64(paymentState.Reservation.EndTimestamp), + // SymbolsPerSec: paymentState.Reservation.SymbolsPerSecond, + // QuorumNumbers: quorumNumbers, + // } + // c.accountant.onDemand = core.OnDemandPayment{ + // CumulativePayment: new(big.Int).SetBytes(paymentState.OnChainCumulativePayment), + // } + // c.accountant.reservationWindow = paymentState.PaymentGlobalParams.ReservationWindow + // c.accountant.pricePerSymbol = paymentState.PaymentGlobalParams.PricePerSymbol + // c.accountant.minNumSymbols = paymentState.PaymentGlobalParams.MinNumSymbols + return nil +} + // initOnceGrpcConnection initializes the grpc connection and client if they are not already initialized. // If initialization fails, it caches the error and will return it on every subsequent call. func (c *disperserClient) initOnceGrpcConnection() error { diff --git a/api/clients/disperser_client_test.go b/api/clients/disperser_client_test.go index 00277657b..853e3cc64 100644 --- a/api/clients/disperser_client_test.go +++ b/api/clients/disperser_client_test.go @@ -14,7 +14,7 @@ import ( func TestPutBlobNoopSigner(t *testing.T) { config := clients.NewConfig("nohost", "noport", time.Second, false) - disperserClient, err := clients.NewDisperserClient(config, auth.NewLocalNoopSigner()) + disperserClient, err := clients.NewDisperserClient(config, auth.NewLocalNoopSigner(), auth.NewNoopPaymentSigner()) assert.NoError(t, err) test := []byte("test") diff --git a/api/clients/eigenda_client.go b/api/clients/eigenda_client.go index 3231f2954..6560be474 100644 --- a/api/clients/eigenda_client.go +++ b/api/clients/eigenda_client.go @@ -99,21 +99,31 @@ func NewEigenDAClient(log log.Logger, config EigenDAClientConfig) (*EigenDAClien } var signer core.BlobRequestSigner + var paymentSigner core.PaymentSigner if len(config.SignerPrivateKeyHex) == 64 { signer = auth.NewLocalBlobRequestSigner(config.SignerPrivateKeyHex) + paymentSigner, err = auth.NewPaymentSigner(hex.EncodeToString([]byte(config.SignerPrivateKeyHex))) + if err != nil { + return nil, fmt.Errorf("new payment signer: %w", err) + } } else if len(config.SignerPrivateKeyHex) == 0 { // noop signer is used when we need a read-only eigenda client signer = auth.NewLocalNoopSigner() + paymentSigner = auth.NewNoopPaymentSigner() } else { return nil, fmt.Errorf("invalid length for signer private key") } disperserConfig := NewConfig(host, port, config.ResponseTimeout, !config.DisableTLS) - disperserClient, err := NewDisperserClient(disperserConfig, signer) + disperserClient, err := NewDisperserClient(disperserConfig, signer, paymentSigner) if err != nil { return nil, fmt.Errorf("new disperser-client: %w", err) } + err = disperserClient.InitializePaymentState(context.Background()) + if err != nil { + return nil, fmt.Errorf("error setting payment state: %w", err) + } lowLevelCodec, err := codecs.BlobEncodingVersionToCodec(config.PutBlobEncodingVersion) if err != nil { diff --git a/api/clients/eigenda_client_test.go b/api/clients/eigenda_client_test.go index 29435472b..9dd3a9f14 100644 --- a/api/clients/eigenda_client_test.go +++ b/api/clients/eigenda_client_test.go @@ -84,6 +84,58 @@ func TestPutRetrieveBlobIFFTSuccess(t *testing.T) { require.Equal(t, expectedBlob, resultBlob) } +// func TestGetBlobPaymentStateSuccess(t *testing.T) { +// disperserClient := clientsmock.NewMockDisperserClient() +// expectedPaymentState := &grpcdisperser.GetPaymentStateReply{PaymentGlobalParams: &grpcdisperser.PaymentGlobalParams{ +// GlobalSymbolsPerSecond: 100000, +// MinNumSymbols: 100, +// PricePerSymbol: 10, +// ReservationWindow: 100, +// OnDemandQuorumNumbers: []uint32{0, 1}, +// }, +// CurrentBinUsage: 100, +// NextBinUsage: 200, +// OverflowBinUsage: 300, +// Reservation: &grpcdisperser.Reservation{ +// SymbolsPerSecond: 1000, +// StartTimestamp: 0, +// EndTimestamp: math.MaxUint32, +// QuorumNumbers: []uint32{0, 1}, +// }, +// CumulativePayment: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, +// OnChainCumulativePayment: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, +// } +// (disperserClient.On("GetPaymentState", mock.Anything, mock.Anything). +// Return(expectedPaymentState, nil).Once()) +// logger := log.NewLogger(log.DiscardHandler()) +// eigendaClient := clients.EigenDAClient{ +// Log: logger, +// Config: clients.EigenDAClientConfig{ +// RPC: "localhost:51001", +// StatusQueryTimeout: 10 * time.Minute, +// StatusQueryRetryInterval: 50 * time.Millisecond, +// ResponseTimeout: 10 * time.Second, +// CustomQuorumIDs: []uint{}, +// SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d", +// DisableTLS: false, +// PutBlobEncodingVersion: codecs.DefaultBlobEncoding, +// DisablePointVerificationMode: false, +// WaitForFinalization: true, +// }, +// Client: disperserClient, +// Codec: codecs.NewIFFTCodec(codecs.NewDefaultBlobCodec()), +// } +// expectedBlob := []byte("dc49e7df326cfb2e7da5cf68f263e1898443ec2e862350606e7dfbda55ad10b5d61ed1d54baf6ae7a86279c1b4fa9c49a7de721dacb211264c1f5df31bade51c") +// blobInfo, err := eigendaClient.PutBlob(context.Background(), expectedBlob) +// require.NoError(t, err) +// require.NotNil(t, blobInfo) +// assert.Equal(t, finalizedBlobInfo, blobInfo) + +// resultBlob, err := eigendaClient.GetBlob(context.Background(), []byte("mock-batch-header-hash"), 100) +// require.NoError(t, err) +// require.Equal(t, expectedBlob, resultBlob) +// } + func TestPutRetrieveBlobIFFTNoDecodeSuccess(t *testing.T) { disperserClient := clientsmock.NewMockDisperserClient() expectedBlobStatus := disperser.Processing diff --git a/api/clients/mock/disperser_client.go b/api/clients/mock/disperser_client.go index 3763e8130..a2848d2cf 100644 --- a/api/clients/mock/disperser_client.go +++ b/api/clients/mock/disperser_client.go @@ -81,6 +81,27 @@ func (c *MockDisperserClient) DisperseBlob(ctx context.Context, data []byte, quo return status, key, err } +func (c *MockDisperserClient) DispersePaidBlob(ctx context.Context, data []byte, quorums []uint8) (*disperser.BlobStatus, []byte, error) { + args := c.Called(data, quorums) + var status *disperser.BlobStatus + if args.Get(0) != nil { + status = (args.Get(0)).(*disperser.BlobStatus) + } + var key []byte + if args.Get(1) != nil { + key = (args.Get(1)).([]byte) + } + var err error + if args.Get(2) != nil { + err = (args.Get(2)).(error) + } + + keyStr := base64.StdEncoding.EncodeToString(key) + c.mockRequestIDStore[keyStr] = data + + return status, key, err +} + func (c *MockDisperserClient) GetBlobStatus(ctx context.Context, key []byte) (*disperser_rpc.BlobStatusReply, error) { args := c.Called(key) var reply *disperser_rpc.BlobStatusReply @@ -117,6 +138,11 @@ func (c *MockDisperserClient) RetrieveBlob(ctx context.Context, batchHeaderHash return blob, err } +func (c *MockDisperserClient) InitializePaymentState(ctx context.Context) error { + args := c.Called() + return args.Error(0) +} + func (c *MockDisperserClient) Close() error { args := c.Called() return args.Error(0) diff --git a/api/grpc/disperser/disperser.pb.go b/api/grpc/disperser/disperser.pb.go index d10d4d736..5872d6c74 100644 --- a/api/grpc/disperser/disperser.pb.go +++ b/api/grpc/disperser/disperser.pb.go @@ -797,6 +797,147 @@ func (x *RetrieveBlobReply) GetData() []byte { return nil } +// GetPaymentStateRequest contains parameters to query the payment state of an account. +type GetPaymentStateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (x *GetPaymentStateRequest) Reset() { + *x = GetPaymentStateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_disperser_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPaymentStateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPaymentStateRequest) ProtoMessage() {} + +func (x *GetPaymentStateRequest) ProtoReflect() protoreflect.Message { + mi := &file_disperser_disperser_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPaymentStateRequest.ProtoReflect.Descriptor instead. +func (*GetPaymentStateRequest) Descriptor() ([]byte, []int) { + return file_disperser_disperser_proto_rawDescGZIP(), []int{11} +} + +func (x *GetPaymentStateRequest) GetAccountId() string { + if x != nil { + return x.AccountId + } + return "" +} + +func (x *GetPaymentStateRequest) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +// GetPaymentStateReply contains the payment state of an account. +type GetPaymentStateReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // global payment vault parameters + PaymentGlobalParams *PaymentGlobalParams `protobuf:"bytes,1,opt,name=payment_global_params,json=paymentGlobalParams,proto3" json:"payment_global_params,omitempty"` + // off-chain account reservation usage records + BinRecords []*BinRecord `protobuf:"bytes,2,rep,name=bin_records,json=binRecords,proto3" json:"bin_records,omitempty"` + // on-chain account reservation setting + Reservation *Reservation `protobuf:"bytes,3,opt,name=reservation,proto3" json:"reservation,omitempty"` + // off-chain on-demand payment usage + CumulativePayment []byte `protobuf:"bytes,4,opt,name=cumulative_payment,json=cumulativePayment,proto3" json:"cumulative_payment,omitempty"` + // on-chain on-demand payment deposited + OnChainCumulativePayment []byte `protobuf:"bytes,5,opt,name=on_chain_cumulative_payment,json=onChainCumulativePayment,proto3" json:"on_chain_cumulative_payment,omitempty"` +} + +func (x *GetPaymentStateReply) Reset() { + *x = GetPaymentStateReply{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_disperser_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPaymentStateReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPaymentStateReply) ProtoMessage() {} + +func (x *GetPaymentStateReply) ProtoReflect() protoreflect.Message { + mi := &file_disperser_disperser_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPaymentStateReply.ProtoReflect.Descriptor instead. +func (*GetPaymentStateReply) Descriptor() ([]byte, []int) { + return file_disperser_disperser_proto_rawDescGZIP(), []int{12} +} + +func (x *GetPaymentStateReply) GetPaymentGlobalParams() *PaymentGlobalParams { + if x != nil { + return x.PaymentGlobalParams + } + return nil +} + +func (x *GetPaymentStateReply) GetBinRecords() []*BinRecord { + if x != nil { + return x.BinRecords + } + return nil +} + +func (x *GetPaymentStateReply) GetReservation() *Reservation { + if x != nil { + return x.Reservation + } + return nil +} + +func (x *GetPaymentStateReply) GetCumulativePayment() []byte { + if x != nil { + return x.CumulativePayment + } + return nil +} + +func (x *GetPaymentStateReply) GetOnChainCumulativePayment() []byte { + if x != nil { + return x.OnChainCumulativePayment + } + return nil +} + // BlobInfo contains information needed to confirm the blob against the EigenDA contracts type BlobInfo struct { state protoimpl.MessageState @@ -810,7 +951,7 @@ type BlobInfo struct { func (x *BlobInfo) Reset() { *x = BlobInfo{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[11] + mi := &file_disperser_disperser_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -823,7 +964,7 @@ func (x *BlobInfo) String() string { func (*BlobInfo) ProtoMessage() {} func (x *BlobInfo) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[11] + mi := &file_disperser_disperser_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -836,7 +977,7 @@ func (x *BlobInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobInfo.ProtoReflect.Descriptor instead. func (*BlobInfo) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{11} + return file_disperser_disperser_proto_rawDescGZIP(), []int{13} } func (x *BlobInfo) GetBlobHeader() *BlobHeader { @@ -869,7 +1010,7 @@ type BlobHeader struct { func (x *BlobHeader) Reset() { *x = BlobHeader{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[12] + mi := &file_disperser_disperser_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -882,7 +1023,7 @@ func (x *BlobHeader) String() string { func (*BlobHeader) ProtoMessage() {} func (x *BlobHeader) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[12] + mi := &file_disperser_disperser_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -895,7 +1036,7 @@ func (x *BlobHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobHeader.ProtoReflect.Descriptor instead. func (*BlobHeader) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{12} + return file_disperser_disperser_proto_rawDescGZIP(), []int{14} } func (x *BlobHeader) GetCommitment() *common.G1Commitment { @@ -940,7 +1081,7 @@ type BlobQuorumParam struct { func (x *BlobQuorumParam) Reset() { *x = BlobQuorumParam{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[13] + mi := &file_disperser_disperser_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -953,7 +1094,7 @@ func (x *BlobQuorumParam) String() string { func (*BlobQuorumParam) ProtoMessage() {} func (x *BlobQuorumParam) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[13] + mi := &file_disperser_disperser_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -966,7 +1107,7 @@ func (x *BlobQuorumParam) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobQuorumParam.ProtoReflect.Descriptor instead. func (*BlobQuorumParam) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{13} + return file_disperser_disperser_proto_rawDescGZIP(), []int{15} } func (x *BlobQuorumParam) GetQuorumNumber() uint32 { @@ -1034,7 +1175,7 @@ type BlobVerificationProof struct { func (x *BlobVerificationProof) Reset() { *x = BlobVerificationProof{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[14] + mi := &file_disperser_disperser_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1047,7 +1188,7 @@ func (x *BlobVerificationProof) String() string { func (*BlobVerificationProof) ProtoMessage() {} func (x *BlobVerificationProof) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[14] + mi := &file_disperser_disperser_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1060,7 +1201,7 @@ func (x *BlobVerificationProof) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobVerificationProof.ProtoReflect.Descriptor instead. func (*BlobVerificationProof) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{14} + return file_disperser_disperser_proto_rawDescGZIP(), []int{16} } func (x *BlobVerificationProof) GetBatchId() uint32 { @@ -1120,7 +1261,7 @@ type BatchMetadata struct { func (x *BatchMetadata) Reset() { *x = BatchMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[15] + mi := &file_disperser_disperser_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1133,7 +1274,7 @@ func (x *BatchMetadata) String() string { func (*BatchMetadata) ProtoMessage() {} func (x *BatchMetadata) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[15] + mi := &file_disperser_disperser_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1146,7 +1287,7 @@ func (x *BatchMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchMetadata.ProtoReflect.Descriptor instead. func (*BatchMetadata) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{15} + return file_disperser_disperser_proto_rawDescGZIP(), []int{17} } func (x *BatchMetadata) GetBatchHeader() *BatchHeader { @@ -1206,7 +1347,7 @@ type BatchHeader struct { func (x *BatchHeader) Reset() { *x = BatchHeader{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[16] + mi := &file_disperser_disperser_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1219,7 +1360,7 @@ func (x *BatchHeader) String() string { func (*BatchHeader) ProtoMessage() {} func (x *BatchHeader) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[16] + mi := &file_disperser_disperser_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1232,7 +1373,7 @@ func (x *BatchHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchHeader.ProtoReflect.Descriptor instead. func (*BatchHeader) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{16} + return file_disperser_disperser_proto_rawDescGZIP(), []int{18} } func (x *BatchHeader) GetBatchRoot() []byte { @@ -1263,6 +1404,219 @@ func (x *BatchHeader) GetReferenceBlockNumber() uint32 { return 0 } +type PaymentGlobalParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GlobalSymbolsPerSecond uint64 `protobuf:"varint,1,opt,name=global_symbols_per_second,json=globalSymbolsPerSecond,proto3" json:"global_symbols_per_second,omitempty"` + MinNumSymbols uint32 `protobuf:"varint,2,opt,name=min_num_symbols,json=minNumSymbols,proto3" json:"min_num_symbols,omitempty"` + PricePerSymbol uint32 `protobuf:"varint,3,opt,name=price_per_symbol,json=pricePerSymbol,proto3" json:"price_per_symbol,omitempty"` + ReservationWindow uint32 `protobuf:"varint,4,opt,name=reservation_window,json=reservationWindow,proto3" json:"reservation_window,omitempty"` + OnDemandQuorumNumbers []uint32 `protobuf:"varint,5,rep,packed,name=on_demand_quorum_numbers,json=onDemandQuorumNumbers,proto3" json:"on_demand_quorum_numbers,omitempty"` +} + +func (x *PaymentGlobalParams) Reset() { + *x = PaymentGlobalParams{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_disperser_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PaymentGlobalParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentGlobalParams) ProtoMessage() {} + +func (x *PaymentGlobalParams) ProtoReflect() protoreflect.Message { + mi := &file_disperser_disperser_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PaymentGlobalParams.ProtoReflect.Descriptor instead. +func (*PaymentGlobalParams) Descriptor() ([]byte, []int) { + return file_disperser_disperser_proto_rawDescGZIP(), []int{19} +} + +func (x *PaymentGlobalParams) GetGlobalSymbolsPerSecond() uint64 { + if x != nil { + return x.GlobalSymbolsPerSecond + } + return 0 +} + +func (x *PaymentGlobalParams) GetMinNumSymbols() uint32 { + if x != nil { + return x.MinNumSymbols + } + return 0 +} + +func (x *PaymentGlobalParams) GetPricePerSymbol() uint32 { + if x != nil { + return x.PricePerSymbol + } + return 0 +} + +func (x *PaymentGlobalParams) GetReservationWindow() uint32 { + if x != nil { + return x.ReservationWindow + } + return 0 +} + +func (x *PaymentGlobalParams) GetOnDemandQuorumNumbers() []uint32 { + if x != nil { + return x.OnDemandQuorumNumbers + } + return nil +} + +type Reservation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SymbolsPerSecond uint64 `protobuf:"varint,1,opt,name=symbols_per_second,json=symbolsPerSecond,proto3" json:"symbols_per_second,omitempty"` + StartTimestamp uint32 `protobuf:"varint,2,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"` + EndTimestamp uint32 `protobuf:"varint,3,opt,name=end_timestamp,json=endTimestamp,proto3" json:"end_timestamp,omitempty"` + QuorumNumbers []uint32 `protobuf:"varint,4,rep,packed,name=quorum_numbers,json=quorumNumbers,proto3" json:"quorum_numbers,omitempty"` + QuorumSplit []uint32 `protobuf:"varint,5,rep,packed,name=quorum_split,json=quorumSplit,proto3" json:"quorum_split,omitempty"` +} + +func (x *Reservation) Reset() { + *x = Reservation{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_disperser_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Reservation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reservation) ProtoMessage() {} + +func (x *Reservation) ProtoReflect() protoreflect.Message { + mi := &file_disperser_disperser_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Reservation.ProtoReflect.Descriptor instead. +func (*Reservation) Descriptor() ([]byte, []int) { + return file_disperser_disperser_proto_rawDescGZIP(), []int{20} +} + +func (x *Reservation) GetSymbolsPerSecond() uint64 { + if x != nil { + return x.SymbolsPerSecond + } + return 0 +} + +func (x *Reservation) GetStartTimestamp() uint32 { + if x != nil { + return x.StartTimestamp + } + return 0 +} + +func (x *Reservation) GetEndTimestamp() uint32 { + if x != nil { + return x.EndTimestamp + } + return 0 +} + +func (x *Reservation) GetQuorumNumbers() []uint32 { + if x != nil { + return x.QuorumNumbers + } + return nil +} + +func (x *Reservation) GetQuorumSplit() []uint32 { + if x != nil { + return x.QuorumSplit + } + return nil +} + +type BinRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Index uint32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Usage uint64 `protobuf:"varint,2,opt,name=usage,proto3" json:"usage,omitempty"` +} + +func (x *BinRecord) Reset() { + *x = BinRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_disperser_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BinRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BinRecord) ProtoMessage() {} + +func (x *BinRecord) ProtoReflect() protoreflect.Message { + mi := &file_disperser_disperser_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BinRecord.ProtoReflect.Descriptor instead. +func (*BinRecord) Descriptor() ([]byte, []int) { + return file_disperser_disperser_proto_rawDescGZIP(), []int{21} +} + +func (x *BinRecord) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *BinRecord) GetUsage() uint64 { + if x != nil { + return x.Usage + } + return 0 +} + var File_disperser_disperser_proto protoreflect.FileDescriptor var file_disperser_disperser_proto_rawDesc = []byte{ @@ -1346,115 +1700,186 @@ var file_disperser_disperser_proto_rawDesc = []byte{ 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x27, 0x0a, 0x11, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x9c, 0x01, 0x0a, 0x08, 0x42, 0x6c, 0x6f, 0x62, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x36, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, - 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0a, - 0x62, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x17, 0x62, 0x6c, - 0x6f, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x15, 0x62, - 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xad, 0x01, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x47, 0x31, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, - 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x12, 0x62, 0x6c, - 0x6f, 0x62, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, - 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x71, 0x75, 0x6f, 0x72, - 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x44, 0x0a, - 0x1e, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, - 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1c, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, - 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, - 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x21, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x65, - 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, 0x65, - 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x4c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x22, 0xe2, 0x01, 0x0a, 0x15, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x19, 0x0a, 0x08, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, - 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3f, 0x0a, 0x0e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0c, 0x62, 0x61, 0x74, - 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, - 0x79, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x13, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x3a, 0x0a, 0x19, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, - 0x73, 0x68, 0x22, 0xc5, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, 0x6f, 0x6f, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x52, 0x6f, 0x6f, - 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, - 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x71, 0x75, 0x6f, 0x72, - 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x71, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, - 0x61, 0x67, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2a, 0x80, 0x01, 0x0a, 0x0a, 0x42, - 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, - 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, - 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, - 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x04, - 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, - 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x12, 0x0e, 0x0a, - 0x0a, 0x44, 0x49, 0x53, 0x50, 0x45, 0x52, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x32, 0xd9, 0x02, - 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0c, 0x44, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x19, 0x44, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x55, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xc9, 0x02, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x52, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, + 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x52, 0x13, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x62, 0x69, 0x6e, + 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x69, 0x6e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x52, 0x0a, 0x62, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, + 0x12, 0x38, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x72, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x75, + 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x1b, 0x6f, 0x6e, 0x5f, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, + 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x9c, 0x01, 0x0a, 0x08, 0x42, 0x6c, 0x6f, + 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x36, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, + 0x17, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x52, 0x15, 0x62, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xad, 0x01, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x31, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x48, 0x0a, + 0x12, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x64, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, + 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x62, + 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x71, + 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x44, 0x0a, 0x1e, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, 0x5f, 0x74, 0x68, + 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1c, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x72, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, + 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x21, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, + 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x1f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, + 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, + 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x4c, + 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xe2, 0x01, 0x0a, 0x15, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, + 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, + 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, + 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3f, 0x0a, 0x0e, 0x62, 0x61, 0x74, + 0x63, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x62, 0x61, 0x74, + 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0c, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, + 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x66, + 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x3a, 0x0a, + 0x19, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x17, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x74, + 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x48, 0x61, 0x73, 0x68, 0x22, 0xc5, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, + 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, + 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, + 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x71, + 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, + 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x72, 0x63, + 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x8a, 0x02, + 0x0a, 0x13, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, + 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x4e, 0x75, + 0x6d, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, + 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x71, + 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0d, 0x52, 0x15, 0x6f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x51, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x52, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, + 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, + 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, + 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, + 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0d, 0x52, 0x0b, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x70, 0x6c, 0x69, 0x74, + 0x22, 0x37, 0x0a, 0x09, 0x42, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x80, 0x01, 0x0a, 0x0a, 0x42, 0x6c, + 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, 0x53, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, + 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x04, 0x12, + 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, + 0x44, 0x49, 0x53, 0x50, 0x45, 0x52, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x32, 0x8a, 0x04, 0x0a, + 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0c, 0x44, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, + 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, + 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x19, 0x44, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, + 0x73, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, - 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x0d, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x2e, - 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0c, 0x52, 0x65, 0x74, - 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x64, 0x69, 0x73, 0x70, - 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, - 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, - 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, - 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, + 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x28, 0x01, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x10, 0x44, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x50, 0x61, 0x69, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x12, + 0x22, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x50, 0x61, 0x69, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, + 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, + 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, + 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x4e, 0x0a, 0x0c, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, + 0x12, 0x1e, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, + 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, + 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x57, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, + 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, + 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, @@ -1474,7 +1899,7 @@ func file_disperser_disperser_proto_rawDescGZIP() []byte { } var file_disperser_disperser_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_disperser_disperser_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_disperser_disperser_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_disperser_disperser_proto_goTypes = []interface{}{ (BlobStatus)(0), // 0: disperser.BlobStatus (*AuthenticatedRequest)(nil), // 1: disperser.AuthenticatedRequest @@ -1488,43 +1913,55 @@ var file_disperser_disperser_proto_goTypes = []interface{}{ (*BlobStatusReply)(nil), // 9: disperser.BlobStatusReply (*RetrieveBlobRequest)(nil), // 10: disperser.RetrieveBlobRequest (*RetrieveBlobReply)(nil), // 11: disperser.RetrieveBlobReply - (*BlobInfo)(nil), // 12: disperser.BlobInfo - (*BlobHeader)(nil), // 13: disperser.BlobHeader - (*BlobQuorumParam)(nil), // 14: disperser.BlobQuorumParam - (*BlobVerificationProof)(nil), // 15: disperser.BlobVerificationProof - (*BatchMetadata)(nil), // 16: disperser.BatchMetadata - (*BatchHeader)(nil), // 17: disperser.BatchHeader - (*common.PaymentHeader)(nil), // 18: common.PaymentHeader - (*common.G1Commitment)(nil), // 19: common.G1Commitment + (*GetPaymentStateRequest)(nil), // 12: disperser.GetPaymentStateRequest + (*GetPaymentStateReply)(nil), // 13: disperser.GetPaymentStateReply + (*BlobInfo)(nil), // 14: disperser.BlobInfo + (*BlobHeader)(nil), // 15: disperser.BlobHeader + (*BlobQuorumParam)(nil), // 16: disperser.BlobQuorumParam + (*BlobVerificationProof)(nil), // 17: disperser.BlobVerificationProof + (*BatchMetadata)(nil), // 18: disperser.BatchMetadata + (*BatchHeader)(nil), // 19: disperser.BatchHeader + (*PaymentGlobalParams)(nil), // 20: disperser.PaymentGlobalParams + (*Reservation)(nil), // 21: disperser.Reservation + (*BinRecord)(nil), // 22: disperser.BinRecord + (*common.PaymentHeader)(nil), // 23: common.PaymentHeader + (*common.G1Commitment)(nil), // 24: common.G1Commitment } var file_disperser_disperser_proto_depIdxs = []int32{ 5, // 0: disperser.AuthenticatedRequest.disperse_request:type_name -> disperser.DisperseBlobRequest 4, // 1: disperser.AuthenticatedRequest.authentication_data:type_name -> disperser.AuthenticationData 3, // 2: disperser.AuthenticatedReply.blob_auth_header:type_name -> disperser.BlobAuthHeader 7, // 3: disperser.AuthenticatedReply.disperse_reply:type_name -> disperser.DisperseBlobReply - 18, // 4: disperser.DispersePaidBlobRequest.payment_header:type_name -> common.PaymentHeader + 23, // 4: disperser.DispersePaidBlobRequest.payment_header:type_name -> common.PaymentHeader 0, // 5: disperser.DisperseBlobReply.result:type_name -> disperser.BlobStatus 0, // 6: disperser.BlobStatusReply.status:type_name -> disperser.BlobStatus - 12, // 7: disperser.BlobStatusReply.info:type_name -> disperser.BlobInfo - 13, // 8: disperser.BlobInfo.blob_header:type_name -> disperser.BlobHeader - 15, // 9: disperser.BlobInfo.blob_verification_proof:type_name -> disperser.BlobVerificationProof - 19, // 10: disperser.BlobHeader.commitment:type_name -> common.G1Commitment - 14, // 11: disperser.BlobHeader.blob_quorum_params:type_name -> disperser.BlobQuorumParam - 16, // 12: disperser.BlobVerificationProof.batch_metadata:type_name -> disperser.BatchMetadata - 17, // 13: disperser.BatchMetadata.batch_header:type_name -> disperser.BatchHeader - 5, // 14: disperser.Disperser.DisperseBlob:input_type -> disperser.DisperseBlobRequest - 1, // 15: disperser.Disperser.DisperseBlobAuthenticated:input_type -> disperser.AuthenticatedRequest - 8, // 16: disperser.Disperser.GetBlobStatus:input_type -> disperser.BlobStatusRequest - 10, // 17: disperser.Disperser.RetrieveBlob:input_type -> disperser.RetrieveBlobRequest - 7, // 18: disperser.Disperser.DisperseBlob:output_type -> disperser.DisperseBlobReply - 2, // 19: disperser.Disperser.DisperseBlobAuthenticated:output_type -> disperser.AuthenticatedReply - 9, // 20: disperser.Disperser.GetBlobStatus:output_type -> disperser.BlobStatusReply - 11, // 21: disperser.Disperser.RetrieveBlob:output_type -> disperser.RetrieveBlobReply - 18, // [18:22] is the sub-list for method output_type - 14, // [14:18] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 14, // 7: disperser.BlobStatusReply.info:type_name -> disperser.BlobInfo + 20, // 8: disperser.GetPaymentStateReply.payment_global_params:type_name -> disperser.PaymentGlobalParams + 22, // 9: disperser.GetPaymentStateReply.bin_records:type_name -> disperser.BinRecord + 21, // 10: disperser.GetPaymentStateReply.reservation:type_name -> disperser.Reservation + 15, // 11: disperser.BlobInfo.blob_header:type_name -> disperser.BlobHeader + 17, // 12: disperser.BlobInfo.blob_verification_proof:type_name -> disperser.BlobVerificationProof + 24, // 13: disperser.BlobHeader.commitment:type_name -> common.G1Commitment + 16, // 14: disperser.BlobHeader.blob_quorum_params:type_name -> disperser.BlobQuorumParam + 18, // 15: disperser.BlobVerificationProof.batch_metadata:type_name -> disperser.BatchMetadata + 19, // 16: disperser.BatchMetadata.batch_header:type_name -> disperser.BatchHeader + 5, // 17: disperser.Disperser.DisperseBlob:input_type -> disperser.DisperseBlobRequest + 1, // 18: disperser.Disperser.DisperseBlobAuthenticated:input_type -> disperser.AuthenticatedRequest + 6, // 19: disperser.Disperser.DispersePaidBlob:input_type -> disperser.DispersePaidBlobRequest + 8, // 20: disperser.Disperser.GetBlobStatus:input_type -> disperser.BlobStatusRequest + 10, // 21: disperser.Disperser.RetrieveBlob:input_type -> disperser.RetrieveBlobRequest + 12, // 22: disperser.Disperser.GetPaymentState:input_type -> disperser.GetPaymentStateRequest + 7, // 23: disperser.Disperser.DisperseBlob:output_type -> disperser.DisperseBlobReply + 2, // 24: disperser.Disperser.DisperseBlobAuthenticated:output_type -> disperser.AuthenticatedReply + 7, // 25: disperser.Disperser.DispersePaidBlob:output_type -> disperser.DisperseBlobReply + 9, // 26: disperser.Disperser.GetBlobStatus:output_type -> disperser.BlobStatusReply + 11, // 27: disperser.Disperser.RetrieveBlob:output_type -> disperser.RetrieveBlobReply + 13, // 28: disperser.Disperser.GetPaymentState:output_type -> disperser.GetPaymentStateReply + 23, // [23:29] is the sub-list for method output_type + 17, // [17:23] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_disperser_disperser_proto_init() } @@ -1666,7 +2103,7 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlobInfo); i { + switch v := v.(*GetPaymentStateRequest); i { case 0: return &v.state case 1: @@ -1678,7 +2115,7 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlobHeader); i { + switch v := v.(*GetPaymentStateReply); i { case 0: return &v.state case 1: @@ -1690,7 +2127,7 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlobQuorumParam); i { + switch v := v.(*BlobInfo); i { case 0: return &v.state case 1: @@ -1702,7 +2139,7 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlobVerificationProof); i { + switch v := v.(*BlobHeader); i { case 0: return &v.state case 1: @@ -1714,7 +2151,7 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchMetadata); i { + switch v := v.(*BlobQuorumParam); i { case 0: return &v.state case 1: @@ -1726,6 +2163,30 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlobVerificationProof); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_disperser_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_disperser_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BatchHeader); i { case 0: return &v.state @@ -1737,6 +2198,42 @@ func file_disperser_disperser_proto_init() { return nil } } + file_disperser_disperser_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PaymentGlobalParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_disperser_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Reservation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_disperser_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BinRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_disperser_disperser_proto_msgTypes[0].OneofWrappers = []interface{}{ (*AuthenticatedRequest_DisperseRequest)(nil), @@ -1752,7 +2249,7 @@ func file_disperser_disperser_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_disperser_disperser_proto_rawDesc, NumEnums: 1, - NumMessages: 17, + NumMessages: 22, NumExtensions: 0, NumServices: 1, }, diff --git a/api/grpc/disperser/disperser_grpc.pb.go b/api/grpc/disperser/disperser_grpc.pb.go index c6bb719a2..d082c3ae8 100644 --- a/api/grpc/disperser/disperser_grpc.pb.go +++ b/api/grpc/disperser/disperser_grpc.pb.go @@ -21,8 +21,10 @@ const _ = grpc.SupportPackageIsVersion7 const ( Disperser_DisperseBlob_FullMethodName = "/disperser.Disperser/DisperseBlob" Disperser_DisperseBlobAuthenticated_FullMethodName = "/disperser.Disperser/DisperseBlobAuthenticated" + Disperser_DispersePaidBlob_FullMethodName = "/disperser.Disperser/DispersePaidBlob" Disperser_GetBlobStatus_FullMethodName = "/disperser.Disperser/GetBlobStatus" Disperser_RetrieveBlob_FullMethodName = "/disperser.Disperser/RetrieveBlob" + Disperser_GetPaymentState_FullMethodName = "/disperser.Disperser/GetPaymentState" ) // DisperserClient is the client API for Disperser service. @@ -51,6 +53,11 @@ type DisperserClient interface { // AuthenticationData message. // 4. The Disperser verifies the signature and returns a DisperseBlobReply message. DisperseBlobAuthenticated(ctx context.Context, opts ...grpc.CallOption) (Disperser_DisperseBlobAuthenticatedClient, error) + // This API require valid payments to accept blob to disperse from clients. + // This executes the dispersal async, i.e. it returns once the request + // is accepted. The client could use GetBlobStatus() API to poll the the + // processing status of the blob. + DispersePaidBlob(ctx context.Context, in *DispersePaidBlobRequest, opts ...grpc.CallOption) (*DisperseBlobReply, error) // This API is meant to be polled for the blob status. GetBlobStatus(ctx context.Context, in *BlobStatusRequest, opts ...grpc.CallOption) (*BlobStatusReply, error) // This retrieves the requested blob from the Disperser's backend. @@ -60,6 +67,8 @@ type DisperserClient interface { // The blob should have been initially dispersed via this Disperser service // for this API to work. RetrieveBlob(ctx context.Context, in *RetrieveBlobRequest, opts ...grpc.CallOption) (*RetrieveBlobReply, error) + // This API is used to query the payment state of a given account. + GetPaymentState(ctx context.Context, in *GetPaymentStateRequest, opts ...grpc.CallOption) (*GetPaymentStateReply, error) } type disperserClient struct { @@ -110,6 +119,15 @@ func (x *disperserDisperseBlobAuthenticatedClient) Recv() (*AuthenticatedReply, return m, nil } +func (c *disperserClient) DispersePaidBlob(ctx context.Context, in *DispersePaidBlobRequest, opts ...grpc.CallOption) (*DisperseBlobReply, error) { + out := new(DisperseBlobReply) + err := c.cc.Invoke(ctx, Disperser_DispersePaidBlob_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *disperserClient) GetBlobStatus(ctx context.Context, in *BlobStatusRequest, opts ...grpc.CallOption) (*BlobStatusReply, error) { out := new(BlobStatusReply) err := c.cc.Invoke(ctx, Disperser_GetBlobStatus_FullMethodName, in, out, opts...) @@ -128,6 +146,15 @@ func (c *disperserClient) RetrieveBlob(ctx context.Context, in *RetrieveBlobRequ return out, nil } +func (c *disperserClient) GetPaymentState(ctx context.Context, in *GetPaymentStateRequest, opts ...grpc.CallOption) (*GetPaymentStateReply, error) { + out := new(GetPaymentStateReply) + err := c.cc.Invoke(ctx, Disperser_GetPaymentState_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DisperserServer is the server API for Disperser service. // All implementations must embed UnimplementedDisperserServer // for forward compatibility @@ -154,6 +181,11 @@ type DisperserServer interface { // AuthenticationData message. // 4. The Disperser verifies the signature and returns a DisperseBlobReply message. DisperseBlobAuthenticated(Disperser_DisperseBlobAuthenticatedServer) error + // This API require valid payments to accept blob to disperse from clients. + // This executes the dispersal async, i.e. it returns once the request + // is accepted. The client could use GetBlobStatus() API to poll the the + // processing status of the blob. + DispersePaidBlob(context.Context, *DispersePaidBlobRequest) (*DisperseBlobReply, error) // This API is meant to be polled for the blob status. GetBlobStatus(context.Context, *BlobStatusRequest) (*BlobStatusReply, error) // This retrieves the requested blob from the Disperser's backend. @@ -163,6 +195,8 @@ type DisperserServer interface { // The blob should have been initially dispersed via this Disperser service // for this API to work. RetrieveBlob(context.Context, *RetrieveBlobRequest) (*RetrieveBlobReply, error) + // This API is used to query the payment state of a given account. + GetPaymentState(context.Context, *GetPaymentStateRequest) (*GetPaymentStateReply, error) mustEmbedUnimplementedDisperserServer() } @@ -176,12 +210,18 @@ func (UnimplementedDisperserServer) DisperseBlob(context.Context, *DisperseBlobR func (UnimplementedDisperserServer) DisperseBlobAuthenticated(Disperser_DisperseBlobAuthenticatedServer) error { return status.Errorf(codes.Unimplemented, "method DisperseBlobAuthenticated not implemented") } +func (UnimplementedDisperserServer) DispersePaidBlob(context.Context, *DispersePaidBlobRequest) (*DisperseBlobReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method DispersePaidBlob not implemented") +} func (UnimplementedDisperserServer) GetBlobStatus(context.Context, *BlobStatusRequest) (*BlobStatusReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetBlobStatus not implemented") } func (UnimplementedDisperserServer) RetrieveBlob(context.Context, *RetrieveBlobRequest) (*RetrieveBlobReply, error) { return nil, status.Errorf(codes.Unimplemented, "method RetrieveBlob not implemented") } +func (UnimplementedDisperserServer) GetPaymentState(context.Context, *GetPaymentStateRequest) (*GetPaymentStateReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPaymentState not implemented") +} func (UnimplementedDisperserServer) mustEmbedUnimplementedDisperserServer() {} // UnsafeDisperserServer may be embedded to opt out of forward compatibility for this service. @@ -239,6 +279,24 @@ func (x *disperserDisperseBlobAuthenticatedServer) Recv() (*AuthenticatedRequest return m, nil } +func _Disperser_DispersePaidBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DispersePaidBlobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DisperserServer).DispersePaidBlob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Disperser_DispersePaidBlob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DisperserServer).DispersePaidBlob(ctx, req.(*DispersePaidBlobRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Disperser_GetBlobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(BlobStatusRequest) if err := dec(in); err != nil { @@ -275,6 +333,24 @@ func _Disperser_RetrieveBlob_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Disperser_GetPaymentState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPaymentStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DisperserServer).GetPaymentState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Disperser_GetPaymentState_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DisperserServer).GetPaymentState(ctx, req.(*GetPaymentStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Disperser_ServiceDesc is the grpc.ServiceDesc for Disperser service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -286,6 +362,10 @@ var Disperser_ServiceDesc = grpc.ServiceDesc{ MethodName: "DisperseBlob", Handler: _Disperser_DisperseBlob_Handler, }, + { + MethodName: "DispersePaidBlob", + Handler: _Disperser_DispersePaidBlob_Handler, + }, { MethodName: "GetBlobStatus", Handler: _Disperser_GetBlobStatus_Handler, @@ -294,6 +374,10 @@ var Disperser_ServiceDesc = grpc.ServiceDesc{ MethodName: "RetrieveBlob", Handler: _Disperser_RetrieveBlob_Handler, }, + { + MethodName: "GetPaymentState", + Handler: _Disperser_GetPaymentState_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/api/proto/disperser/disperser.proto b/api/proto/disperser/disperser.proto index f4bfa1384..b9d5c01fe 100644 --- a/api/proto/disperser/disperser.proto +++ b/api/proto/disperser/disperser.proto @@ -27,6 +27,12 @@ service Disperser { // 4. The Disperser verifies the signature and returns a DisperseBlobReply message. rpc DisperseBlobAuthenticated(stream AuthenticatedRequest) returns (stream AuthenticatedReply); + // This API require valid payments to accept blob to disperse from clients. + // This executes the dispersal async, i.e. it returns once the request + // is accepted. The client could use GetBlobStatus() API to poll the the + // processing status of the blob. + rpc DispersePaidBlob(DispersePaidBlobRequest) returns (DisperseBlobReply) {} + // This API is meant to be polled for the blob status. rpc GetBlobStatus(BlobStatusRequest) returns (BlobStatusReply) {} @@ -37,6 +43,9 @@ service Disperser { // The blob should have been initially dispersed via this Disperser service // for this API to work. rpc RetrieveBlob(RetrieveBlobRequest) returns (RetrieveBlobReply) {} + + // This API is used to query the payment state of a given account. + rpc GetPaymentState(GetPaymentStateRequest) returns (GetPaymentStateReply) {} } // Requests and Responses @@ -142,6 +151,26 @@ message RetrieveBlobReply { bytes data = 1; } +// GetPaymentStateRequest contains parameters to query the payment state of an account. +message GetPaymentStateRequest { + string account_id = 1; + bytes signature = 2; +} + +// GetPaymentStateReply contains the payment state of an account. +message GetPaymentStateReply { + // global payment vault parameters + PaymentGlobalParams payment_global_params = 1; + // off-chain account reservation usage records + repeated BinRecord bin_records = 2; + // on-chain account reservation setting + Reservation reservation = 3; + // off-chain on-demand payment usage + bytes cumulative_payment = 4; + // on-chain on-demand payment deposited + bytes on_chain_cumulative_payment = 5; +} + // Data Types // BlobStatus represents the status of a blob. @@ -272,3 +301,24 @@ message BatchHeader { // (e.g. operator stakes) at this block number. uint32 reference_block_number = 4; } + +message PaymentGlobalParams { + uint64 global_symbols_per_second = 1; + uint32 min_num_symbols = 2; + uint32 price_per_symbol = 3; + uint32 reservation_window = 4; + repeated uint32 on_demand_quorum_numbers = 5; +} + +message Reservation { + uint64 symbols_per_second = 1; + uint32 start_timestamp = 2; + uint32 end_timestamp = 3; + repeated uint32 quorum_numbers = 4; + repeated uint32 quorum_split = 5; +} + +message BinRecord { + uint32 index = 1; + uint64 usage = 2; +} diff --git a/core/auth.go b/core/auth.go index 7e7669aa2..dbeab3a58 100644 --- a/core/auth.go +++ b/core/auth.go @@ -51,5 +51,6 @@ func VerifySignature(message []byte, accountAddr geth.Address, sig []byte) error type PaymentSigner interface { SignBlobPayment(header *PaymentMetadata) ([]byte, error) + SignAccountID(accountID string) ([]byte, error) GetAccountID() string } diff --git a/core/auth/payment_signer.go b/core/auth/payment_signer.go index b22283040..f4fa92dce 100644 --- a/core/auth/payment_signer.go +++ b/core/auth/payment_signer.go @@ -2,7 +2,9 @@ package auth import ( "crypto/ecdsa" + "encoding/hex" "fmt" + "log" "github.com/Layr-Labs/eigenda/core" "github.com/ethereum/go-ethereum/common" @@ -45,6 +47,16 @@ func (s *paymentSigner) SignBlobPayment(pm *core.PaymentMetadata) ([]byte, error return sig, nil } +func (s *paymentSigner) SignAccountID(accountID string) ([]byte, error) { + hash := crypto.Keccak256Hash([]byte(accountID)) + sig, err := crypto.Sign(hash.Bytes(), s.PrivateKey) + if err != nil { + return nil, fmt.Errorf("failed to sign account ID: %v", err) + } + + return sig, nil +} + type NoopPaymentSigner struct{} func NewNoopPaymentSigner() *NoopPaymentSigner { @@ -55,6 +67,10 @@ func (s *NoopPaymentSigner) SignBlobPayment(header *core.PaymentMetadata) ([]byt return nil, fmt.Errorf("noop signer cannot sign blob payment header") } +func (s *NoopPaymentSigner) SignAccountID(accountID string) ([]byte, error) { + return nil, fmt.Errorf("noop signer cannot sign account ID") +} + func (s *NoopPaymentSigner) GetAccountID() string { return "" } @@ -90,6 +106,26 @@ func VerifyPaymentSignature(paymentHeader *core.PaymentMetadata, paymentSignatur return nil } +// VerifyAccountSignature verifies the signature against an account ID +func VerifyAccountSignature(accountID string, paymentSignature []byte) bool { + pubKeyBytes, err := hex.DecodeString(accountID) + if err != nil { + log.Printf("Failed to decode AccountId: %v\n", err) + return false + } + accountPubKey, err := crypto.UnmarshalPubkey(pubKeyBytes) + if err != nil { + log.Printf("Failed to unmarshal public key: %v\n", err) + return false + } + + return crypto.VerifySignature( + crypto.FromECDSAPub(accountPubKey), + []byte(accountID), + paymentSignature[:len(paymentSignature)-1], // Remove recovery ID + ) +} + // GetAccountID returns the Ethereum address of the signer func (s *paymentSigner) GetAccountID() string { publicKey := crypto.FromECDSAPub(&s.PrivateKey.PublicKey) diff --git a/core/data.go b/core/data.go index 430305690..ebc9f170f 100644 --- a/core/data.go +++ b/core/data.go @@ -601,7 +601,8 @@ func ConvertToPaymentMetadata(ph *commonpb.PaymentHeader) *PaymentMetadata { // OperatorInfo contains information about an operator which is stored on the blockchain state, // corresponding to a particular quorum type ActiveReservation struct { - SymbolsPerSec uint64 // reserve number of symbols per second + SymbolsPerSec uint64 // reserve number of symbols per second + //TODO: we are not using start and end timestamp, should remove StartTimestamp uint64 // Unix timestamp that's valid for basically eternity EndTimestamp uint64 diff --git a/core/meterer/offchain_store.go b/core/meterer/offchain_store.go index e07ca0668..0a5f425d5 100644 --- a/core/meterer/offchain_store.go +++ b/core/meterer/offchain_store.go @@ -237,3 +237,79 @@ func (s *OffchainStore) GetRelevantOnDemandRecords(ctx context.Context, accountI return prevPayment, nextPayment, nextDataLength, nil } + +func (s *OffchainStore) GetBinUsages(ctx context.Context, accountID string, binIndex uint32) (uint64, uint64, uint64, error) { + // Fetch the 3 bins start from the current bin + queryInput := &dynamodb.QueryInput{ + TableName: aws.String(s.reservationTableName), + KeyConditionExpression: aws.String("AccountID = :account AND binIndex > :binIndex"), + ExpressionAttributeValues: commondynamodb.ExpressionValues{ + ":account": &types.AttributeValueMemberS{Value: accountID}, + ":binIndex": &types.AttributeValueMemberN{Value: strconv.FormatUint(uint64(binIndex), 10)}, + }, + ScanIndexForward: aws.Bool(true), + Limit: aws.Int32(3), + } + bins, err := s.dynamoClient.QueryWithInput(ctx, queryInput) + if err != nil { + return 0, 0, 0, fmt.Errorf("failed to query payments for account: %w", err) + } + + usages := make([]uint64, 3) + for i := 0; i < len(bins) && i < 3; i++ { + usage, err := parseBinUsage(bins[i]) + if err != nil { + return 0, 0, 0, fmt.Errorf("failed to parse bin %d usage: %w", i, err) + } + usages[i] = usage + } + + return usages[0], usages[1], usages[2], nil +} + +func (s *OffchainStore) GetLargestCumulativePayment(ctx context.Context, accountID string) (*big.Int, error) { + // Fetch the largest cumulative payment + queryInput := &dynamodb.QueryInput{ + TableName: aws.String(s.onDemandTableName), + KeyConditionExpression: aws.String("AccountID = :account"), + ExpressionAttributeValues: commondynamodb.ExpressionValues{ + ":account": &types.AttributeValueMemberS{Value: accountID}, + }, + ScanIndexForward: aws.Bool(false), + Limit: aws.Int32(1), + } + payments, err := s.dynamoClient.QueryWithInput(ctx, queryInput) + if err != nil { + return nil, fmt.Errorf("failed to query payments for account: %w", err) + } + + if len(payments) == 0 { + return nil, nil + } + + payment, err := strconv.ParseUint(payments[0]["CumulativePayments"].(*types.AttributeValueMemberN).Value, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse payment: %w", err) + } + + return big.NewInt(int64(payment)), nil +} + +func parseBinUsage(bin map[string]types.AttributeValue) (uint64, error) { + binUsage, ok := bin["BinUsage"] + if !ok { + return 0, errors.New("BinUsage is not present in the response") + } + + binUsageAttr, ok := binUsage.(*types.AttributeValueMemberN) + if !ok { + return 0, fmt.Errorf("unexpected type for BinUsage: %T", binUsage) + } + + binUsageValue, err := strconv.ParseUint(binUsageAttr.Value, 10, 32) + if err != nil { + return 0, fmt.Errorf("failed to parse BinUsage: %w", err) + } + + return binUsageValue, nil +} diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 6c9be3c54..c9bc58a2e 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "errors" "fmt" + "math/big" "net" "slices" "strings" @@ -325,6 +326,100 @@ func (s *DispersalServer) disperseBlob(ctx context.Context, blob *core.Blob, aut }, nil } +func (s *DispersalServer) DispersePaidBlob(ctx context.Context, req *pb.DispersePaidBlobRequest) (*pb.DisperseBlobReply, error) { + blob, err := s.validatePaidRequestAndGetBlob(ctx, req) + binIndex := req.PaymentHeader.BinIndex + cumulativePayment := new(big.Int).SetBytes(req.PaymentHeader.CumulativePayment) + //todo: before disperse blob, validate the signature + signature := req.PaymentSignature + if err := auth.VerifyPaymentSignature(core.ConvertToPaymentMetadata(req.GetPaymentHeader()), signature); err != nil { + return nil, api.NewErrorInvalidArg("payment signature is invalid") + } + if err != nil { + for _, quorumID := range req.QuorumNumbers { + s.metrics.HandleFailedRequest(codes.InvalidArgument.String(), fmt.Sprint(quorumID), len(req.GetData()), "DispersePaidBlob") + } + s.metrics.HandleInvalidArgRpcRequest("DispersePaidBlob") + return nil, api.NewErrorInvalidArg(err.Error()) + } + + paymentHeader := core.PaymentMetadata{ + AccountID: blob.RequestHeader.AccountID, + BinIndex: binIndex, + CumulativePayment: cumulativePayment, + } + reply, err := s.disperseBlob(ctx, blob, "", "DispersePaidBlob", &paymentHeader) + if err != nil { + // Note the DispersePaidBlob already updated metrics for this error. + s.logger.Info("failed to disperse blob", "err", err) + } else { + s.metrics.HandleSuccessfulRpcRequest("DispersePaidBlob") + } + return reply, err +} + +func (s *DispersalServer) GetPaymentState(ctx context.Context, req *pb.GetPaymentStateRequest) (*pb.GetPaymentStateReply, error) { + // validate the signature + if !auth.VerifyAccountSignature(req.AccountId, req.Signature) { + return nil, api.NewErrorInvalidArg("invalid signature") + } + + // on-chain global payment parameters + globalSymbolsPerSecond := s.meterer.ChainPaymentState.GetGlobalSymbolsPerSecond() + minNumSymbols := s.meterer.ChainPaymentState.GetMinNumSymbols() + pricePerSymbol := s.meterer.ChainPaymentState.GetPricePerSymbol() + reservationWindow := s.meterer.ChainPaymentState.GetReservationWindow() + + // off-chain account specific payment state + now := uint64(time.Now().Unix()) + currentBinIndex := meterer.GetBinIndex(now, reservationWindow) + currentBinUsage, nextBinUsage, overflowBinUsage, err := s.meterer.OffchainStore.GetBinUsages(ctx, req.AccountId, currentBinIndex) + if err != nil { + return nil, api.NewErrorNotFound("failed to get active reservation") + } + largestCumulativePayment, err := s.meterer.OffchainStore.GetLargestCumulativePayment(ctx, req.AccountId) + if err != nil { + return nil, api.NewErrorNotFound("failed to get largest cumulative payment") + } + // on-Chain account state + reservation, err := s.meterer.ChainPaymentState.GetActiveReservationByAccount(ctx, req.AccountId) + if err != nil { + return nil, api.NewErrorNotFound("failed to get active reservation") + } + onDemandPayment, err := s.meterer.ChainPaymentState.GetOnDemandPaymentByAccount(ctx, req.AccountId) + if err != nil { + return nil, api.NewErrorNotFound("failed to get on-demand payment") + } + + paymentGlobalParams := pb.PaymentGlobalParams{ + GlobalSymbolsPerSecond: globalSymbolsPerSecond, + MinNumSymbols: minNumSymbols, + PricePerSymbol: pricePerSymbol, + ReservationWindow: reservationWindow, + } + + quorumNumbers := make([]uint32, len(reservation.QuorumNumbers)) + for i, v := range reservation.QuorumNumbers { + quorumNumbers[i] = uint32(v) + } + // build reply + reply := &pb.GetPaymentStateReply{ + PaymentGlobalParams: &paymentGlobalParams, + CurrentBinUsage: uint32(currentBinUsage), + NextBinUsage: uint32(nextBinUsage), + OverflowBinUsage: uint32(overflowBinUsage), + Reservation: &pb.Reservation{ + SymbolsPerSecond: reservation.SymbolsPerSec, + StartTimestamp: uint32(reservation.StartTimestamp), + EndTimestamp: uint32(reservation.EndTimestamp), + QuorumNumbers: quorumNumbers, + }, + CumulativePayment: largestCumulativePayment.Bytes(), + OnChainCumulativePayment: onDemandPayment.CumulativePayment.Bytes(), + } + return reply, nil +} + func (s *DispersalServer) getAccountRate(origin, authenticatedAddress string, quorumID core.QuorumID) (*PerUserRateInfo, string, error) { unauthRates, ok := s.rateConfig.QuorumRateInfos[quorumID] if !ok { @@ -1072,3 +1167,97 @@ func contextError(err error) error { return nil } + +// TODO: refactor checks with validateRequestAndGetBlob; most checks are the same, but paid requests have different quorum requirements +func (s *DispersalServer) validatePaidRequestAndGetBlob(ctx context.Context, req *pb.DispersePaidBlobRequest) (*core.Blob, error) { + + data := req.GetData() + blobSize := len(data) + // The blob size in bytes must be in range [1, maxBlobSize]. + if blobSize > s.maxBlobSize { + return nil, fmt.Errorf("blob size cannot exceed %v Bytes", s.maxBlobSize) + } + if blobSize == 0 { + return nil, fmt.Errorf("blob size must be greater than 0") + } + + if len(req.GetQuorumNumbers()) > 256 { + return nil, errors.New("number of custom_quorum_numbers must not exceed 256") + } + + // validate every 32 bytes is a valid field element + _, err := rs.ToFrArray(data) + if err != nil { + s.logger.Error("failed to convert a 32bytes as a field element", "err", err) + return nil, api.NewErrorInvalidArg(fmt.Sprintf("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: %v", err)) + } + + quorumConfig, err := s.updateQuorumConfig(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get quorum config: %w", err) + } + + if len(req.GetQuorumNumbers()) > int(quorumConfig.QuorumCount) { + return nil, errors.New("number of custom_quorum_numbers must not exceed number of quorums") + } + + seenQuorums := make(map[uint8]struct{}) + + // TODO: validate payment signature against payment metadata + if err = auth.VerifyPaymentSignature(core.ConvertToPaymentMetadata(req.GetPaymentHeader()), req.GetPaymentSignature()); err != nil { + return nil, fmt.Errorf("payment signature is invalid: %w", err) + } + // Unlike regular blob dispersal request validation, there's no check with required quorums + // Because Reservation has their specific quorum requirements, and on-demand is only allowed and paid to the required quorums. + // Payment specific validations are done within the meterer library. + for i := range req.GetQuorumNumbers() { + + if req.GetQuorumNumbers()[i] > core.MaxQuorumID { + return nil, fmt.Errorf("custom_quorum_numbers must be in range [0, 254], but found %d", req.GetQuorumNumbers()[i]) + } + + quorumID := uint8(req.GetQuorumNumbers()[i]) + if quorumID >= quorumConfig.QuorumCount { + return nil, fmt.Errorf("custom_quorum_numbers must be in range [0, %d], but found %d", s.quorumConfig.QuorumCount-1, quorumID) + } + + if _, ok := seenQuorums[quorumID]; ok { + return nil, fmt.Errorf("custom_quorum_numbers must not contain duplicates") + } + seenQuorums[quorumID] = struct{}{} + + } + + if len(seenQuorums) == 0 { + return nil, fmt.Errorf("the blob must be sent to at least one quorum") + } + + params := make([]*core.SecurityParam, len(seenQuorums)) + i := 0 + for quorumID := range seenQuorums { + params[i] = &core.SecurityParam{ + QuorumID: core.QuorumID(quorumID), + AdversaryThreshold: quorumConfig.SecurityParams[quorumID].AdversaryThreshold, + ConfirmationThreshold: quorumConfig.SecurityParams[quorumID].ConfirmationThreshold, + } + err = params[i].Validate() + if err != nil { + return nil, fmt.Errorf("invalid request: %w", err) + } + i++ + } + + header := core.BlobRequestHeader{ + BlobAuthHeader: core.BlobAuthHeader{ + AccountID: req.PaymentHeader.AccountId, + }, + SecurityParams: params, + } + + blob := &core.Blob{ + RequestHeader: header, + Data: data, + } + + return blob, nil +} diff --git a/inabox/tests/ratelimit_test.go b/inabox/tests/ratelimit_test.go index f3972fc81..c492d15b9 100644 --- a/inabox/tests/ratelimit_test.go +++ b/inabox/tests/ratelimit_test.go @@ -11,6 +11,7 @@ import ( grpcdisperser "github.com/Layr-Labs/eigenda/api/grpc/disperser" "github.com/Layr-Labs/eigenda/api/grpc/retriever" "github.com/Layr-Labs/eigenda/core" + "github.com/Layr-Labs/eigenda/core/auth" "github.com/Layr-Labs/eigenda/disperser" "github.com/Layr-Labs/eigenda/inabox/deploy" "github.com/stretchr/testify/assert" @@ -107,11 +108,12 @@ func testRatelimit(t *testing.T, testConfig *deploy.Config, c ratelimitTestCase) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() + noopPaymentSigner := auth.NewNoopPaymentSigner() disp, err := clients.NewDisperserClient(&clients.Config{ Hostname: "localhost", Port: testConfig.Dispersers[0].DISPERSER_SERVER_GRPC_PORT, Timeout: 10 * time.Second, - }, nil) + }, nil, noopPaymentSigner) assert.NoError(t, err) assert.NotNil(t, disp) From a71ff3a1c8547b6d9dc0d9ee83d23799200037d5 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 15 Nov 2024 00:57:47 -0800 Subject: [PATCH 02/18] feat: disperser api v2 payment --- api/proto/disperser/disperser.proto | 50 ----------------------- api/proto/disperser/v2/disperser_v2.proto | 44 ++++++++++++++++++++ disperser/apiserver/disperse_blob_v2.go | 28 ++++++++++++- disperser/apiserver/server.go | 17 ++++++-- disperser/apiserver/server_v2.go | 2 + inabox/tests/integration_test.go | 4 +- 6 files changed, 90 insertions(+), 55 deletions(-) diff --git a/api/proto/disperser/disperser.proto b/api/proto/disperser/disperser.proto index b9d5c01fe..f4bfa1384 100644 --- a/api/proto/disperser/disperser.proto +++ b/api/proto/disperser/disperser.proto @@ -27,12 +27,6 @@ service Disperser { // 4. The Disperser verifies the signature and returns a DisperseBlobReply message. rpc DisperseBlobAuthenticated(stream AuthenticatedRequest) returns (stream AuthenticatedReply); - // This API require valid payments to accept blob to disperse from clients. - // This executes the dispersal async, i.e. it returns once the request - // is accepted. The client could use GetBlobStatus() API to poll the the - // processing status of the blob. - rpc DispersePaidBlob(DispersePaidBlobRequest) returns (DisperseBlobReply) {} - // This API is meant to be polled for the blob status. rpc GetBlobStatus(BlobStatusRequest) returns (BlobStatusReply) {} @@ -43,9 +37,6 @@ service Disperser { // The blob should have been initially dispersed via this Disperser service // for this API to work. rpc RetrieveBlob(RetrieveBlobRequest) returns (RetrieveBlobReply) {} - - // This API is used to query the payment state of a given account. - rpc GetPaymentState(GetPaymentStateRequest) returns (GetPaymentStateReply) {} } // Requests and Responses @@ -151,26 +142,6 @@ message RetrieveBlobReply { bytes data = 1; } -// GetPaymentStateRequest contains parameters to query the payment state of an account. -message GetPaymentStateRequest { - string account_id = 1; - bytes signature = 2; -} - -// GetPaymentStateReply contains the payment state of an account. -message GetPaymentStateReply { - // global payment vault parameters - PaymentGlobalParams payment_global_params = 1; - // off-chain account reservation usage records - repeated BinRecord bin_records = 2; - // on-chain account reservation setting - Reservation reservation = 3; - // off-chain on-demand payment usage - bytes cumulative_payment = 4; - // on-chain on-demand payment deposited - bytes on_chain_cumulative_payment = 5; -} - // Data Types // BlobStatus represents the status of a blob. @@ -301,24 +272,3 @@ message BatchHeader { // (e.g. operator stakes) at this block number. uint32 reference_block_number = 4; } - -message PaymentGlobalParams { - uint64 global_symbols_per_second = 1; - uint32 min_num_symbols = 2; - uint32 price_per_symbol = 3; - uint32 reservation_window = 4; - repeated uint32 on_demand_quorum_numbers = 5; -} - -message Reservation { - uint64 symbols_per_second = 1; - uint32 start_timestamp = 2; - uint32 end_timestamp = 3; - repeated uint32 quorum_numbers = 4; - repeated uint32 quorum_split = 5; -} - -message BinRecord { - uint32 index = 1; - uint64 usage = 2; -} diff --git a/api/proto/disperser/v2/disperser_v2.proto b/api/proto/disperser/v2/disperser_v2.proto index c6e4388e1..5a5ce1784 100644 --- a/api/proto/disperser/v2/disperser_v2.proto +++ b/api/proto/disperser/v2/disperser_v2.proto @@ -19,6 +19,9 @@ service Disperser { // GetBlobCommitment is a utility method that calculates commitment for a blob payload. rpc GetBlobCommitment(BlobCommitmentRequest) returns (BlobCommitmentReply) {} + + // GetPaymentState is a utility method to get the payment state of a given account. + rpc GetPaymentState(GetPaymentStateRequest) returns (GetPaymentStateReply) {} } // Requests and Replys @@ -63,6 +66,26 @@ message BlobCommitmentReply { common.BlobCommitment blob_commitment = 1; } +// GetPaymentStateRequest contains parameters to query the payment state of an account. +message GetPaymentStateRequest { + string account_id = 1; + bytes signature = 2; +} + +// GetPaymentStateReply contains the payment state of an account. +message GetPaymentStateReply { + // global payment vault parameters + PaymentGlobalParams payment_global_params = 1; + // off-chain account reservation usage records + repeated BinRecord bin_records = 2; + // on-chain account reservation setting + Reservation reservation = 3; + // off-chain on-demand payment usage + bytes cumulative_payment = 4; + // on-chain on-demand payment deposited + bytes on_chain_cumulative_payment = 5; +} + // Data Types // BlobStatus represents the status of a blob. @@ -125,3 +148,24 @@ message Attestation { // Relevant quorum numbers for the attestation repeated uint32 quorum_numbers = 5; } + +message PaymentGlobalParams { + uint64 global_symbols_per_second = 1; + uint32 min_num_symbols = 2; + uint32 price_per_symbol = 3; + uint32 reservation_window = 4; + repeated uint32 on_demand_quorum_numbers = 5; +} + +message Reservation { + uint64 symbols_per_second = 1; + uint32 start_timestamp = 2; + uint32 end_timestamp = 3; + repeated uint32 quorum_numbers = 4; + repeated uint32 quorum_split = 5; +} + +message BinRecord { + uint32 index = 1; + uint64 usage = 2; +} diff --git a/disperser/apiserver/disperse_blob_v2.go b/disperser/apiserver/disperse_blob_v2.go index 05034122c..a56e6ca93 100644 --- a/disperser/apiserver/disperse_blob_v2.go +++ b/disperser/apiserver/disperse_blob_v2.go @@ -3,10 +3,13 @@ package apiserver import ( "context" "fmt" + "math/big" "time" "github.com/Layr-Labs/eigenda/api" pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" + "github.com/Layr-Labs/eigenda/core" + "github.com/Layr-Labs/eigenda/core/auth" corev2 "github.com/Layr-Labs/eigenda/core/v2" dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2" "github.com/Layr-Labs/eigenda/encoding" @@ -30,7 +33,30 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl } s.logger.Debug("received a new blob dispersal request", "blobSizeBytes", len(data), "quorums", req.GetBlobHeader().GetQuorumNumbers()) - // TODO(ian-shim): handle payments and check rate limits + // handle payments and check rate limits + if req.GetBlobHeader().GetPaymentHeader() != nil { + binIndex := req.GetBlobHeader().GetPaymentHeader().GetBinIndex() + cumulativePayment := new(big.Int).SetBytes(req.GetBlobHeader().GetPaymentHeader().GetCumulativePayment()) + signature := req.GetBlobHeader().GetSignature() + if err := auth.VerifyPaymentSignature(core.ConvertToPaymentMetadata(req.GetBlobHeader().GetPaymentHeader()), signature); err != nil { + return nil, api.NewErrorInvalidArg("payment signature is invalid") + } + + paymentHeader := core.PaymentMetadata{ + AccountID: req.GetBlobHeader().GetPaymentHeader().GetAccountId(), + BinIndex: binIndex, + CumulativePayment: cumulativePayment, + } + + blobLength := encoding.GetBlobLength(uint(len(data))) + err := s.meterer.MeterRequest(ctx, paymentHeader, blobLength, blobHeader.QuorumNumbers) + if err != nil { + return nil, api.NewErrorResourceExhausted(err.Error()) + } + } else { + // Q: do we want a seprate check to use original rate limiter if there's no payment attached? + return nil, api.NewErrorInvalidArg("payment header is required") + } blobKey, err := s.StoreBlob(ctx, data, blobHeader, time.Now(), onchainState.TTL) if err != nil { diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index c9bc58a2e..57d86aab3 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -405,9 +405,20 @@ func (s *DispersalServer) GetPaymentState(ctx context.Context, req *pb.GetPaymen // build reply reply := &pb.GetPaymentStateReply{ PaymentGlobalParams: &paymentGlobalParams, - CurrentBinUsage: uint32(currentBinUsage), - NextBinUsage: uint32(nextBinUsage), - OverflowBinUsage: uint32(overflowBinUsage), + BinRecords: []*pb.BinRecord{ + { + Index: uint32(currentBinIndex), + Usage: uint64(currentBinUsage), + }, + { + Index: uint32(currentBinIndex + 1), + Usage: uint64(nextBinUsage), + }, + { + Index: uint32(currentBinIndex + 2), + Usage: uint64(overflowBinUsage), + }, + }, Reservation: &pb.Reservation{ SymbolsPerSecond: reservation.SymbolsPerSec, StartTimestamp: uint32(reservation.StartTimestamp), diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index acf85b054..e328127ec 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -14,6 +14,7 @@ import ( "github.com/Layr-Labs/eigenda/common" healthcheck "github.com/Layr-Labs/eigenda/common/healthcheck" "github.com/Layr-Labs/eigenda/core" + "github.com/Layr-Labs/eigenda/core/meterer" corev2 "github.com/Layr-Labs/eigenda/core/v2" v2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/disperser" @@ -37,6 +38,7 @@ type DispersalServerV2 struct { serverConfig disperser.ServerConfig blobStore *blobstore.BlobStore blobMetadataStore *blobstore.BlobMetadataStore + meterer *meterer.Meterer chainReader core.Reader authenticator corev2.BlobRequestAuthenticator diff --git a/inabox/tests/integration_test.go b/inabox/tests/integration_test.go index 36cedebe4..7b17bc9e5 100644 --- a/inabox/tests/integration_test.go +++ b/inabox/tests/integration_test.go @@ -35,12 +35,14 @@ var _ = Describe("Inabox Integration", func() { privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcded" signer := auth.NewLocalBlobRequestSigner(privateKeyHex) + paymentSigner, err := auth.NewPaymentSigner(privateKeyHex) + Expect(err).To(BeNil()) disp, err := clients.NewDisperserClient(&clients.Config{ Hostname: "localhost", Port: "32003", Timeout: 10 * time.Second, - }, signer) + }, signer, paymentSigner) Expect(err).To(BeNil()) Expect(disp).To(Not(BeNil())) From f50af66848c7b11f18f76a7a854d1f8de41f0aad Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 15 Nov 2024 01:16:45 -0800 Subject: [PATCH 03/18] fix: precise uint64->big.Int conversion --- core/meterer/offchain_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/meterer/offchain_store.go b/core/meterer/offchain_store.go index 0a5f425d5..29686ebd2 100644 --- a/core/meterer/offchain_store.go +++ b/core/meterer/offchain_store.go @@ -292,7 +292,7 @@ func (s *OffchainStore) GetLargestCumulativePayment(ctx context.Context, account return nil, fmt.Errorf("failed to parse payment: %w", err) } - return big.NewInt(int64(payment)), nil + return new(big.Int).SetUint64(payment), nil } func parseBinUsage(bin map[string]types.AttributeValue) (uint64, error) { From 1652b300bb6316acf033be3a6c7a71f218ae6f87 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 15 Nov 2024 02:07:07 -0800 Subject: [PATCH 04/18] fix: rm v1 payment api, add paymentState to v2 --- api/clients/accountant.go | 12 +- api/clients/disperser_client.go | 104 --- api/clients/eigenda_client.go | 9 +- api/grpc/disperser/disperser.pb.go | 821 ++++-------------- api/grpc/disperser/disperser_grpc.pb.go | 84 -- api/grpc/disperser/v2/disperser_v2.pb.go | 697 ++++++++++++--- api/grpc/disperser/v2/disperser_v2_grpc.pb.go | 39 + disperser/apiserver/server.go | 200 ----- disperser/apiserver/server_v2.go | 74 ++ tools/traffic/generator.go | 2 +- tools/traffic/generator_v2.go | 3 +- 11 files changed, 883 insertions(+), 1162 deletions(-) diff --git a/api/clients/accountant.go b/api/clients/accountant.go index 4b8b06967..bcd0b2d24 100644 --- a/api/clients/accountant.go +++ b/api/clients/accountant.go @@ -9,7 +9,7 @@ import ( "time" commonpb "github.com/Layr-Labs/eigenda/api/grpc/common" - disperser_rpc "github.com/Layr-Labs/eigenda/api/grpc/disperser" + disperser_v2_rpc "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/core/meterer" ) @@ -19,8 +19,8 @@ var requiredQuorums = []uint8{0, 1} type Accountant interface { AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, []byte, error) - AuthenticatePaymentStateRequest() (*disperser_rpc.GetPaymentStateRequest, error) - SetPaymentState(paymentState *disperser_rpc.GetPaymentStateReply) + AuthenticatePaymentStateRequest() (*disperser_v2_rpc.GetPaymentStateRequest, error) + SetPaymentState(paymentState *disperser_v2_rpc.GetPaymentStateReply) } var _ Accountant = &accountant{} @@ -182,7 +182,7 @@ func QuorumCheck(quorumNumbers []uint8, allowedNumbers []uint8) error { return nil } -func (a *accountant) SetPaymentState(paymentState *disperser_rpc.GetPaymentStateReply) { +func (a *accountant) SetPaymentState(paymentState *disperser_v2_rpc.GetPaymentStateReply) { quorumNumbers := make([]uint8, len(paymentState.Reservation.QuorumNumbers)) for i, quorum := range paymentState.Reservation.QuorumNumbers { quorumNumbers[i] = uint8(quorum) @@ -213,7 +213,7 @@ func (a *accountant) SetPaymentState(paymentState *disperser_rpc.GetPaymentState a.reservation.EndTimestamp = uint64(paymentState.Reservation.EndTimestamp) } -func (a *accountant) AuthenticatePaymentStateRequest() (*disperser_rpc.GetPaymentStateRequest, error) { +func (a *accountant) AuthenticatePaymentStateRequest() (*disperser_v2_rpc.GetPaymentStateRequest, error) { accountID := a.paymentSigner.GetAccountID() signature, err := a.paymentSigner.SignAccountID(accountID) @@ -221,7 +221,7 @@ func (a *accountant) AuthenticatePaymentStateRequest() (*disperser_rpc.GetPaymen return nil, err } - request := &disperser_rpc.GetPaymentStateRequest{ + request := &disperser_v2_rpc.GetPaymentStateRequest{ AccountId: accountID, Signature: signature, } diff --git a/api/clients/disperser_client.go b/api/clients/disperser_client.go index ff508d05e..2db937777 100644 --- a/api/clients/disperser_client.go +++ b/api/clients/disperser_client.go @@ -3,7 +3,6 @@ package clients import ( "context" "crypto/tls" - "errors" "fmt" "sync" "time" @@ -55,10 +54,8 @@ type DisperserClient interface { // DisperseBlobAuthenticated disperses a blob with an authenticated request. // The BlobStatus returned will always be PROCESSSING if error is nil. DisperseBlobAuthenticated(ctx context.Context, data []byte, customQuorums []uint8) (*disperser.BlobStatus, []byte, error) - DispersePaidBlob(ctx context.Context, data []byte, customQuorums []uint8) (*disperser.BlobStatus, []byte, error) GetBlobStatus(ctx context.Context, key []byte) (*disperser_rpc.BlobStatusReply, error) RetrieveBlob(ctx context.Context, batchHeaderHash []byte, blobIndex uint32) ([]byte, error) - InitializePaymentState(ctx context.Context) error } // See the NewDisperserClient constructor's documentation for details and usage examples. @@ -190,59 +187,6 @@ func (c *disperserClient) DisperseBlob(ctx context.Context, data []byte, quorums return blobStatus, reply.GetRequestId(), nil } -// DispersePaidBlob disperses a blob with a payment header and signature. Similar to DisperseBlob but with signed payment header. -func (c *disperserClient) DispersePaidBlob(ctx context.Context, data []byte, quorums []uint8) (*disperser.BlobStatus, []byte, error) { - if c.accountant == nil { - return nil, nil, api.NewErrorInternal("not implemented") - } - - err := c.initOnceGrpcConnection() - if err != nil { - return nil, nil, fmt.Errorf("error initializing connection: %w", err) - } - - ctxTimeout, cancel := context.WithTimeout(ctx, c.config.Timeout) - defer cancel() - - quorumNumbers := make([]uint32, len(quorums)) - for i, q := range quorums { - quorumNumbers[i] = uint32(q) - } - - // check every 32 bytes of data are within the valid range for a bn254 field element - _, err = rs.ToFrArray(data) - if err != nil { - return nil, nil, fmt.Errorf("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 %w", err) - } - - header, signature, err := c.accountant.AccountBlob(ctx, uint64(encoding.GetBlobLength(uint(len(data)))), quorums) - if header == nil { - return nil, nil, errors.New("accountant returned nil pointer to header") - } - if err != nil { - return nil, nil, err - } - - request := &disperser_rpc.DispersePaidBlobRequest{ - Data: data, - QuorumNumbers: quorumNumbers, - PaymentHeader: header, - PaymentSignature: signature, - } - - reply, err := c.client.DispersePaidBlob(ctxTimeout, request) - if err != nil { - return nil, nil, err - } - - blobStatus, err := disperser.FromBlobStatusProto(reply.GetResult()) - if err != nil { - return nil, nil, err - } - - return blobStatus, reply.GetRequestId(), nil -} - func (c *disperserClient) DisperseBlobAuthenticated(ctx context.Context, data []byte, quorums []uint8) (*disperser.BlobStatus, []byte, error) { err := c.initOnceGrpcConnection() if err != nil { @@ -384,54 +328,6 @@ func (c *disperserClient) RetrieveBlob(ctx context.Context, batchHeaderHash []by return reply.Data, nil } -func (c *disperserClient) getPaymentState(ctx context.Context) (*disperser_rpc.GetPaymentStateReply, error) { - err := c.initOnceGrpcConnection() - if err != nil { - return nil, fmt.Errorf("error initializing connection: %w", err) - } - - ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*60) - defer cancel() - - request, err := c.accountant.AuthenticatePaymentStateRequest() - if err != nil { - return nil, err - } - reply, err := c.client.GetPaymentState(ctxTimeout, request) - if err != nil { - return nil, err - } - - return reply, nil -} - -func (c *disperserClient) InitializePaymentState(ctx context.Context) error { - paymentState, err := c.getPaymentState(ctx) - if err != nil { - return fmt.Errorf("error getting payment state from disperser: %w", err) - } - c.accountant.SetPaymentState(paymentState) - // c.accountant.binUsages = []uint64{uint64(paymentState.CurrentBinUsage), uint64(paymentState.NextBinUsage), uint64(paymentState.OverflowBinUsage)} - // c.accountant.cumulativePayment = new(big.Int).SetBytes(paymentState.CumulativePayment) - // quorumNumbers := make([]uint8, len(paymentState.Reservation.QuorumNumbers)) - // for i, q := range paymentState.Reservation.QuorumNumbers { - // quorumNumbers[i] = uint8(q) - // } - // c.accountant.reservation = core.ActiveReservation{ - // StartTimestamp: uint64(paymentState.Reservation.StartTimestamp), - // EndTimestamp: uint64(paymentState.Reservation.EndTimestamp), - // SymbolsPerSec: paymentState.Reservation.SymbolsPerSecond, - // QuorumNumbers: quorumNumbers, - // } - // c.accountant.onDemand = core.OnDemandPayment{ - // CumulativePayment: new(big.Int).SetBytes(paymentState.OnChainCumulativePayment), - // } - // c.accountant.reservationWindow = paymentState.PaymentGlobalParams.ReservationWindow - // c.accountant.pricePerSymbol = paymentState.PaymentGlobalParams.PricePerSymbol - // c.accountant.minNumSymbols = paymentState.PaymentGlobalParams.MinNumSymbols - return nil -} - // initOnceGrpcConnection initializes the grpc connection and client if they are not already initialized. // If initialization fails, it caches the error and will return it on every subsequent call. func (c *disperserClient) initOnceGrpcConnection() error { diff --git a/api/clients/eigenda_client.go b/api/clients/eigenda_client.go index 6560be474..d07b033ba 100644 --- a/api/clients/eigenda_client.go +++ b/api/clients/eigenda_client.go @@ -120,10 +120,11 @@ func NewEigenDAClient(log log.Logger, config EigenDAClientConfig) (*EigenDAClien if err != nil { return nil, fmt.Errorf("new disperser-client: %w", err) } - err = disperserClient.InitializePaymentState(context.Background()) - if err != nil { - return nil, fmt.Errorf("error setting payment state: %w", err) - } + // TODO: uncomment this when we are using disperser client v2 + // err = disperserClient.InitializePaymentState(context.Background()) + // if err != nil { + // return nil, fmt.Errorf("error setting payment state: %w", err) + // } lowLevelCodec, err := codecs.BlobEncodingVersionToCodec(config.PutBlobEncodingVersion) if err != nil { diff --git a/api/grpc/disperser/disperser.pb.go b/api/grpc/disperser/disperser.pb.go index 5872d6c74..d10d4d736 100644 --- a/api/grpc/disperser/disperser.pb.go +++ b/api/grpc/disperser/disperser.pb.go @@ -797,147 +797,6 @@ func (x *RetrieveBlobReply) GetData() []byte { return nil } -// GetPaymentStateRequest contains parameters to query the payment state of an account. -type GetPaymentStateRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` -} - -func (x *GetPaymentStateRequest) Reset() { - *x = GetPaymentStateRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetPaymentStateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetPaymentStateRequest) ProtoMessage() {} - -func (x *GetPaymentStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetPaymentStateRequest.ProtoReflect.Descriptor instead. -func (*GetPaymentStateRequest) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{11} -} - -func (x *GetPaymentStateRequest) GetAccountId() string { - if x != nil { - return x.AccountId - } - return "" -} - -func (x *GetPaymentStateRequest) GetSignature() []byte { - if x != nil { - return x.Signature - } - return nil -} - -// GetPaymentStateReply contains the payment state of an account. -type GetPaymentStateReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // global payment vault parameters - PaymentGlobalParams *PaymentGlobalParams `protobuf:"bytes,1,opt,name=payment_global_params,json=paymentGlobalParams,proto3" json:"payment_global_params,omitempty"` - // off-chain account reservation usage records - BinRecords []*BinRecord `protobuf:"bytes,2,rep,name=bin_records,json=binRecords,proto3" json:"bin_records,omitempty"` - // on-chain account reservation setting - Reservation *Reservation `protobuf:"bytes,3,opt,name=reservation,proto3" json:"reservation,omitempty"` - // off-chain on-demand payment usage - CumulativePayment []byte `protobuf:"bytes,4,opt,name=cumulative_payment,json=cumulativePayment,proto3" json:"cumulative_payment,omitempty"` - // on-chain on-demand payment deposited - OnChainCumulativePayment []byte `protobuf:"bytes,5,opt,name=on_chain_cumulative_payment,json=onChainCumulativePayment,proto3" json:"on_chain_cumulative_payment,omitempty"` -} - -func (x *GetPaymentStateReply) Reset() { - *x = GetPaymentStateReply{} - if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetPaymentStateReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetPaymentStateReply) ProtoMessage() {} - -func (x *GetPaymentStateReply) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetPaymentStateReply.ProtoReflect.Descriptor instead. -func (*GetPaymentStateReply) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{12} -} - -func (x *GetPaymentStateReply) GetPaymentGlobalParams() *PaymentGlobalParams { - if x != nil { - return x.PaymentGlobalParams - } - return nil -} - -func (x *GetPaymentStateReply) GetBinRecords() []*BinRecord { - if x != nil { - return x.BinRecords - } - return nil -} - -func (x *GetPaymentStateReply) GetReservation() *Reservation { - if x != nil { - return x.Reservation - } - return nil -} - -func (x *GetPaymentStateReply) GetCumulativePayment() []byte { - if x != nil { - return x.CumulativePayment - } - return nil -} - -func (x *GetPaymentStateReply) GetOnChainCumulativePayment() []byte { - if x != nil { - return x.OnChainCumulativePayment - } - return nil -} - // BlobInfo contains information needed to confirm the blob against the EigenDA contracts type BlobInfo struct { state protoimpl.MessageState @@ -951,7 +810,7 @@ type BlobInfo struct { func (x *BlobInfo) Reset() { *x = BlobInfo{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[13] + mi := &file_disperser_disperser_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -964,7 +823,7 @@ func (x *BlobInfo) String() string { func (*BlobInfo) ProtoMessage() {} func (x *BlobInfo) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[13] + mi := &file_disperser_disperser_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -977,7 +836,7 @@ func (x *BlobInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobInfo.ProtoReflect.Descriptor instead. func (*BlobInfo) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{13} + return file_disperser_disperser_proto_rawDescGZIP(), []int{11} } func (x *BlobInfo) GetBlobHeader() *BlobHeader { @@ -1010,7 +869,7 @@ type BlobHeader struct { func (x *BlobHeader) Reset() { *x = BlobHeader{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[14] + mi := &file_disperser_disperser_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1023,7 +882,7 @@ func (x *BlobHeader) String() string { func (*BlobHeader) ProtoMessage() {} func (x *BlobHeader) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[14] + mi := &file_disperser_disperser_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1036,7 +895,7 @@ func (x *BlobHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobHeader.ProtoReflect.Descriptor instead. func (*BlobHeader) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{14} + return file_disperser_disperser_proto_rawDescGZIP(), []int{12} } func (x *BlobHeader) GetCommitment() *common.G1Commitment { @@ -1081,7 +940,7 @@ type BlobQuorumParam struct { func (x *BlobQuorumParam) Reset() { *x = BlobQuorumParam{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[15] + mi := &file_disperser_disperser_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1094,7 +953,7 @@ func (x *BlobQuorumParam) String() string { func (*BlobQuorumParam) ProtoMessage() {} func (x *BlobQuorumParam) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[15] + mi := &file_disperser_disperser_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1107,7 +966,7 @@ func (x *BlobQuorumParam) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobQuorumParam.ProtoReflect.Descriptor instead. func (*BlobQuorumParam) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{15} + return file_disperser_disperser_proto_rawDescGZIP(), []int{13} } func (x *BlobQuorumParam) GetQuorumNumber() uint32 { @@ -1175,7 +1034,7 @@ type BlobVerificationProof struct { func (x *BlobVerificationProof) Reset() { *x = BlobVerificationProof{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[16] + mi := &file_disperser_disperser_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1188,7 +1047,7 @@ func (x *BlobVerificationProof) String() string { func (*BlobVerificationProof) ProtoMessage() {} func (x *BlobVerificationProof) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[16] + mi := &file_disperser_disperser_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1201,7 +1060,7 @@ func (x *BlobVerificationProof) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobVerificationProof.ProtoReflect.Descriptor instead. func (*BlobVerificationProof) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{16} + return file_disperser_disperser_proto_rawDescGZIP(), []int{14} } func (x *BlobVerificationProof) GetBatchId() uint32 { @@ -1261,7 +1120,7 @@ type BatchMetadata struct { func (x *BatchMetadata) Reset() { *x = BatchMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[17] + mi := &file_disperser_disperser_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1274,7 +1133,7 @@ func (x *BatchMetadata) String() string { func (*BatchMetadata) ProtoMessage() {} func (x *BatchMetadata) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[17] + mi := &file_disperser_disperser_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1287,7 +1146,7 @@ func (x *BatchMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchMetadata.ProtoReflect.Descriptor instead. func (*BatchMetadata) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{17} + return file_disperser_disperser_proto_rawDescGZIP(), []int{15} } func (x *BatchMetadata) GetBatchHeader() *BatchHeader { @@ -1347,7 +1206,7 @@ type BatchHeader struct { func (x *BatchHeader) Reset() { *x = BatchHeader{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[18] + mi := &file_disperser_disperser_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1360,7 +1219,7 @@ func (x *BatchHeader) String() string { func (*BatchHeader) ProtoMessage() {} func (x *BatchHeader) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[18] + mi := &file_disperser_disperser_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1373,7 +1232,7 @@ func (x *BatchHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchHeader.ProtoReflect.Descriptor instead. func (*BatchHeader) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{18} + return file_disperser_disperser_proto_rawDescGZIP(), []int{16} } func (x *BatchHeader) GetBatchRoot() []byte { @@ -1404,219 +1263,6 @@ func (x *BatchHeader) GetReferenceBlockNumber() uint32 { return 0 } -type PaymentGlobalParams struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - GlobalSymbolsPerSecond uint64 `protobuf:"varint,1,opt,name=global_symbols_per_second,json=globalSymbolsPerSecond,proto3" json:"global_symbols_per_second,omitempty"` - MinNumSymbols uint32 `protobuf:"varint,2,opt,name=min_num_symbols,json=minNumSymbols,proto3" json:"min_num_symbols,omitempty"` - PricePerSymbol uint32 `protobuf:"varint,3,opt,name=price_per_symbol,json=pricePerSymbol,proto3" json:"price_per_symbol,omitempty"` - ReservationWindow uint32 `protobuf:"varint,4,opt,name=reservation_window,json=reservationWindow,proto3" json:"reservation_window,omitempty"` - OnDemandQuorumNumbers []uint32 `protobuf:"varint,5,rep,packed,name=on_demand_quorum_numbers,json=onDemandQuorumNumbers,proto3" json:"on_demand_quorum_numbers,omitempty"` -} - -func (x *PaymentGlobalParams) Reset() { - *x = PaymentGlobalParams{} - if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PaymentGlobalParams) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PaymentGlobalParams) ProtoMessage() {} - -func (x *PaymentGlobalParams) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PaymentGlobalParams.ProtoReflect.Descriptor instead. -func (*PaymentGlobalParams) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{19} -} - -func (x *PaymentGlobalParams) GetGlobalSymbolsPerSecond() uint64 { - if x != nil { - return x.GlobalSymbolsPerSecond - } - return 0 -} - -func (x *PaymentGlobalParams) GetMinNumSymbols() uint32 { - if x != nil { - return x.MinNumSymbols - } - return 0 -} - -func (x *PaymentGlobalParams) GetPricePerSymbol() uint32 { - if x != nil { - return x.PricePerSymbol - } - return 0 -} - -func (x *PaymentGlobalParams) GetReservationWindow() uint32 { - if x != nil { - return x.ReservationWindow - } - return 0 -} - -func (x *PaymentGlobalParams) GetOnDemandQuorumNumbers() []uint32 { - if x != nil { - return x.OnDemandQuorumNumbers - } - return nil -} - -type Reservation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SymbolsPerSecond uint64 `protobuf:"varint,1,opt,name=symbols_per_second,json=symbolsPerSecond,proto3" json:"symbols_per_second,omitempty"` - StartTimestamp uint32 `protobuf:"varint,2,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"` - EndTimestamp uint32 `protobuf:"varint,3,opt,name=end_timestamp,json=endTimestamp,proto3" json:"end_timestamp,omitempty"` - QuorumNumbers []uint32 `protobuf:"varint,4,rep,packed,name=quorum_numbers,json=quorumNumbers,proto3" json:"quorum_numbers,omitempty"` - QuorumSplit []uint32 `protobuf:"varint,5,rep,packed,name=quorum_split,json=quorumSplit,proto3" json:"quorum_split,omitempty"` -} - -func (x *Reservation) Reset() { - *x = Reservation{} - if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Reservation) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Reservation) ProtoMessage() {} - -func (x *Reservation) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Reservation.ProtoReflect.Descriptor instead. -func (*Reservation) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{20} -} - -func (x *Reservation) GetSymbolsPerSecond() uint64 { - if x != nil { - return x.SymbolsPerSecond - } - return 0 -} - -func (x *Reservation) GetStartTimestamp() uint32 { - if x != nil { - return x.StartTimestamp - } - return 0 -} - -func (x *Reservation) GetEndTimestamp() uint32 { - if x != nil { - return x.EndTimestamp - } - return 0 -} - -func (x *Reservation) GetQuorumNumbers() []uint32 { - if x != nil { - return x.QuorumNumbers - } - return nil -} - -func (x *Reservation) GetQuorumSplit() []uint32 { - if x != nil { - return x.QuorumSplit - } - return nil -} - -type BinRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Index uint32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` - Usage uint64 `protobuf:"varint,2,opt,name=usage,proto3" json:"usage,omitempty"` -} - -func (x *BinRecord) Reset() { - *x = BinRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_disperser_disperser_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BinRecord) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BinRecord) ProtoMessage() {} - -func (x *BinRecord) ProtoReflect() protoreflect.Message { - mi := &file_disperser_disperser_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BinRecord.ProtoReflect.Descriptor instead. -func (*BinRecord) Descriptor() ([]byte, []int) { - return file_disperser_disperser_proto_rawDescGZIP(), []int{21} -} - -func (x *BinRecord) GetIndex() uint32 { - if x != nil { - return x.Index - } - return 0 -} - -func (x *BinRecord) GetUsage() uint64 { - if x != nil { - return x.Usage - } - return 0 -} - var File_disperser_disperser_proto protoreflect.FileDescriptor var file_disperser_disperser_proto_rawDesc = []byte{ @@ -1700,186 +1346,115 @@ var file_disperser_disperser_proto_rawDesc = []byte{ 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x27, 0x0a, 0x11, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x55, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xc9, 0x02, 0x0a, - 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x52, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x52, 0x13, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x62, 0x69, 0x6e, - 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x69, 0x6e, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x52, 0x0a, 0x62, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x12, 0x38, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x72, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x72, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x75, - 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, - 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x1b, 0x6f, 0x6e, 0x5f, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, - 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, - 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, - 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x9c, 0x01, 0x0a, 0x08, 0x42, 0x6c, 0x6f, - 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x36, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x64, 0x69, 0x73, - 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, - 0x17, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0x52, 0x15, 0x62, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xad, 0x01, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x47, 0x31, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x48, 0x0a, - 0x12, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x64, 0x69, 0x73, 0x70, - 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, - 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x62, - 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x71, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x44, 0x0a, 0x1e, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, 0x5f, 0x74, 0x68, - 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, - 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1c, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, - 0x61, 0x72, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, - 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x21, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, - 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, - 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x1f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, - 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, - 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x4c, - 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xe2, 0x01, 0x0a, 0x15, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, - 0x19, 0x0a, 0x08, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, - 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, - 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3f, 0x0a, 0x0e, 0x62, 0x61, 0x74, - 0x63, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x62, 0x61, 0x74, - 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0c, - 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, - 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, - 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x66, - 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x3a, 0x0a, - 0x19, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x17, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x74, - 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x48, 0x61, 0x73, 0x68, 0x22, 0xc5, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, - 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, - 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x71, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, - 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, - 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x72, 0x63, - 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x8a, 0x02, - 0x0a, 0x13, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, - 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, - 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, - 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x79, 0x6d, 0x62, - 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x4e, 0x75, - 0x6d, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, - 0x6f, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, - 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x71, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0d, 0x52, 0x15, 0x6f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x51, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x52, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, - 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, - 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0d, 0x52, 0x0b, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x70, 0x6c, 0x69, 0x74, - 0x22, 0x37, 0x0a, 0x09, 0x42, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x80, 0x01, 0x0a, 0x0a, 0x42, 0x6c, - 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, 0x53, - 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, - 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, - 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x04, 0x12, - 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, - 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, - 0x44, 0x49, 0x53, 0x50, 0x45, 0x52, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x32, 0x8a, 0x04, 0x0a, - 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0c, 0x44, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x64, 0x69, 0x73, - 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, - 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, - 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, - 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x19, 0x44, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, - 0x73, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x9c, 0x01, 0x0a, 0x08, 0x42, 0x6c, 0x6f, 0x62, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x36, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, + 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0a, + 0x62, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x17, 0x62, 0x6c, + 0x6f, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x64, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x15, 0x62, + 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xad, 0x01, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x47, 0x31, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, + 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x12, 0x62, 0x6c, + 0x6f, 0x62, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, + 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x71, 0x75, 0x6f, 0x72, + 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x44, 0x0a, + 0x1e, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, + 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1c, 0x61, 0x64, 0x76, 0x65, 0x72, 0x73, 0x61, 0x72, 0x79, + 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, + 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x21, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x65, + 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, 0x65, + 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x4c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x22, 0xe2, 0x01, 0x0a, 0x15, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x19, 0x0a, 0x08, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, + 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3f, 0x0a, 0x0e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0c, 0x62, 0x61, 0x74, + 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x79, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x13, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x3a, 0x0a, 0x19, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, + 0x73, 0x68, 0x22, 0xc5, 0x01, 0x0a, 0x0b, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, 0x6f, 0x6f, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x52, 0x6f, 0x6f, + 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, + 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x71, 0x75, 0x6f, 0x72, + 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x71, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, + 0x61, 0x67, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2a, 0x80, 0x01, 0x0a, 0x0a, 0x42, + 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, + 0x53, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, + 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, + 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x04, + 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, + 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x12, 0x0e, 0x0a, + 0x0a, 0x44, 0x49, 0x53, 0x50, 0x45, 0x52, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x32, 0xd9, 0x02, + 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0c, 0x44, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x64, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, + 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, + 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x19, 0x44, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x28, 0x01, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x10, 0x44, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x50, 0x61, 0x69, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x12, - 0x22, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x73, 0x70, - 0x65, 0x72, 0x73, 0x65, 0x50, 0x61, 0x69, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, - 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, - 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x4e, 0x0a, 0x0c, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, - 0x12, 0x1e, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, - 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, - 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x57, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, - 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, - 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x0d, + 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x2e, + 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x64, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0c, 0x52, 0x65, 0x74, + 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x64, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x64, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x42, 0x6c, + 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, @@ -1899,7 +1474,7 @@ func file_disperser_disperser_proto_rawDescGZIP() []byte { } var file_disperser_disperser_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_disperser_disperser_proto_msgTypes = make([]protoimpl.MessageInfo, 22) +var file_disperser_disperser_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_disperser_disperser_proto_goTypes = []interface{}{ (BlobStatus)(0), // 0: disperser.BlobStatus (*AuthenticatedRequest)(nil), // 1: disperser.AuthenticatedRequest @@ -1913,55 +1488,43 @@ var file_disperser_disperser_proto_goTypes = []interface{}{ (*BlobStatusReply)(nil), // 9: disperser.BlobStatusReply (*RetrieveBlobRequest)(nil), // 10: disperser.RetrieveBlobRequest (*RetrieveBlobReply)(nil), // 11: disperser.RetrieveBlobReply - (*GetPaymentStateRequest)(nil), // 12: disperser.GetPaymentStateRequest - (*GetPaymentStateReply)(nil), // 13: disperser.GetPaymentStateReply - (*BlobInfo)(nil), // 14: disperser.BlobInfo - (*BlobHeader)(nil), // 15: disperser.BlobHeader - (*BlobQuorumParam)(nil), // 16: disperser.BlobQuorumParam - (*BlobVerificationProof)(nil), // 17: disperser.BlobVerificationProof - (*BatchMetadata)(nil), // 18: disperser.BatchMetadata - (*BatchHeader)(nil), // 19: disperser.BatchHeader - (*PaymentGlobalParams)(nil), // 20: disperser.PaymentGlobalParams - (*Reservation)(nil), // 21: disperser.Reservation - (*BinRecord)(nil), // 22: disperser.BinRecord - (*common.PaymentHeader)(nil), // 23: common.PaymentHeader - (*common.G1Commitment)(nil), // 24: common.G1Commitment + (*BlobInfo)(nil), // 12: disperser.BlobInfo + (*BlobHeader)(nil), // 13: disperser.BlobHeader + (*BlobQuorumParam)(nil), // 14: disperser.BlobQuorumParam + (*BlobVerificationProof)(nil), // 15: disperser.BlobVerificationProof + (*BatchMetadata)(nil), // 16: disperser.BatchMetadata + (*BatchHeader)(nil), // 17: disperser.BatchHeader + (*common.PaymentHeader)(nil), // 18: common.PaymentHeader + (*common.G1Commitment)(nil), // 19: common.G1Commitment } var file_disperser_disperser_proto_depIdxs = []int32{ 5, // 0: disperser.AuthenticatedRequest.disperse_request:type_name -> disperser.DisperseBlobRequest 4, // 1: disperser.AuthenticatedRequest.authentication_data:type_name -> disperser.AuthenticationData 3, // 2: disperser.AuthenticatedReply.blob_auth_header:type_name -> disperser.BlobAuthHeader 7, // 3: disperser.AuthenticatedReply.disperse_reply:type_name -> disperser.DisperseBlobReply - 23, // 4: disperser.DispersePaidBlobRequest.payment_header:type_name -> common.PaymentHeader + 18, // 4: disperser.DispersePaidBlobRequest.payment_header:type_name -> common.PaymentHeader 0, // 5: disperser.DisperseBlobReply.result:type_name -> disperser.BlobStatus 0, // 6: disperser.BlobStatusReply.status:type_name -> disperser.BlobStatus - 14, // 7: disperser.BlobStatusReply.info:type_name -> disperser.BlobInfo - 20, // 8: disperser.GetPaymentStateReply.payment_global_params:type_name -> disperser.PaymentGlobalParams - 22, // 9: disperser.GetPaymentStateReply.bin_records:type_name -> disperser.BinRecord - 21, // 10: disperser.GetPaymentStateReply.reservation:type_name -> disperser.Reservation - 15, // 11: disperser.BlobInfo.blob_header:type_name -> disperser.BlobHeader - 17, // 12: disperser.BlobInfo.blob_verification_proof:type_name -> disperser.BlobVerificationProof - 24, // 13: disperser.BlobHeader.commitment:type_name -> common.G1Commitment - 16, // 14: disperser.BlobHeader.blob_quorum_params:type_name -> disperser.BlobQuorumParam - 18, // 15: disperser.BlobVerificationProof.batch_metadata:type_name -> disperser.BatchMetadata - 19, // 16: disperser.BatchMetadata.batch_header:type_name -> disperser.BatchHeader - 5, // 17: disperser.Disperser.DisperseBlob:input_type -> disperser.DisperseBlobRequest - 1, // 18: disperser.Disperser.DisperseBlobAuthenticated:input_type -> disperser.AuthenticatedRequest - 6, // 19: disperser.Disperser.DispersePaidBlob:input_type -> disperser.DispersePaidBlobRequest - 8, // 20: disperser.Disperser.GetBlobStatus:input_type -> disperser.BlobStatusRequest - 10, // 21: disperser.Disperser.RetrieveBlob:input_type -> disperser.RetrieveBlobRequest - 12, // 22: disperser.Disperser.GetPaymentState:input_type -> disperser.GetPaymentStateRequest - 7, // 23: disperser.Disperser.DisperseBlob:output_type -> disperser.DisperseBlobReply - 2, // 24: disperser.Disperser.DisperseBlobAuthenticated:output_type -> disperser.AuthenticatedReply - 7, // 25: disperser.Disperser.DispersePaidBlob:output_type -> disperser.DisperseBlobReply - 9, // 26: disperser.Disperser.GetBlobStatus:output_type -> disperser.BlobStatusReply - 11, // 27: disperser.Disperser.RetrieveBlob:output_type -> disperser.RetrieveBlobReply - 13, // 28: disperser.Disperser.GetPaymentState:output_type -> disperser.GetPaymentStateReply - 23, // [23:29] is the sub-list for method output_type - 17, // [17:23] is the sub-list for method input_type - 17, // [17:17] is the sub-list for extension type_name - 17, // [17:17] is the sub-list for extension extendee - 0, // [0:17] is the sub-list for field type_name + 12, // 7: disperser.BlobStatusReply.info:type_name -> disperser.BlobInfo + 13, // 8: disperser.BlobInfo.blob_header:type_name -> disperser.BlobHeader + 15, // 9: disperser.BlobInfo.blob_verification_proof:type_name -> disperser.BlobVerificationProof + 19, // 10: disperser.BlobHeader.commitment:type_name -> common.G1Commitment + 14, // 11: disperser.BlobHeader.blob_quorum_params:type_name -> disperser.BlobQuorumParam + 16, // 12: disperser.BlobVerificationProof.batch_metadata:type_name -> disperser.BatchMetadata + 17, // 13: disperser.BatchMetadata.batch_header:type_name -> disperser.BatchHeader + 5, // 14: disperser.Disperser.DisperseBlob:input_type -> disperser.DisperseBlobRequest + 1, // 15: disperser.Disperser.DisperseBlobAuthenticated:input_type -> disperser.AuthenticatedRequest + 8, // 16: disperser.Disperser.GetBlobStatus:input_type -> disperser.BlobStatusRequest + 10, // 17: disperser.Disperser.RetrieveBlob:input_type -> disperser.RetrieveBlobRequest + 7, // 18: disperser.Disperser.DisperseBlob:output_type -> disperser.DisperseBlobReply + 2, // 19: disperser.Disperser.DisperseBlobAuthenticated:output_type -> disperser.AuthenticatedReply + 9, // 20: disperser.Disperser.GetBlobStatus:output_type -> disperser.BlobStatusReply + 11, // 21: disperser.Disperser.RetrieveBlob:output_type -> disperser.RetrieveBlobReply + 18, // [18:22] is the sub-list for method output_type + 14, // [14:18] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_disperser_disperser_proto_init() } @@ -2103,30 +1666,6 @@ func file_disperser_disperser_proto_init() { } } file_disperser_disperser_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPaymentStateRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_disperser_disperser_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPaymentStateReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_disperser_disperser_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlobInfo); i { case 0: return &v.state @@ -2138,7 +1677,7 @@ func file_disperser_disperser_proto_init() { return nil } } - file_disperser_disperser_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_disperser_disperser_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlobHeader); i { case 0: return &v.state @@ -2150,7 +1689,7 @@ func file_disperser_disperser_proto_init() { return nil } } - file_disperser_disperser_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_disperser_disperser_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlobQuorumParam); i { case 0: return &v.state @@ -2162,7 +1701,7 @@ func file_disperser_disperser_proto_init() { return nil } } - file_disperser_disperser_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_disperser_disperser_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlobVerificationProof); i { case 0: return &v.state @@ -2174,7 +1713,7 @@ func file_disperser_disperser_proto_init() { return nil } } - file_disperser_disperser_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_disperser_disperser_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BatchMetadata); i { case 0: return &v.state @@ -2186,7 +1725,7 @@ func file_disperser_disperser_proto_init() { return nil } } - file_disperser_disperser_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_disperser_disperser_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BatchHeader); i { case 0: return &v.state @@ -2198,42 +1737,6 @@ func file_disperser_disperser_proto_init() { return nil } } - file_disperser_disperser_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PaymentGlobalParams); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_disperser_disperser_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Reservation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_disperser_disperser_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BinRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } file_disperser_disperser_proto_msgTypes[0].OneofWrappers = []interface{}{ (*AuthenticatedRequest_DisperseRequest)(nil), @@ -2249,7 +1752,7 @@ func file_disperser_disperser_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_disperser_disperser_proto_rawDesc, NumEnums: 1, - NumMessages: 22, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/api/grpc/disperser/disperser_grpc.pb.go b/api/grpc/disperser/disperser_grpc.pb.go index d082c3ae8..c6bb719a2 100644 --- a/api/grpc/disperser/disperser_grpc.pb.go +++ b/api/grpc/disperser/disperser_grpc.pb.go @@ -21,10 +21,8 @@ const _ = grpc.SupportPackageIsVersion7 const ( Disperser_DisperseBlob_FullMethodName = "/disperser.Disperser/DisperseBlob" Disperser_DisperseBlobAuthenticated_FullMethodName = "/disperser.Disperser/DisperseBlobAuthenticated" - Disperser_DispersePaidBlob_FullMethodName = "/disperser.Disperser/DispersePaidBlob" Disperser_GetBlobStatus_FullMethodName = "/disperser.Disperser/GetBlobStatus" Disperser_RetrieveBlob_FullMethodName = "/disperser.Disperser/RetrieveBlob" - Disperser_GetPaymentState_FullMethodName = "/disperser.Disperser/GetPaymentState" ) // DisperserClient is the client API for Disperser service. @@ -53,11 +51,6 @@ type DisperserClient interface { // AuthenticationData message. // 4. The Disperser verifies the signature and returns a DisperseBlobReply message. DisperseBlobAuthenticated(ctx context.Context, opts ...grpc.CallOption) (Disperser_DisperseBlobAuthenticatedClient, error) - // This API require valid payments to accept blob to disperse from clients. - // This executes the dispersal async, i.e. it returns once the request - // is accepted. The client could use GetBlobStatus() API to poll the the - // processing status of the blob. - DispersePaidBlob(ctx context.Context, in *DispersePaidBlobRequest, opts ...grpc.CallOption) (*DisperseBlobReply, error) // This API is meant to be polled for the blob status. GetBlobStatus(ctx context.Context, in *BlobStatusRequest, opts ...grpc.CallOption) (*BlobStatusReply, error) // This retrieves the requested blob from the Disperser's backend. @@ -67,8 +60,6 @@ type DisperserClient interface { // The blob should have been initially dispersed via this Disperser service // for this API to work. RetrieveBlob(ctx context.Context, in *RetrieveBlobRequest, opts ...grpc.CallOption) (*RetrieveBlobReply, error) - // This API is used to query the payment state of a given account. - GetPaymentState(ctx context.Context, in *GetPaymentStateRequest, opts ...grpc.CallOption) (*GetPaymentStateReply, error) } type disperserClient struct { @@ -119,15 +110,6 @@ func (x *disperserDisperseBlobAuthenticatedClient) Recv() (*AuthenticatedReply, return m, nil } -func (c *disperserClient) DispersePaidBlob(ctx context.Context, in *DispersePaidBlobRequest, opts ...grpc.CallOption) (*DisperseBlobReply, error) { - out := new(DisperseBlobReply) - err := c.cc.Invoke(ctx, Disperser_DispersePaidBlob_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *disperserClient) GetBlobStatus(ctx context.Context, in *BlobStatusRequest, opts ...grpc.CallOption) (*BlobStatusReply, error) { out := new(BlobStatusReply) err := c.cc.Invoke(ctx, Disperser_GetBlobStatus_FullMethodName, in, out, opts...) @@ -146,15 +128,6 @@ func (c *disperserClient) RetrieveBlob(ctx context.Context, in *RetrieveBlobRequ return out, nil } -func (c *disperserClient) GetPaymentState(ctx context.Context, in *GetPaymentStateRequest, opts ...grpc.CallOption) (*GetPaymentStateReply, error) { - out := new(GetPaymentStateReply) - err := c.cc.Invoke(ctx, Disperser_GetPaymentState_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // DisperserServer is the server API for Disperser service. // All implementations must embed UnimplementedDisperserServer // for forward compatibility @@ -181,11 +154,6 @@ type DisperserServer interface { // AuthenticationData message. // 4. The Disperser verifies the signature and returns a DisperseBlobReply message. DisperseBlobAuthenticated(Disperser_DisperseBlobAuthenticatedServer) error - // This API require valid payments to accept blob to disperse from clients. - // This executes the dispersal async, i.e. it returns once the request - // is accepted. The client could use GetBlobStatus() API to poll the the - // processing status of the blob. - DispersePaidBlob(context.Context, *DispersePaidBlobRequest) (*DisperseBlobReply, error) // This API is meant to be polled for the blob status. GetBlobStatus(context.Context, *BlobStatusRequest) (*BlobStatusReply, error) // This retrieves the requested blob from the Disperser's backend. @@ -195,8 +163,6 @@ type DisperserServer interface { // The blob should have been initially dispersed via this Disperser service // for this API to work. RetrieveBlob(context.Context, *RetrieveBlobRequest) (*RetrieveBlobReply, error) - // This API is used to query the payment state of a given account. - GetPaymentState(context.Context, *GetPaymentStateRequest) (*GetPaymentStateReply, error) mustEmbedUnimplementedDisperserServer() } @@ -210,18 +176,12 @@ func (UnimplementedDisperserServer) DisperseBlob(context.Context, *DisperseBlobR func (UnimplementedDisperserServer) DisperseBlobAuthenticated(Disperser_DisperseBlobAuthenticatedServer) error { return status.Errorf(codes.Unimplemented, "method DisperseBlobAuthenticated not implemented") } -func (UnimplementedDisperserServer) DispersePaidBlob(context.Context, *DispersePaidBlobRequest) (*DisperseBlobReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method DispersePaidBlob not implemented") -} func (UnimplementedDisperserServer) GetBlobStatus(context.Context, *BlobStatusRequest) (*BlobStatusReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetBlobStatus not implemented") } func (UnimplementedDisperserServer) RetrieveBlob(context.Context, *RetrieveBlobRequest) (*RetrieveBlobReply, error) { return nil, status.Errorf(codes.Unimplemented, "method RetrieveBlob not implemented") } -func (UnimplementedDisperserServer) GetPaymentState(context.Context, *GetPaymentStateRequest) (*GetPaymentStateReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetPaymentState not implemented") -} func (UnimplementedDisperserServer) mustEmbedUnimplementedDisperserServer() {} // UnsafeDisperserServer may be embedded to opt out of forward compatibility for this service. @@ -279,24 +239,6 @@ func (x *disperserDisperseBlobAuthenticatedServer) Recv() (*AuthenticatedRequest return m, nil } -func _Disperser_DispersePaidBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DispersePaidBlobRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DisperserServer).DispersePaidBlob(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Disperser_DispersePaidBlob_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DisperserServer).DispersePaidBlob(ctx, req.(*DispersePaidBlobRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Disperser_GetBlobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(BlobStatusRequest) if err := dec(in); err != nil { @@ -333,24 +275,6 @@ func _Disperser_RetrieveBlob_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } -func _Disperser_GetPaymentState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetPaymentStateRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DisperserServer).GetPaymentState(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Disperser_GetPaymentState_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DisperserServer).GetPaymentState(ctx, req.(*GetPaymentStateRequest)) - } - return interceptor(ctx, in, info, handler) -} - // Disperser_ServiceDesc is the grpc.ServiceDesc for Disperser service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -362,10 +286,6 @@ var Disperser_ServiceDesc = grpc.ServiceDesc{ MethodName: "DisperseBlob", Handler: _Disperser_DisperseBlob_Handler, }, - { - MethodName: "DispersePaidBlob", - Handler: _Disperser_DispersePaidBlob_Handler, - }, { MethodName: "GetBlobStatus", Handler: _Disperser_GetBlobStatus_Handler, @@ -374,10 +294,6 @@ var Disperser_ServiceDesc = grpc.ServiceDesc{ MethodName: "RetrieveBlob", Handler: _Disperser_RetrieveBlob_Handler, }, - { - MethodName: "GetPaymentState", - Handler: _Disperser_GetPaymentState_Handler, - }, }, Streams: []grpc.StreamDesc{ { diff --git a/api/grpc/disperser/v2/disperser_v2.pb.go b/api/grpc/disperser/v2/disperser_v2.pb.go index 3527f50b4..b716c88bf 100644 --- a/api/grpc/disperser/v2/disperser_v2.pb.go +++ b/api/grpc/disperser/v2/disperser_v2.pb.go @@ -423,6 +423,147 @@ func (x *BlobCommitmentReply) GetBlobCommitment() *common.BlobCommitment { return nil } +// GetPaymentStateRequest contains parameters to query the payment state of an account. +type GetPaymentStateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (x *GetPaymentStateRequest) Reset() { + *x = GetPaymentStateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPaymentStateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPaymentStateRequest) ProtoMessage() {} + +func (x *GetPaymentStateRequest) ProtoReflect() protoreflect.Message { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPaymentStateRequest.ProtoReflect.Descriptor instead. +func (*GetPaymentStateRequest) Descriptor() ([]byte, []int) { + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{6} +} + +func (x *GetPaymentStateRequest) GetAccountId() string { + if x != nil { + return x.AccountId + } + return "" +} + +func (x *GetPaymentStateRequest) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +// GetPaymentStateReply contains the payment state of an account. +type GetPaymentStateReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // global payment vault parameters + PaymentGlobalParams *PaymentGlobalParams `protobuf:"bytes,1,opt,name=payment_global_params,json=paymentGlobalParams,proto3" json:"payment_global_params,omitempty"` + // off-chain account reservation usage records + BinRecords []*BinRecord `protobuf:"bytes,2,rep,name=bin_records,json=binRecords,proto3" json:"bin_records,omitempty"` + // on-chain account reservation setting + Reservation *Reservation `protobuf:"bytes,3,opt,name=reservation,proto3" json:"reservation,omitempty"` + // off-chain on-demand payment usage + CumulativePayment []byte `protobuf:"bytes,4,opt,name=cumulative_payment,json=cumulativePayment,proto3" json:"cumulative_payment,omitempty"` + // on-chain on-demand payment deposited + OnChainCumulativePayment []byte `protobuf:"bytes,5,opt,name=on_chain_cumulative_payment,json=onChainCumulativePayment,proto3" json:"on_chain_cumulative_payment,omitempty"` +} + +func (x *GetPaymentStateReply) Reset() { + *x = GetPaymentStateReply{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPaymentStateReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPaymentStateReply) ProtoMessage() {} + +func (x *GetPaymentStateReply) ProtoReflect() protoreflect.Message { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPaymentStateReply.ProtoReflect.Descriptor instead. +func (*GetPaymentStateReply) Descriptor() ([]byte, []int) { + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{7} +} + +func (x *GetPaymentStateReply) GetPaymentGlobalParams() *PaymentGlobalParams { + if x != nil { + return x.PaymentGlobalParams + } + return nil +} + +func (x *GetPaymentStateReply) GetBinRecords() []*BinRecord { + if x != nil { + return x.BinRecords + } + return nil +} + +func (x *GetPaymentStateReply) GetReservation() *Reservation { + if x != nil { + return x.Reservation + } + return nil +} + +func (x *GetPaymentStateReply) GetCumulativePayment() []byte { + if x != nil { + return x.CumulativePayment + } + return nil +} + +func (x *GetPaymentStateReply) GetOnChainCumulativePayment() []byte { + if x != nil { + return x.OnChainCumulativePayment + } + return nil +} + // SignedBatch is a batch of blobs with a signature. type SignedBatch struct { state protoimpl.MessageState @@ -438,7 +579,7 @@ type SignedBatch struct { func (x *SignedBatch) Reset() { *x = SignedBatch{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[6] + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -451,7 +592,7 @@ func (x *SignedBatch) String() string { func (*SignedBatch) ProtoMessage() {} func (x *SignedBatch) ProtoReflect() protoreflect.Message { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[6] + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -464,7 +605,7 @@ func (x *SignedBatch) ProtoReflect() protoreflect.Message { // Deprecated: Use SignedBatch.ProtoReflect.Descriptor instead. func (*SignedBatch) Descriptor() ([]byte, []int) { - return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{6} + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{8} } func (x *SignedBatch) GetHeader() *v2.BatchHeader { @@ -497,7 +638,7 @@ type BlobVerificationInfo struct { func (x *BlobVerificationInfo) Reset() { *x = BlobVerificationInfo{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[7] + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -510,7 +651,7 @@ func (x *BlobVerificationInfo) String() string { func (*BlobVerificationInfo) ProtoMessage() {} func (x *BlobVerificationInfo) ProtoReflect() protoreflect.Message { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[7] + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -523,7 +664,7 @@ func (x *BlobVerificationInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobVerificationInfo.ProtoReflect.Descriptor instead. func (*BlobVerificationInfo) Descriptor() ([]byte, []int) { - return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{7} + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{9} } func (x *BlobVerificationInfo) GetBlobCertificate() *v2.BlobCertificate { @@ -567,7 +708,7 @@ type Attestation struct { func (x *Attestation) Reset() { *x = Attestation{} if protoimpl.UnsafeEnabled { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[8] + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -580,7 +721,7 @@ func (x *Attestation) String() string { func (*Attestation) ProtoMessage() {} func (x *Attestation) ProtoReflect() protoreflect.Message { - mi := &file_disperser_v2_disperser_v2_proto_msgTypes[8] + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -593,7 +734,7 @@ func (x *Attestation) ProtoReflect() protoreflect.Message { // Deprecated: Use Attestation.ProtoReflect.Descriptor instead. func (*Attestation) Descriptor() ([]byte, []int) { - return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{8} + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{10} } func (x *Attestation) GetNonSignerPubkeys() [][]byte { @@ -631,6 +772,219 @@ func (x *Attestation) GetQuorumNumbers() []uint32 { return nil } +type PaymentGlobalParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GlobalSymbolsPerSecond uint64 `protobuf:"varint,1,opt,name=global_symbols_per_second,json=globalSymbolsPerSecond,proto3" json:"global_symbols_per_second,omitempty"` + MinNumSymbols uint32 `protobuf:"varint,2,opt,name=min_num_symbols,json=minNumSymbols,proto3" json:"min_num_symbols,omitempty"` + PricePerSymbol uint32 `protobuf:"varint,3,opt,name=price_per_symbol,json=pricePerSymbol,proto3" json:"price_per_symbol,omitempty"` + ReservationWindow uint32 `protobuf:"varint,4,opt,name=reservation_window,json=reservationWindow,proto3" json:"reservation_window,omitempty"` + OnDemandQuorumNumbers []uint32 `protobuf:"varint,5,rep,packed,name=on_demand_quorum_numbers,json=onDemandQuorumNumbers,proto3" json:"on_demand_quorum_numbers,omitempty"` +} + +func (x *PaymentGlobalParams) Reset() { + *x = PaymentGlobalParams{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PaymentGlobalParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentGlobalParams) ProtoMessage() {} + +func (x *PaymentGlobalParams) ProtoReflect() protoreflect.Message { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PaymentGlobalParams.ProtoReflect.Descriptor instead. +func (*PaymentGlobalParams) Descriptor() ([]byte, []int) { + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{11} +} + +func (x *PaymentGlobalParams) GetGlobalSymbolsPerSecond() uint64 { + if x != nil { + return x.GlobalSymbolsPerSecond + } + return 0 +} + +func (x *PaymentGlobalParams) GetMinNumSymbols() uint32 { + if x != nil { + return x.MinNumSymbols + } + return 0 +} + +func (x *PaymentGlobalParams) GetPricePerSymbol() uint32 { + if x != nil { + return x.PricePerSymbol + } + return 0 +} + +func (x *PaymentGlobalParams) GetReservationWindow() uint32 { + if x != nil { + return x.ReservationWindow + } + return 0 +} + +func (x *PaymentGlobalParams) GetOnDemandQuorumNumbers() []uint32 { + if x != nil { + return x.OnDemandQuorumNumbers + } + return nil +} + +type Reservation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SymbolsPerSecond uint64 `protobuf:"varint,1,opt,name=symbols_per_second,json=symbolsPerSecond,proto3" json:"symbols_per_second,omitempty"` + StartTimestamp uint32 `protobuf:"varint,2,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"` + EndTimestamp uint32 `protobuf:"varint,3,opt,name=end_timestamp,json=endTimestamp,proto3" json:"end_timestamp,omitempty"` + QuorumNumbers []uint32 `protobuf:"varint,4,rep,packed,name=quorum_numbers,json=quorumNumbers,proto3" json:"quorum_numbers,omitempty"` + QuorumSplit []uint32 `protobuf:"varint,5,rep,packed,name=quorum_split,json=quorumSplit,proto3" json:"quorum_split,omitempty"` +} + +func (x *Reservation) Reset() { + *x = Reservation{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Reservation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reservation) ProtoMessage() {} + +func (x *Reservation) ProtoReflect() protoreflect.Message { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Reservation.ProtoReflect.Descriptor instead. +func (*Reservation) Descriptor() ([]byte, []int) { + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{12} +} + +func (x *Reservation) GetSymbolsPerSecond() uint64 { + if x != nil { + return x.SymbolsPerSecond + } + return 0 +} + +func (x *Reservation) GetStartTimestamp() uint32 { + if x != nil { + return x.StartTimestamp + } + return 0 +} + +func (x *Reservation) GetEndTimestamp() uint32 { + if x != nil { + return x.EndTimestamp + } + return 0 +} + +func (x *Reservation) GetQuorumNumbers() []uint32 { + if x != nil { + return x.QuorumNumbers + } + return nil +} + +func (x *Reservation) GetQuorumSplit() []uint32 { + if x != nil { + return x.QuorumSplit + } + return nil +} + +type BinRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Index uint32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Usage uint64 `protobuf:"varint,2,opt,name=usage,proto3" json:"usage,omitempty"` +} + +func (x *BinRecord) Reset() { + *x = BinRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BinRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BinRecord) ProtoMessage() {} + +func (x *BinRecord) ProtoReflect() protoreflect.Message { + mi := &file_disperser_v2_disperser_v2_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BinRecord.ProtoReflect.Descriptor instead. +func (*BinRecord) Descriptor() ([]byte, []int) { + return file_disperser_v2_disperser_v2_proto_rawDescGZIP(), []int{13} +} + +func (x *BinRecord) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *BinRecord) GetUsage() uint64 { + if x != nil { + return x.Usage + } + return 0 +} + var File_disperser_v2_disperser_v2_proto protoreflect.FileDescriptor var file_disperser_v2_disperser_v2_proto_rawDesc = []byte{ @@ -677,64 +1031,131 @@ var file_disperser_v2_disperser_v2_proto_rawDesc = []byte{ 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x7a, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x12, 0x2e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, - 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0xa5, 0x01, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x10, 0x62, 0x6c, 0x6f, - 0x62, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, - 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, - 0x0f, 0x62, 0x6c, 0x6f, 0x62, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb0, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x6f, 0x6e, 0x5f, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, - 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x6b, 0x5f, 0x67, 0x32, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x70, 0x6b, 0x47, 0x32, 0x12, 0x1f, 0x0a, - 0x0b, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x61, 0x70, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x0a, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, - 0x69, 0x67, 0x6d, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, - 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2a, 0x6a, 0x0a, 0x0a, 0x42, - 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, - 0x0d, 0x0a, 0x09, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0a, - 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, - 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, - 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x32, 0x93, 0x02, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, - 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, - 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, - 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, - 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0d, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x64, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, - 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, - 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, - 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, - 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, - 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, - 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, - 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, + 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x14, + 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x55, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x32, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x13, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x38, 0x0a, 0x0b, 0x62, + 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, + 0x42, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x0a, 0x62, 0x69, 0x6e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, + 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x3d, 0x0a, 0x1b, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x63, 0x75, + 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x22, 0x7a, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, + 0x2e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x3b, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa5, 0x01, 0x0a, + 0x14, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x62, 0x6c, 0x6f, + 0x62, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb0, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x6f, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x10, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x6b, 0x5f, 0x67, 0x32, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x61, 0x70, 0x6b, 0x47, 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x71, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x5f, 0x61, 0x70, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, + 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, + 0x67, 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, + 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x13, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, + 0x39, 0x0a, 0x19, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x16, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, + 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x53, 0x79, 0x6d, 0x62, 0x6f, + 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x2d, 0x0a, 0x12, + 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x37, 0x0a, 0x18, 0x6f, + 0x6e, 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x15, 0x6f, + 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, + 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, + 0x6d, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0b, 0x71, + 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x22, 0x37, 0x0a, 0x09, 0x42, 0x69, + 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x14, 0x0a, + 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x75, 0x73, + 0x61, 0x67, 0x65, 0x2a, 0x6a, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, + 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, + 0x43, 0x4f, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, + 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, + 0x4e, 0x54, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x32, + 0xf2, 0x02, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x54, 0x0a, + 0x0c, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x2e, + 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, + 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, + 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, + 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x64, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, + 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, + 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, + 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, + 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -750,44 +1171,54 @@ func file_disperser_v2_disperser_v2_proto_rawDescGZIP() []byte { } var file_disperser_v2_disperser_v2_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_disperser_v2_disperser_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_disperser_v2_disperser_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_disperser_v2_disperser_v2_proto_goTypes = []interface{}{ - (BlobStatus)(0), // 0: disperser.v2.BlobStatus - (*DisperseBlobRequest)(nil), // 1: disperser.v2.DisperseBlobRequest - (*DisperseBlobReply)(nil), // 2: disperser.v2.DisperseBlobReply - (*BlobStatusRequest)(nil), // 3: disperser.v2.BlobStatusRequest - (*BlobStatusReply)(nil), // 4: disperser.v2.BlobStatusReply - (*BlobCommitmentRequest)(nil), // 5: disperser.v2.BlobCommitmentRequest - (*BlobCommitmentReply)(nil), // 6: disperser.v2.BlobCommitmentReply - (*SignedBatch)(nil), // 7: disperser.v2.SignedBatch - (*BlobVerificationInfo)(nil), // 8: disperser.v2.BlobVerificationInfo - (*Attestation)(nil), // 9: disperser.v2.Attestation - (*v2.BlobHeader)(nil), // 10: common.v2.BlobHeader - (*common.BlobCommitment)(nil), // 11: common.BlobCommitment - (*v2.BatchHeader)(nil), // 12: common.v2.BatchHeader - (*v2.BlobCertificate)(nil), // 13: common.v2.BlobCertificate + (BlobStatus)(0), // 0: disperser.v2.BlobStatus + (*DisperseBlobRequest)(nil), // 1: disperser.v2.DisperseBlobRequest + (*DisperseBlobReply)(nil), // 2: disperser.v2.DisperseBlobReply + (*BlobStatusRequest)(nil), // 3: disperser.v2.BlobStatusRequest + (*BlobStatusReply)(nil), // 4: disperser.v2.BlobStatusReply + (*BlobCommitmentRequest)(nil), // 5: disperser.v2.BlobCommitmentRequest + (*BlobCommitmentReply)(nil), // 6: disperser.v2.BlobCommitmentReply + (*GetPaymentStateRequest)(nil), // 7: disperser.v2.GetPaymentStateRequest + (*GetPaymentStateReply)(nil), // 8: disperser.v2.GetPaymentStateReply + (*SignedBatch)(nil), // 9: disperser.v2.SignedBatch + (*BlobVerificationInfo)(nil), // 10: disperser.v2.BlobVerificationInfo + (*Attestation)(nil), // 11: disperser.v2.Attestation + (*PaymentGlobalParams)(nil), // 12: disperser.v2.PaymentGlobalParams + (*Reservation)(nil), // 13: disperser.v2.Reservation + (*BinRecord)(nil), // 14: disperser.v2.BinRecord + (*v2.BlobHeader)(nil), // 15: common.v2.BlobHeader + (*common.BlobCommitment)(nil), // 16: common.BlobCommitment + (*v2.BatchHeader)(nil), // 17: common.v2.BatchHeader + (*v2.BlobCertificate)(nil), // 18: common.v2.BlobCertificate } var file_disperser_v2_disperser_v2_proto_depIdxs = []int32{ - 10, // 0: disperser.v2.DisperseBlobRequest.blob_header:type_name -> common.v2.BlobHeader + 15, // 0: disperser.v2.DisperseBlobRequest.blob_header:type_name -> common.v2.BlobHeader 0, // 1: disperser.v2.DisperseBlobReply.result:type_name -> disperser.v2.BlobStatus 0, // 2: disperser.v2.BlobStatusReply.status:type_name -> disperser.v2.BlobStatus - 7, // 3: disperser.v2.BlobStatusReply.signed_batch:type_name -> disperser.v2.SignedBatch - 8, // 4: disperser.v2.BlobStatusReply.blob_verification_info:type_name -> disperser.v2.BlobVerificationInfo - 11, // 5: disperser.v2.BlobCommitmentReply.blob_commitment:type_name -> common.BlobCommitment - 12, // 6: disperser.v2.SignedBatch.header:type_name -> common.v2.BatchHeader - 9, // 7: disperser.v2.SignedBatch.attestation:type_name -> disperser.v2.Attestation - 13, // 8: disperser.v2.BlobVerificationInfo.blob_certificate:type_name -> common.v2.BlobCertificate - 1, // 9: disperser.v2.Disperser.DisperseBlob:input_type -> disperser.v2.DisperseBlobRequest - 3, // 10: disperser.v2.Disperser.GetBlobStatus:input_type -> disperser.v2.BlobStatusRequest - 5, // 11: disperser.v2.Disperser.GetBlobCommitment:input_type -> disperser.v2.BlobCommitmentRequest - 2, // 12: disperser.v2.Disperser.DisperseBlob:output_type -> disperser.v2.DisperseBlobReply - 4, // 13: disperser.v2.Disperser.GetBlobStatus:output_type -> disperser.v2.BlobStatusReply - 6, // 14: disperser.v2.Disperser.GetBlobCommitment:output_type -> disperser.v2.BlobCommitmentReply - 12, // [12:15] is the sub-list for method output_type - 9, // [9:12] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 9, // 3: disperser.v2.BlobStatusReply.signed_batch:type_name -> disperser.v2.SignedBatch + 10, // 4: disperser.v2.BlobStatusReply.blob_verification_info:type_name -> disperser.v2.BlobVerificationInfo + 16, // 5: disperser.v2.BlobCommitmentReply.blob_commitment:type_name -> common.BlobCommitment + 12, // 6: disperser.v2.GetPaymentStateReply.payment_global_params:type_name -> disperser.v2.PaymentGlobalParams + 14, // 7: disperser.v2.GetPaymentStateReply.bin_records:type_name -> disperser.v2.BinRecord + 13, // 8: disperser.v2.GetPaymentStateReply.reservation:type_name -> disperser.v2.Reservation + 17, // 9: disperser.v2.SignedBatch.header:type_name -> common.v2.BatchHeader + 11, // 10: disperser.v2.SignedBatch.attestation:type_name -> disperser.v2.Attestation + 18, // 11: disperser.v2.BlobVerificationInfo.blob_certificate:type_name -> common.v2.BlobCertificate + 1, // 12: disperser.v2.Disperser.DisperseBlob:input_type -> disperser.v2.DisperseBlobRequest + 3, // 13: disperser.v2.Disperser.GetBlobStatus:input_type -> disperser.v2.BlobStatusRequest + 5, // 14: disperser.v2.Disperser.GetBlobCommitment:input_type -> disperser.v2.BlobCommitmentRequest + 7, // 15: disperser.v2.Disperser.GetPaymentState:input_type -> disperser.v2.GetPaymentStateRequest + 2, // 16: disperser.v2.Disperser.DisperseBlob:output_type -> disperser.v2.DisperseBlobReply + 4, // 17: disperser.v2.Disperser.GetBlobStatus:output_type -> disperser.v2.BlobStatusReply + 6, // 18: disperser.v2.Disperser.GetBlobCommitment:output_type -> disperser.v2.BlobCommitmentReply + 8, // 19: disperser.v2.Disperser.GetPaymentState:output_type -> disperser.v2.GetPaymentStateReply + 16, // [16:20] is the sub-list for method output_type + 12, // [12:16] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_disperser_v2_disperser_v2_proto_init() } @@ -869,7 +1300,7 @@ func file_disperser_v2_disperser_v2_proto_init() { } } file_disperser_v2_disperser_v2_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SignedBatch); i { + switch v := v.(*GetPaymentStateRequest); i { case 0: return &v.state case 1: @@ -881,7 +1312,7 @@ func file_disperser_v2_disperser_v2_proto_init() { } } file_disperser_v2_disperser_v2_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlobVerificationInfo); i { + switch v := v.(*GetPaymentStateReply); i { case 0: return &v.state case 1: @@ -893,6 +1324,30 @@ func file_disperser_v2_disperser_v2_proto_init() { } } file_disperser_v2_disperser_v2_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignedBatch); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_v2_disperser_v2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlobVerificationInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_v2_disperser_v2_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Attestation); i { case 0: return &v.state @@ -904,6 +1359,42 @@ func file_disperser_v2_disperser_v2_proto_init() { return nil } } + file_disperser_v2_disperser_v2_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PaymentGlobalParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_v2_disperser_v2_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Reservation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_disperser_v2_disperser_v2_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BinRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -911,7 +1402,7 @@ func file_disperser_v2_disperser_v2_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_disperser_v2_disperser_v2_proto_rawDesc, NumEnums: 1, - NumMessages: 9, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/api/grpc/disperser/v2/disperser_v2_grpc.pb.go b/api/grpc/disperser/v2/disperser_v2_grpc.pb.go index d84637329..bd93c2ea2 100644 --- a/api/grpc/disperser/v2/disperser_v2_grpc.pb.go +++ b/api/grpc/disperser/v2/disperser_v2_grpc.pb.go @@ -22,6 +22,7 @@ const ( Disperser_DisperseBlob_FullMethodName = "/disperser.v2.Disperser/DisperseBlob" Disperser_GetBlobStatus_FullMethodName = "/disperser.v2.Disperser/GetBlobStatus" Disperser_GetBlobCommitment_FullMethodName = "/disperser.v2.Disperser/GetBlobCommitment" + Disperser_GetPaymentState_FullMethodName = "/disperser.v2.Disperser/GetPaymentState" ) // DisperserClient is the client API for Disperser service. @@ -37,6 +38,8 @@ type DisperserClient interface { GetBlobStatus(ctx context.Context, in *BlobStatusRequest, opts ...grpc.CallOption) (*BlobStatusReply, error) // GetBlobCommitment is a utility method that calculates commitment for a blob payload. GetBlobCommitment(ctx context.Context, in *BlobCommitmentRequest, opts ...grpc.CallOption) (*BlobCommitmentReply, error) + // GetPaymentState is a utility method to get the payment state of a given account. + GetPaymentState(ctx context.Context, in *GetPaymentStateRequest, opts ...grpc.CallOption) (*GetPaymentStateReply, error) } type disperserClient struct { @@ -74,6 +77,15 @@ func (c *disperserClient) GetBlobCommitment(ctx context.Context, in *BlobCommitm return out, nil } +func (c *disperserClient) GetPaymentState(ctx context.Context, in *GetPaymentStateRequest, opts ...grpc.CallOption) (*GetPaymentStateReply, error) { + out := new(GetPaymentStateReply) + err := c.cc.Invoke(ctx, Disperser_GetPaymentState_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DisperserServer is the server API for Disperser service. // All implementations must embed UnimplementedDisperserServer // for forward compatibility @@ -87,6 +99,8 @@ type DisperserServer interface { GetBlobStatus(context.Context, *BlobStatusRequest) (*BlobStatusReply, error) // GetBlobCommitment is a utility method that calculates commitment for a blob payload. GetBlobCommitment(context.Context, *BlobCommitmentRequest) (*BlobCommitmentReply, error) + // GetPaymentState is a utility method to get the payment state of a given account. + GetPaymentState(context.Context, *GetPaymentStateRequest) (*GetPaymentStateReply, error) mustEmbedUnimplementedDisperserServer() } @@ -103,6 +117,9 @@ func (UnimplementedDisperserServer) GetBlobStatus(context.Context, *BlobStatusRe func (UnimplementedDisperserServer) GetBlobCommitment(context.Context, *BlobCommitmentRequest) (*BlobCommitmentReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetBlobCommitment not implemented") } +func (UnimplementedDisperserServer) GetPaymentState(context.Context, *GetPaymentStateRequest) (*GetPaymentStateReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPaymentState not implemented") +} func (UnimplementedDisperserServer) mustEmbedUnimplementedDisperserServer() {} // UnsafeDisperserServer may be embedded to opt out of forward compatibility for this service. @@ -170,6 +187,24 @@ func _Disperser_GetBlobCommitment_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _Disperser_GetPaymentState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPaymentStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DisperserServer).GetPaymentState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Disperser_GetPaymentState_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DisperserServer).GetPaymentState(ctx, req.(*GetPaymentStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Disperser_ServiceDesc is the grpc.ServiceDesc for Disperser service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -189,6 +224,10 @@ var Disperser_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetBlobCommitment", Handler: _Disperser_GetBlobCommitment_Handler, }, + { + MethodName: "GetPaymentState", + Handler: _Disperser_GetPaymentState_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "disperser/v2/disperser_v2.proto", diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 57d86aab3..6c9be3c54 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -6,7 +6,6 @@ import ( "encoding/binary" "errors" "fmt" - "math/big" "net" "slices" "strings" @@ -326,111 +325,6 @@ func (s *DispersalServer) disperseBlob(ctx context.Context, blob *core.Blob, aut }, nil } -func (s *DispersalServer) DispersePaidBlob(ctx context.Context, req *pb.DispersePaidBlobRequest) (*pb.DisperseBlobReply, error) { - blob, err := s.validatePaidRequestAndGetBlob(ctx, req) - binIndex := req.PaymentHeader.BinIndex - cumulativePayment := new(big.Int).SetBytes(req.PaymentHeader.CumulativePayment) - //todo: before disperse blob, validate the signature - signature := req.PaymentSignature - if err := auth.VerifyPaymentSignature(core.ConvertToPaymentMetadata(req.GetPaymentHeader()), signature); err != nil { - return nil, api.NewErrorInvalidArg("payment signature is invalid") - } - if err != nil { - for _, quorumID := range req.QuorumNumbers { - s.metrics.HandleFailedRequest(codes.InvalidArgument.String(), fmt.Sprint(quorumID), len(req.GetData()), "DispersePaidBlob") - } - s.metrics.HandleInvalidArgRpcRequest("DispersePaidBlob") - return nil, api.NewErrorInvalidArg(err.Error()) - } - - paymentHeader := core.PaymentMetadata{ - AccountID: blob.RequestHeader.AccountID, - BinIndex: binIndex, - CumulativePayment: cumulativePayment, - } - reply, err := s.disperseBlob(ctx, blob, "", "DispersePaidBlob", &paymentHeader) - if err != nil { - // Note the DispersePaidBlob already updated metrics for this error. - s.logger.Info("failed to disperse blob", "err", err) - } else { - s.metrics.HandleSuccessfulRpcRequest("DispersePaidBlob") - } - return reply, err -} - -func (s *DispersalServer) GetPaymentState(ctx context.Context, req *pb.GetPaymentStateRequest) (*pb.GetPaymentStateReply, error) { - // validate the signature - if !auth.VerifyAccountSignature(req.AccountId, req.Signature) { - return nil, api.NewErrorInvalidArg("invalid signature") - } - - // on-chain global payment parameters - globalSymbolsPerSecond := s.meterer.ChainPaymentState.GetGlobalSymbolsPerSecond() - minNumSymbols := s.meterer.ChainPaymentState.GetMinNumSymbols() - pricePerSymbol := s.meterer.ChainPaymentState.GetPricePerSymbol() - reservationWindow := s.meterer.ChainPaymentState.GetReservationWindow() - - // off-chain account specific payment state - now := uint64(time.Now().Unix()) - currentBinIndex := meterer.GetBinIndex(now, reservationWindow) - currentBinUsage, nextBinUsage, overflowBinUsage, err := s.meterer.OffchainStore.GetBinUsages(ctx, req.AccountId, currentBinIndex) - if err != nil { - return nil, api.NewErrorNotFound("failed to get active reservation") - } - largestCumulativePayment, err := s.meterer.OffchainStore.GetLargestCumulativePayment(ctx, req.AccountId) - if err != nil { - return nil, api.NewErrorNotFound("failed to get largest cumulative payment") - } - // on-Chain account state - reservation, err := s.meterer.ChainPaymentState.GetActiveReservationByAccount(ctx, req.AccountId) - if err != nil { - return nil, api.NewErrorNotFound("failed to get active reservation") - } - onDemandPayment, err := s.meterer.ChainPaymentState.GetOnDemandPaymentByAccount(ctx, req.AccountId) - if err != nil { - return nil, api.NewErrorNotFound("failed to get on-demand payment") - } - - paymentGlobalParams := pb.PaymentGlobalParams{ - GlobalSymbolsPerSecond: globalSymbolsPerSecond, - MinNumSymbols: minNumSymbols, - PricePerSymbol: pricePerSymbol, - ReservationWindow: reservationWindow, - } - - quorumNumbers := make([]uint32, len(reservation.QuorumNumbers)) - for i, v := range reservation.QuorumNumbers { - quorumNumbers[i] = uint32(v) - } - // build reply - reply := &pb.GetPaymentStateReply{ - PaymentGlobalParams: &paymentGlobalParams, - BinRecords: []*pb.BinRecord{ - { - Index: uint32(currentBinIndex), - Usage: uint64(currentBinUsage), - }, - { - Index: uint32(currentBinIndex + 1), - Usage: uint64(nextBinUsage), - }, - { - Index: uint32(currentBinIndex + 2), - Usage: uint64(overflowBinUsage), - }, - }, - Reservation: &pb.Reservation{ - SymbolsPerSecond: reservation.SymbolsPerSec, - StartTimestamp: uint32(reservation.StartTimestamp), - EndTimestamp: uint32(reservation.EndTimestamp), - QuorumNumbers: quorumNumbers, - }, - CumulativePayment: largestCumulativePayment.Bytes(), - OnChainCumulativePayment: onDemandPayment.CumulativePayment.Bytes(), - } - return reply, nil -} - func (s *DispersalServer) getAccountRate(origin, authenticatedAddress string, quorumID core.QuorumID) (*PerUserRateInfo, string, error) { unauthRates, ok := s.rateConfig.QuorumRateInfos[quorumID] if !ok { @@ -1178,97 +1072,3 @@ func contextError(err error) error { return nil } - -// TODO: refactor checks with validateRequestAndGetBlob; most checks are the same, but paid requests have different quorum requirements -func (s *DispersalServer) validatePaidRequestAndGetBlob(ctx context.Context, req *pb.DispersePaidBlobRequest) (*core.Blob, error) { - - data := req.GetData() - blobSize := len(data) - // The blob size in bytes must be in range [1, maxBlobSize]. - if blobSize > s.maxBlobSize { - return nil, fmt.Errorf("blob size cannot exceed %v Bytes", s.maxBlobSize) - } - if blobSize == 0 { - return nil, fmt.Errorf("blob size must be greater than 0") - } - - if len(req.GetQuorumNumbers()) > 256 { - return nil, errors.New("number of custom_quorum_numbers must not exceed 256") - } - - // validate every 32 bytes is a valid field element - _, err := rs.ToFrArray(data) - if err != nil { - s.logger.Error("failed to convert a 32bytes as a field element", "err", err) - return nil, api.NewErrorInvalidArg(fmt.Sprintf("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: %v", err)) - } - - quorumConfig, err := s.updateQuorumConfig(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get quorum config: %w", err) - } - - if len(req.GetQuorumNumbers()) > int(quorumConfig.QuorumCount) { - return nil, errors.New("number of custom_quorum_numbers must not exceed number of quorums") - } - - seenQuorums := make(map[uint8]struct{}) - - // TODO: validate payment signature against payment metadata - if err = auth.VerifyPaymentSignature(core.ConvertToPaymentMetadata(req.GetPaymentHeader()), req.GetPaymentSignature()); err != nil { - return nil, fmt.Errorf("payment signature is invalid: %w", err) - } - // Unlike regular blob dispersal request validation, there's no check with required quorums - // Because Reservation has their specific quorum requirements, and on-demand is only allowed and paid to the required quorums. - // Payment specific validations are done within the meterer library. - for i := range req.GetQuorumNumbers() { - - if req.GetQuorumNumbers()[i] > core.MaxQuorumID { - return nil, fmt.Errorf("custom_quorum_numbers must be in range [0, 254], but found %d", req.GetQuorumNumbers()[i]) - } - - quorumID := uint8(req.GetQuorumNumbers()[i]) - if quorumID >= quorumConfig.QuorumCount { - return nil, fmt.Errorf("custom_quorum_numbers must be in range [0, %d], but found %d", s.quorumConfig.QuorumCount-1, quorumID) - } - - if _, ok := seenQuorums[quorumID]; ok { - return nil, fmt.Errorf("custom_quorum_numbers must not contain duplicates") - } - seenQuorums[quorumID] = struct{}{} - - } - - if len(seenQuorums) == 0 { - return nil, fmt.Errorf("the blob must be sent to at least one quorum") - } - - params := make([]*core.SecurityParam, len(seenQuorums)) - i := 0 - for quorumID := range seenQuorums { - params[i] = &core.SecurityParam{ - QuorumID: core.QuorumID(quorumID), - AdversaryThreshold: quorumConfig.SecurityParams[quorumID].AdversaryThreshold, - ConfirmationThreshold: quorumConfig.SecurityParams[quorumID].ConfirmationThreshold, - } - err = params[i].Validate() - if err != nil { - return nil, fmt.Errorf("invalid request: %w", err) - } - i++ - } - - header := core.BlobRequestHeader{ - BlobAuthHeader: core.BlobAuthHeader{ - AccountID: req.PaymentHeader.AccountId, - }, - SecurityParams: params, - } - - blob := &core.Blob{ - RequestHeader: header, - Data: data, - } - - return blob, nil -} diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index e328127ec..100382e04 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -14,6 +14,7 @@ import ( "github.com/Layr-Labs/eigenda/common" healthcheck "github.com/Layr-Labs/eigenda/common/healthcheck" "github.com/Layr-Labs/eigenda/core" + "github.com/Layr-Labs/eigenda/core/auth" "github.com/Layr-Labs/eigenda/core/meterer" corev2 "github.com/Layr-Labs/eigenda/core/v2" v2 "github.com/Layr-Labs/eigenda/core/v2" @@ -209,3 +210,76 @@ func (s *DispersalServerV2) RefreshOnchainState(ctx context.Context) error { return nil } + +func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaymentStateRequest) (*pb.GetPaymentStateReply, error) { + // validate the signature + if !auth.VerifyAccountSignature(req.AccountId, req.Signature) { + return nil, api.NewErrorInvalidArg("invalid signature") + } + + // on-chain global payment parameters + globalSymbolsPerSecond := s.meterer.ChainPaymentState.GetGlobalSymbolsPerSecond() + minNumSymbols := s.meterer.ChainPaymentState.GetMinNumSymbols() + pricePerSymbol := s.meterer.ChainPaymentState.GetPricePerSymbol() + reservationWindow := s.meterer.ChainPaymentState.GetReservationWindow() + + // off-chain account specific payment state + now := uint64(time.Now().Unix()) + currentBinIndex := meterer.GetBinIndex(now, reservationWindow) + currentBinUsage, nextBinUsage, overflowBinUsage, err := s.meterer.OffchainStore.GetBinUsages(ctx, req.AccountId, currentBinIndex) + if err != nil { + return nil, api.NewErrorNotFound("failed to get active reservation") + } + largestCumulativePayment, err := s.meterer.OffchainStore.GetLargestCumulativePayment(ctx, req.AccountId) + if err != nil { + return nil, api.NewErrorNotFound("failed to get largest cumulative payment") + } + // on-Chain account state + reservation, err := s.meterer.ChainPaymentState.GetActiveReservationByAccount(ctx, req.AccountId) + if err != nil { + return nil, api.NewErrorNotFound("failed to get active reservation") + } + onDemandPayment, err := s.meterer.ChainPaymentState.GetOnDemandPaymentByAccount(ctx, req.AccountId) + if err != nil { + return nil, api.NewErrorNotFound("failed to get on-demand payment") + } + + paymentGlobalParams := pb.PaymentGlobalParams{ + GlobalSymbolsPerSecond: globalSymbolsPerSecond, + MinNumSymbols: minNumSymbols, + PricePerSymbol: pricePerSymbol, + ReservationWindow: reservationWindow, + } + + quorumNumbers := make([]uint32, len(reservation.QuorumNumbers)) + for i, v := range reservation.QuorumNumbers { + quorumNumbers[i] = uint32(v) + } + // build reply + reply := &pb.GetPaymentStateReply{ + PaymentGlobalParams: &paymentGlobalParams, + BinRecords: []*pb.BinRecord{ + { + Index: uint32(currentBinIndex), + Usage: uint64(currentBinUsage), + }, + { + Index: uint32(currentBinIndex + 1), + Usage: uint64(nextBinUsage), + }, + { + Index: uint32(currentBinIndex + 2), + Usage: uint64(overflowBinUsage), + }, + }, + Reservation: &pb.Reservation{ + SymbolsPerSecond: reservation.SymbolsPerSec, + StartTimestamp: uint32(reservation.StartTimestamp), + EndTimestamp: uint32(reservation.EndTimestamp), + QuorumNumbers: quorumNumbers, + }, + CumulativePayment: largestCumulativePayment.Bytes(), + OnChainCumulativePayment: onDemandPayment.CumulativePayment.Bytes(), + } + return reply, nil +} diff --git a/tools/traffic/generator.go b/tools/traffic/generator.go index 5afdf0b56..f979ac177 100644 --- a/tools/traffic/generator.go +++ b/tools/traffic/generator.go @@ -31,7 +31,7 @@ func NewTrafficGenerator(config *Config, signer core.BlobRequestSigner) (*Traffi return nil, fmt.Errorf("new logger: %w", err) } - dispserserClient, err := clients.NewDisperserClient(&config.Config, signer) + dispserserClient, err := clients.NewDisperserClient(&config.Config, signer, nil) if err != nil { return nil, fmt.Errorf("new disperser-client: %w", err) } diff --git a/tools/traffic/generator_v2.go b/tools/traffic/generator_v2.go index 61575b9c0..c95efa111 100644 --- a/tools/traffic/generator_v2.go +++ b/tools/traffic/generator_v2.go @@ -88,7 +88,8 @@ func NewTrafficGeneratorV2(config *config.Config) (*Generator, error) { unconfirmedKeyChannel := make(chan *workers.UnconfirmedKey, 100) - disperserClient, err := clients.NewDisperserClient(config.DisperserClientConfig, signer) + // TODO: create a dedicated reservation for traffic generator and create a payment signer + disperserClient, err := clients.NewDisperserClient(config.DisperserClientConfig, signer, nil) if err != nil { cancel() return nil, fmt.Errorf("new disperser-client: %w", err) From 2bb63580636b9c8dda7a08e09a1bbe4584bd86ab Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 03:15:18 -0800 Subject: [PATCH 05/18] refactor: undo client side changes, focus on server --- api/clients/accountant.go | 50 -------------------------- api/clients/config.go | 7 ---- api/clients/disperser_client.go | 14 +++----- api/clients/disperser_client_test.go | 2 +- api/clients/eigenda_client.go | 13 +------ api/clients/eigenda_client_test.go | 52 ---------------------------- api/clients/mock/disperser_client.go | 27 --------------- core/auth.go | 1 - core/auth/payment_signer.go | 36 ------------------- core/data.go | 2 +- inabox/tests/integration_test.go | 4 +-- inabox/tests/ratelimit_test.go | 4 +-- tools/traffic/generator.go | 2 +- tools/traffic/generator_v2.go | 2 +- 14 files changed, 12 insertions(+), 204 deletions(-) diff --git a/api/clients/accountant.go b/api/clients/accountant.go index bcd0b2d24..122ec3eea 100644 --- a/api/clients/accountant.go +++ b/api/clients/accountant.go @@ -9,7 +9,6 @@ import ( "time" commonpb "github.com/Layr-Labs/eigenda/api/grpc/common" - disperser_v2_rpc "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/core/meterer" ) @@ -19,8 +18,6 @@ var requiredQuorums = []uint8{0, 1} type Accountant interface { AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, []byte, error) - AuthenticatePaymentStateRequest() (*disperser_v2_rpc.GetPaymentStateRequest, error) - SetPaymentState(paymentState *disperser_v2_rpc.GetPaymentStateReply) } var _ Accountant = &accountant{} @@ -181,50 +178,3 @@ func QuorumCheck(quorumNumbers []uint8, allowedNumbers []uint8) error { } return nil } - -func (a *accountant) SetPaymentState(paymentState *disperser_v2_rpc.GetPaymentStateReply) { - quorumNumbers := make([]uint8, len(paymentState.Reservation.QuorumNumbers)) - for i, quorum := range paymentState.Reservation.QuorumNumbers { - quorumNumbers[i] = uint8(quorum) - } - quorumSplit := make([]uint8, len(paymentState.Reservation.QuorumSplit)) - for i, quorum := range paymentState.Reservation.QuorumSplit { - quorumSplit[i] = uint8(quorum) - } - a.reservation.QuorumNumbers = quorumNumbers - a.reservation.QuorumSplit = quorumSplit - - a.onDemand.CumulativePayment = new(big.Int).SetBytes(paymentState.OnChainCumulativePayment) - - a.pricePerSymbol = uint32(paymentState.PaymentGlobalParams.PricePerSymbol) - a.minNumSymbols = uint32(paymentState.PaymentGlobalParams.MinNumSymbols) - a.reservationWindow = uint32(paymentState.PaymentGlobalParams.ReservationWindow) - - records := make([]BinRecord, len(paymentState.BinRecords)) - for i, record := range paymentState.BinRecords { - records[i] = BinRecord{ - Index: record.Index, - Usage: record.Usage, - } - } - a.binRecords = records - a.reservation.SymbolsPerSec = uint64(paymentState.Reservation.SymbolsPerSecond) - a.reservation.StartTimestamp = uint64(paymentState.Reservation.StartTimestamp) - a.reservation.EndTimestamp = uint64(paymentState.Reservation.EndTimestamp) -} - -func (a *accountant) AuthenticatePaymentStateRequest() (*disperser_v2_rpc.GetPaymentStateRequest, error) { - accountID := a.paymentSigner.GetAccountID() - - signature, err := a.paymentSigner.SignAccountID(accountID) - if err != nil { - return nil, err - } - - request := &disperser_v2_rpc.GetPaymentStateRequest{ - AccountId: accountID, - Signature: signature, - } - - return request, nil -} diff --git a/api/clients/config.go b/api/clients/config.go index 5dbd78de0..f4d9caa9f 100644 --- a/api/clients/config.go +++ b/api/clients/config.go @@ -60,10 +60,6 @@ type EigenDAClientConfig struct { // that can retrieve blobs but cannot disperse blobs. SignerPrivateKeyHex string - // Payment signer private key in hex encoded format. This key connect to the wallet with payment registered on-chain - // if set to "", will result in a non-paying client and cannot disperse paid blobs. - PaymentSignerPrivateKeyHex string - // Whether to disable TLS for an insecure connection when connecting to a local EigenDA disperser instance. DisableTLS bool @@ -116,9 +112,6 @@ func (c *EigenDAClientConfig) CheckAndSetDefaults() error { if len(c.SignerPrivateKeyHex) > 0 && len(c.SignerPrivateKeyHex) != 64 { return fmt.Errorf("a valid length SignerPrivateKeyHex needs to have 64 bytes") } - if len(c.PaymentSignerPrivateKeyHex) > 0 && len(c.PaymentSignerPrivateKeyHex) != 64 { - return fmt.Errorf("a valid length PaymentSignerPrivateKeyHex needs to have 64 bytes") - } if len(c.RPC) == 0 { return fmt.Errorf("EigenDAClientConfig.RPC not set") diff --git a/api/clients/disperser_client.go b/api/clients/disperser_client.go index 2db937777..219b85bb4 100644 --- a/api/clients/disperser_client.go +++ b/api/clients/disperser_client.go @@ -76,9 +76,8 @@ type disperserClient struct { // TODO: we should refactor or make a new constructor which allows setting conn and/or client // via dependency injection. This would allow for testing via https://pkg.go.dev/google.golang.org/grpc/test/bufconn // instead of a real network connection for eg. - conn *grpc.ClientConn - client disperser_rpc.DisperserClient - accountant Accountant + conn *grpc.ClientConn + client disperser_rpc.DisperserClient } var _ DisperserClient = &disperserClient{} @@ -103,16 +102,13 @@ var _ DisperserClient = &disperserClient{} // // // Subsequent calls will use the existing connection // status2, requestId2, err := client.DisperseBlob(ctx, otherData, otherQuorums) -func NewDisperserClient(config *Config, signer core.BlobRequestSigner, paymentSigner core.PaymentSigner) (*disperserClient, error) { +func NewDisperserClient(config *Config, signer core.BlobRequestSigner) (*disperserClient, error) { if err := checkConfigAndSetDefaults(config); err != nil { return nil, fmt.Errorf("invalid config: %w", err) } - // initialize an empty accountant; update payment state after initialization - accountant := NewAccountant(&core.ActiveReservation{}, &core.OnDemandPayment{}, 0, 0, 0, paymentSigner, 0) return &disperserClient{ - config: config, - signer: signer, - accountant: accountant, + config: config, + signer: signer, // conn and client are initialized lazily }, nil } diff --git a/api/clients/disperser_client_test.go b/api/clients/disperser_client_test.go index 853e3cc64..00277657b 100644 --- a/api/clients/disperser_client_test.go +++ b/api/clients/disperser_client_test.go @@ -14,7 +14,7 @@ import ( func TestPutBlobNoopSigner(t *testing.T) { config := clients.NewConfig("nohost", "noport", time.Second, false) - disperserClient, err := clients.NewDisperserClient(config, auth.NewLocalNoopSigner(), auth.NewNoopPaymentSigner()) + disperserClient, err := clients.NewDisperserClient(config, auth.NewLocalNoopSigner()) assert.NoError(t, err) test := []byte("test") diff --git a/api/clients/eigenda_client.go b/api/clients/eigenda_client.go index d07b033ba..3231f2954 100644 --- a/api/clients/eigenda_client.go +++ b/api/clients/eigenda_client.go @@ -99,32 +99,21 @@ func NewEigenDAClient(log log.Logger, config EigenDAClientConfig) (*EigenDAClien } var signer core.BlobRequestSigner - var paymentSigner core.PaymentSigner if len(config.SignerPrivateKeyHex) == 64 { signer = auth.NewLocalBlobRequestSigner(config.SignerPrivateKeyHex) - paymentSigner, err = auth.NewPaymentSigner(hex.EncodeToString([]byte(config.SignerPrivateKeyHex))) - if err != nil { - return nil, fmt.Errorf("new payment signer: %w", err) - } } else if len(config.SignerPrivateKeyHex) == 0 { // noop signer is used when we need a read-only eigenda client signer = auth.NewLocalNoopSigner() - paymentSigner = auth.NewNoopPaymentSigner() } else { return nil, fmt.Errorf("invalid length for signer private key") } disperserConfig := NewConfig(host, port, config.ResponseTimeout, !config.DisableTLS) - disperserClient, err := NewDisperserClient(disperserConfig, signer, paymentSigner) + disperserClient, err := NewDisperserClient(disperserConfig, signer) if err != nil { return nil, fmt.Errorf("new disperser-client: %w", err) } - // TODO: uncomment this when we are using disperser client v2 - // err = disperserClient.InitializePaymentState(context.Background()) - // if err != nil { - // return nil, fmt.Errorf("error setting payment state: %w", err) - // } lowLevelCodec, err := codecs.BlobEncodingVersionToCodec(config.PutBlobEncodingVersion) if err != nil { diff --git a/api/clients/eigenda_client_test.go b/api/clients/eigenda_client_test.go index 9dd3a9f14..29435472b 100644 --- a/api/clients/eigenda_client_test.go +++ b/api/clients/eigenda_client_test.go @@ -84,58 +84,6 @@ func TestPutRetrieveBlobIFFTSuccess(t *testing.T) { require.Equal(t, expectedBlob, resultBlob) } -// func TestGetBlobPaymentStateSuccess(t *testing.T) { -// disperserClient := clientsmock.NewMockDisperserClient() -// expectedPaymentState := &grpcdisperser.GetPaymentStateReply{PaymentGlobalParams: &grpcdisperser.PaymentGlobalParams{ -// GlobalSymbolsPerSecond: 100000, -// MinNumSymbols: 100, -// PricePerSymbol: 10, -// ReservationWindow: 100, -// OnDemandQuorumNumbers: []uint32{0, 1}, -// }, -// CurrentBinUsage: 100, -// NextBinUsage: 200, -// OverflowBinUsage: 300, -// Reservation: &grpcdisperser.Reservation{ -// SymbolsPerSecond: 1000, -// StartTimestamp: 0, -// EndTimestamp: math.MaxUint32, -// QuorumNumbers: []uint32{0, 1}, -// }, -// CumulativePayment: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, -// OnChainCumulativePayment: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, -// } -// (disperserClient.On("GetPaymentState", mock.Anything, mock.Anything). -// Return(expectedPaymentState, nil).Once()) -// logger := log.NewLogger(log.DiscardHandler()) -// eigendaClient := clients.EigenDAClient{ -// Log: logger, -// Config: clients.EigenDAClientConfig{ -// RPC: "localhost:51001", -// StatusQueryTimeout: 10 * time.Minute, -// StatusQueryRetryInterval: 50 * time.Millisecond, -// ResponseTimeout: 10 * time.Second, -// CustomQuorumIDs: []uint{}, -// SignerPrivateKeyHex: "75f9e29cac7f5774d106adb355ef294987ce39b7863b75bb3f2ea42ca160926d", -// DisableTLS: false, -// PutBlobEncodingVersion: codecs.DefaultBlobEncoding, -// DisablePointVerificationMode: false, -// WaitForFinalization: true, -// }, -// Client: disperserClient, -// Codec: codecs.NewIFFTCodec(codecs.NewDefaultBlobCodec()), -// } -// expectedBlob := []byte("dc49e7df326cfb2e7da5cf68f263e1898443ec2e862350606e7dfbda55ad10b5d61ed1d54baf6ae7a86279c1b4fa9c49a7de721dacb211264c1f5df31bade51c") -// blobInfo, err := eigendaClient.PutBlob(context.Background(), expectedBlob) -// require.NoError(t, err) -// require.NotNil(t, blobInfo) -// assert.Equal(t, finalizedBlobInfo, blobInfo) - -// resultBlob, err := eigendaClient.GetBlob(context.Background(), []byte("mock-batch-header-hash"), 100) -// require.NoError(t, err) -// require.Equal(t, expectedBlob, resultBlob) -// } - func TestPutRetrieveBlobIFFTNoDecodeSuccess(t *testing.T) { disperserClient := clientsmock.NewMockDisperserClient() expectedBlobStatus := disperser.Processing diff --git a/api/clients/mock/disperser_client.go b/api/clients/mock/disperser_client.go index a2848d2cf..ffdb0b4b9 100644 --- a/api/clients/mock/disperser_client.go +++ b/api/clients/mock/disperser_client.go @@ -80,28 +80,6 @@ func (c *MockDisperserClient) DisperseBlob(ctx context.Context, data []byte, quo return status, key, err } - -func (c *MockDisperserClient) DispersePaidBlob(ctx context.Context, data []byte, quorums []uint8) (*disperser.BlobStatus, []byte, error) { - args := c.Called(data, quorums) - var status *disperser.BlobStatus - if args.Get(0) != nil { - status = (args.Get(0)).(*disperser.BlobStatus) - } - var key []byte - if args.Get(1) != nil { - key = (args.Get(1)).([]byte) - } - var err error - if args.Get(2) != nil { - err = (args.Get(2)).(error) - } - - keyStr := base64.StdEncoding.EncodeToString(key) - c.mockRequestIDStore[keyStr] = data - - return status, key, err -} - func (c *MockDisperserClient) GetBlobStatus(ctx context.Context, key []byte) (*disperser_rpc.BlobStatusReply, error) { args := c.Called(key) var reply *disperser_rpc.BlobStatusReply @@ -138,11 +116,6 @@ func (c *MockDisperserClient) RetrieveBlob(ctx context.Context, batchHeaderHash return blob, err } -func (c *MockDisperserClient) InitializePaymentState(ctx context.Context) error { - args := c.Called() - return args.Error(0) -} - func (c *MockDisperserClient) Close() error { args := c.Called() return args.Error(0) diff --git a/core/auth.go b/core/auth.go index dbeab3a58..7e7669aa2 100644 --- a/core/auth.go +++ b/core/auth.go @@ -51,6 +51,5 @@ func VerifySignature(message []byte, accountAddr geth.Address, sig []byte) error type PaymentSigner interface { SignBlobPayment(header *PaymentMetadata) ([]byte, error) - SignAccountID(accountID string) ([]byte, error) GetAccountID() string } diff --git a/core/auth/payment_signer.go b/core/auth/payment_signer.go index f4fa92dce..b22283040 100644 --- a/core/auth/payment_signer.go +++ b/core/auth/payment_signer.go @@ -2,9 +2,7 @@ package auth import ( "crypto/ecdsa" - "encoding/hex" "fmt" - "log" "github.com/Layr-Labs/eigenda/core" "github.com/ethereum/go-ethereum/common" @@ -47,16 +45,6 @@ func (s *paymentSigner) SignBlobPayment(pm *core.PaymentMetadata) ([]byte, error return sig, nil } -func (s *paymentSigner) SignAccountID(accountID string) ([]byte, error) { - hash := crypto.Keccak256Hash([]byte(accountID)) - sig, err := crypto.Sign(hash.Bytes(), s.PrivateKey) - if err != nil { - return nil, fmt.Errorf("failed to sign account ID: %v", err) - } - - return sig, nil -} - type NoopPaymentSigner struct{} func NewNoopPaymentSigner() *NoopPaymentSigner { @@ -67,10 +55,6 @@ func (s *NoopPaymentSigner) SignBlobPayment(header *core.PaymentMetadata) ([]byt return nil, fmt.Errorf("noop signer cannot sign blob payment header") } -func (s *NoopPaymentSigner) SignAccountID(accountID string) ([]byte, error) { - return nil, fmt.Errorf("noop signer cannot sign account ID") -} - func (s *NoopPaymentSigner) GetAccountID() string { return "" } @@ -106,26 +90,6 @@ func VerifyPaymentSignature(paymentHeader *core.PaymentMetadata, paymentSignatur return nil } -// VerifyAccountSignature verifies the signature against an account ID -func VerifyAccountSignature(accountID string, paymentSignature []byte) bool { - pubKeyBytes, err := hex.DecodeString(accountID) - if err != nil { - log.Printf("Failed to decode AccountId: %v\n", err) - return false - } - accountPubKey, err := crypto.UnmarshalPubkey(pubKeyBytes) - if err != nil { - log.Printf("Failed to unmarshal public key: %v\n", err) - return false - } - - return crypto.VerifySignature( - crypto.FromECDSAPub(accountPubKey), - []byte(accountID), - paymentSignature[:len(paymentSignature)-1], // Remove recovery ID - ) -} - // GetAccountID returns the Ethereum address of the signer func (s *paymentSigner) GetAccountID() string { publicKey := crypto.FromECDSAPub(&s.PrivateKey.PublicKey) diff --git a/core/data.go b/core/data.go index ebc9f170f..1a3b5218a 100644 --- a/core/data.go +++ b/core/data.go @@ -602,7 +602,7 @@ func ConvertToPaymentMetadata(ph *commonpb.PaymentHeader) *PaymentMetadata { // corresponding to a particular quorum type ActiveReservation struct { SymbolsPerSec uint64 // reserve number of symbols per second - //TODO: we are not using start and end timestamp, should remove + //TODO: we are not using start and end timestamp, add check or remove StartTimestamp uint64 // Unix timestamp that's valid for basically eternity EndTimestamp uint64 diff --git a/inabox/tests/integration_test.go b/inabox/tests/integration_test.go index 7b17bc9e5..36cedebe4 100644 --- a/inabox/tests/integration_test.go +++ b/inabox/tests/integration_test.go @@ -35,14 +35,12 @@ var _ = Describe("Inabox Integration", func() { privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcded" signer := auth.NewLocalBlobRequestSigner(privateKeyHex) - paymentSigner, err := auth.NewPaymentSigner(privateKeyHex) - Expect(err).To(BeNil()) disp, err := clients.NewDisperserClient(&clients.Config{ Hostname: "localhost", Port: "32003", Timeout: 10 * time.Second, - }, signer, paymentSigner) + }, signer) Expect(err).To(BeNil()) Expect(disp).To(Not(BeNil())) diff --git a/inabox/tests/ratelimit_test.go b/inabox/tests/ratelimit_test.go index c492d15b9..f3972fc81 100644 --- a/inabox/tests/ratelimit_test.go +++ b/inabox/tests/ratelimit_test.go @@ -11,7 +11,6 @@ import ( grpcdisperser "github.com/Layr-Labs/eigenda/api/grpc/disperser" "github.com/Layr-Labs/eigenda/api/grpc/retriever" "github.com/Layr-Labs/eigenda/core" - "github.com/Layr-Labs/eigenda/core/auth" "github.com/Layr-Labs/eigenda/disperser" "github.com/Layr-Labs/eigenda/inabox/deploy" "github.com/stretchr/testify/assert" @@ -108,12 +107,11 @@ func testRatelimit(t *testing.T, testConfig *deploy.Config, c ratelimitTestCase) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() - noopPaymentSigner := auth.NewNoopPaymentSigner() disp, err := clients.NewDisperserClient(&clients.Config{ Hostname: "localhost", Port: testConfig.Dispersers[0].DISPERSER_SERVER_GRPC_PORT, Timeout: 10 * time.Second, - }, nil, noopPaymentSigner) + }, nil) assert.NoError(t, err) assert.NotNil(t, disp) diff --git a/tools/traffic/generator.go b/tools/traffic/generator.go index f979ac177..5afdf0b56 100644 --- a/tools/traffic/generator.go +++ b/tools/traffic/generator.go @@ -31,7 +31,7 @@ func NewTrafficGenerator(config *Config, signer core.BlobRequestSigner) (*Traffi return nil, fmt.Errorf("new logger: %w", err) } - dispserserClient, err := clients.NewDisperserClient(&config.Config, signer, nil) + dispserserClient, err := clients.NewDisperserClient(&config.Config, signer) if err != nil { return nil, fmt.Errorf("new disperser-client: %w", err) } diff --git a/tools/traffic/generator_v2.go b/tools/traffic/generator_v2.go index c95efa111..060aa4945 100644 --- a/tools/traffic/generator_v2.go +++ b/tools/traffic/generator_v2.go @@ -89,7 +89,7 @@ func NewTrafficGeneratorV2(config *config.Config) (*Generator, error) { unconfirmedKeyChannel := make(chan *workers.UnconfirmedKey, 100) // TODO: create a dedicated reservation for traffic generator and create a payment signer - disperserClient, err := clients.NewDisperserClient(config.DisperserClientConfig, signer, nil) + disperserClient, err := clients.NewDisperserClient(config.DisperserClientConfig, signer) if err != nil { cancel() return nil, fmt.Errorf("new disperser-client: %w", err) From 5199befc8d3998554a3381e8b948121b3f4a8f31 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 03:18:38 -0800 Subject: [PATCH 06/18] fix: lint --- core/auth/payment_signer.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/auth/payment_signer.go b/core/auth/payment_signer.go index b22283040..a6f11c28a 100644 --- a/core/auth/payment_signer.go +++ b/core/auth/payment_signer.go @@ -2,7 +2,9 @@ package auth import ( "crypto/ecdsa" + "encoding/hex" "fmt" + "log" "github.com/Layr-Labs/eigenda/core" "github.com/ethereum/go-ethereum/common" @@ -90,6 +92,26 @@ func VerifyPaymentSignature(paymentHeader *core.PaymentMetadata, paymentSignatur return nil } +// VerifyAccountSignature verifies the signature against an account ID +func VerifyAccountSignature(accountID string, paymentSignature []byte) bool { + pubKeyBytes, err := hex.DecodeString(accountID) + if err != nil { + log.Printf("Failed to decode AccountId: %v\n", err) + return false + } + accountPubKey, err := crypto.UnmarshalPubkey(pubKeyBytes) + if err != nil { + log.Printf("Failed to unmarshal public key: %v\n", err) + return false + } + + return crypto.VerifySignature( + crypto.FromECDSAPub(accountPubKey), + []byte(accountID), + paymentSignature[:len(paymentSignature)-1], // Remove recovery ID + ) +} + // GetAccountID returns the Ethereum address of the signer func (s *paymentSigner) GetAccountID() string { publicKey := crypto.FromECDSAPub(&s.PrivateKey.PublicKey) From 0894fa7526ec814c33f49dade5dd5ee7015f2664 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 06:14:14 -0800 Subject: [PATCH 07/18] fix: use existing signaturemethod --- api/clients/accountant.go | 24 ++--- api/clients/accountant_test.go | 86 ++++++++--------- api/clients/mock/disperser_client.go | 1 + core/auth/payment_signer.go | 121 ------------------------ core/auth/payment_signer_test.go | 78 --------------- disperser/apiserver/disperse_blob_v2.go | 6 -- tools/traffic/generator_v2.go | 2 +- 7 files changed, 50 insertions(+), 268 deletions(-) delete mode 100644 core/auth/payment_signer.go delete mode 100644 core/auth/payment_signer_test.go diff --git a/api/clients/accountant.go b/api/clients/accountant.go index 122ec3eea..08d714703 100644 --- a/api/clients/accountant.go +++ b/api/clients/accountant.go @@ -17,13 +17,14 @@ var minNumBins uint32 = 3 var requiredQuorums = []uint8{0, 1} type Accountant interface { - AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, []byte, error) + AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, error) } var _ Accountant = &accountant{} type accountant struct { // on-chain states + accountID string reservation *core.ActiveReservation onDemand *core.OnDemandPayment reservationWindow uint32 @@ -36,8 +37,7 @@ type accountant struct { usageLock sync.Mutex cumulativePayment *big.Int - paymentSigner core.PaymentSigner - numBins uint32 + numBins uint32 } type BinRecord struct { @@ -45,7 +45,7 @@ type BinRecord struct { Usage uint64 } -func NewAccountant(reservation *core.ActiveReservation, onDemand *core.OnDemandPayment, reservationWindow uint32, pricePerSymbol uint32, minNumSymbols uint32, paymentSigner core.PaymentSigner, numBins uint32) *accountant { +func NewAccountant(accountID string, reservation *core.ActiveReservation, onDemand *core.OnDemandPayment, reservationWindow uint32, pricePerSymbol uint32, minNumSymbols uint32, numBins uint32) *accountant { //TODO: client storage; currently every instance starts fresh but on-chain or a small store makes more sense // Also client is currently responsible for supplying network params, we need to add RPC in order to be automatic // There's a subsequent PR that handles populating the accountant with on-chain state from the disperser @@ -54,6 +54,7 @@ func NewAccountant(reservation *core.ActiveReservation, onDemand *core.OnDemandP binRecords[i] = BinRecord{Index: uint32(i), Usage: 0} } a := accountant{ + accountID: accountID, reservation: reservation, onDemand: onDemand, reservationWindow: reservationWindow, @@ -61,7 +62,6 @@ func NewAccountant(reservation *core.ActiveReservation, onDemand *core.OnDemandP minNumSymbols: minNumSymbols, binRecords: binRecords, cumulativePayment: big.NewInt(0), - paymentSigner: paymentSigner, numBins: max(numBins, minNumBins), } // TODO: add a routine to refresh the on-chain state occasionally? @@ -116,26 +116,20 @@ func (a *accountant) BlobPaymentInfo(ctx context.Context, numSymbols uint64, quo } // AccountBlob accountant provides and records payment information -func (a *accountant) AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, []byte, error) { +func (a *accountant) AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*commonpb.PaymentHeader, error) { binIndex, cumulativePayment, err := a.BlobPaymentInfo(ctx, numSymbols, quorums) if err != nil { - return nil, nil, err + return nil, err } - accountID := a.paymentSigner.GetAccountID() pm := &core.PaymentMetadata{ - AccountID: accountID, + AccountID: a.accountID, BinIndex: binIndex, CumulativePayment: cumulativePayment, } protoPaymentHeader := pm.ConvertToProtoPaymentHeader() - signature, err := a.paymentSigner.SignBlobPayment(pm) - if err != nil { - return nil, nil, err - } - - return protoPaymentHeader, signature, nil + return protoPaymentHeader, nil } // TODO: PaymentCharged and SymbolsCharged copied from meterer, should be refactored diff --git a/api/clients/accountant_test.go b/api/clients/accountant_test.go index d40f75550..979c08792 100644 --- a/api/clients/accountant_test.go +++ b/api/clients/accountant_test.go @@ -9,7 +9,6 @@ import ( "time" "github.com/Layr-Labs/eigenda/core" - "github.com/Layr-Labs/eigenda/core/auth" "github.com/Layr-Labs/eigenda/core/meterer" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" @@ -34,9 +33,8 @@ func TestNewAccountant(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) assert.NotNil(t, accountant) assert.Equal(t, reservation, accountant.reservation) @@ -65,15 +63,14 @@ func TestAccountBlob_Reservation(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() symbolLength := uint64(500) quorums := []uint8{0, 1} - header, _, err := accountant.AccountBlob(ctx, symbolLength, quorums) + header, err := accountant.AccountBlob(ctx, symbolLength, quorums) metadata := core.ConvertPaymentHeader(header) assert.NoError(t, err) @@ -83,7 +80,7 @@ func TestAccountBlob_Reservation(t *testing.T) { symbolLength = uint64(700) - header, _, err = accountant.AccountBlob(ctx, symbolLength, quorums) + header, err = accountant.AccountBlob(ctx, symbolLength, quorums) metadata = core.ConvertPaymentHeader(header) assert.NoError(t, err) @@ -92,7 +89,7 @@ func TestAccountBlob_Reservation(t *testing.T) { assert.Equal(t, isRotation([]uint64{1200, 0, 200}, mapRecordUsage(accountant.binRecords)), true) // Second call should use on-demand payment - header, _, err = accountant.AccountBlob(ctx, 300, quorums) + header, err = accountant.AccountBlob(ctx, 300, quorums) metadata = core.ConvertPaymentHeader(header) assert.NoError(t, err) @@ -117,15 +114,14 @@ func TestAccountBlob_OnDemand(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() numSymbols := uint64(1500) quorums := []uint8{0, 1} - header, _, err := accountant.AccountBlob(ctx, numSymbols, quorums) + header, err := accountant.AccountBlob(ctx, numSymbols, quorums) assert.NoError(t, err) metadata := core.ConvertPaymentHeader(header) @@ -147,15 +143,14 @@ func TestAccountBlob_InsufficientOnDemand(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() numSymbols := uint64(2000) quorums := []uint8{0, 1} - _, _, err = accountant.AccountBlob(ctx, numSymbols, quorums) + _, err = accountant.AccountBlob(ctx, numSymbols, quorums) assert.Contains(t, err.Error(), "neither reservation nor on-demand payment is available") } @@ -176,37 +171,36 @@ func TestAccountBlobCallSeries(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() quorums := []uint8{0, 1} now := time.Now().Unix() // First call: Use reservation - header, _, err := accountant.AccountBlob(ctx, 800, quorums) + header, err := accountant.AccountBlob(ctx, 800, quorums) metadata := core.ConvertPaymentHeader(header) assert.NoError(t, err) assert.Equal(t, meterer.GetBinIndex(uint64(now), reservationWindow), header.BinIndex) assert.Equal(t, big.NewInt(0), metadata.CumulativePayment) // Second call: Use remaining reservation + overflow - header, _, err = accountant.AccountBlob(ctx, 300, quorums) + header, err = accountant.AccountBlob(ctx, 300, quorums) metadata = core.ConvertPaymentHeader(header) assert.NoError(t, err) assert.Equal(t, meterer.GetBinIndex(uint64(now), reservationWindow), header.BinIndex) assert.Equal(t, big.NewInt(0), metadata.CumulativePayment) // Third call: Use on-demand - header, _, err = accountant.AccountBlob(ctx, 500, quorums) + header, err = accountant.AccountBlob(ctx, 500, quorums) metadata = core.ConvertPaymentHeader(header) assert.NoError(t, err) assert.Equal(t, uint32(0), header.BinIndex) assert.Equal(t, big.NewInt(500), metadata.CumulativePayment) // Fourth call: Insufficient on-demand - _, _, err = accountant.AccountBlob(ctx, 600, quorums) + _, err = accountant.AccountBlob(ctx, 600, quorums) assert.Error(t, err) assert.Contains(t, err.Error(), "neither reservation nor on-demand payment is available") } @@ -225,17 +219,17 @@ func TestAccountBlob_BinRotation(t *testing.T) { reservationWindow := uint32(1) // Set to 1 second for testing pricePerSymbol := uint32(1) minNumSymbols := uint32(100) + privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() quorums := []uint8{0, 1} // First call - _, _, err = accountant.AccountBlob(ctx, 800, quorums) + _, err = accountant.AccountBlob(ctx, 800, quorums) assert.NoError(t, err) assert.Equal(t, isRotation([]uint64{800, 0, 0}, mapRecordUsage(accountant.binRecords)), true) @@ -243,12 +237,12 @@ func TestAccountBlob_BinRotation(t *testing.T) { time.Sleep(1000 * time.Millisecond) // Second call - _, _, err = accountant.AccountBlob(ctx, 300, quorums) + _, err = accountant.AccountBlob(ctx, 300, quorums) assert.NoError(t, err) assert.Equal(t, isRotation([]uint64{800, 300, 0}, mapRecordUsage(accountant.binRecords)), true) // Third call - _, _, err = accountant.AccountBlob(ctx, 500, quorums) + _, err = accountant.AccountBlob(ctx, 500, quorums) assert.NoError(t, err) assert.Equal(t, isRotation([]uint64{800, 800, 0}, mapRecordUsage(accountant.binRecords)), true) } @@ -270,9 +264,8 @@ func TestConcurrentBinRotationAndAccountBlob(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() quorums := []uint8{0, 1} @@ -285,7 +278,7 @@ func TestConcurrentBinRotationAndAccountBlob(t *testing.T) { defer wg.Done() // for j := 0; j < 5; j++ { // fmt.Println("request ", i) - _, _, err := accountant.AccountBlob(ctx, 100, quorums) + _, err := accountant.AccountBlob(ctx, 100, quorums) assert.NoError(t, err) time.Sleep(500 * time.Millisecond) // } @@ -317,15 +310,15 @@ func TestAccountBlob_ReservationWithOneOverflow(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) + ctx := context.Background() quorums := []uint8{0, 1} now := time.Now().Unix() // Okay reservation - header, _, err := accountant.AccountBlob(ctx, 800, quorums) + header, err := accountant.AccountBlob(ctx, 800, quorums) assert.NoError(t, err) assert.Equal(t, meterer.GetBinIndex(uint64(now), reservationWindow), header.BinIndex) metadata := core.ConvertPaymentHeader(header) @@ -333,14 +326,14 @@ func TestAccountBlob_ReservationWithOneOverflow(t *testing.T) { assert.Equal(t, isRotation([]uint64{800, 0, 0}, mapRecordUsage(accountant.binRecords)), true) // Second call: Allow one overflow - header, _, err = accountant.AccountBlob(ctx, 500, quorums) + header, err = accountant.AccountBlob(ctx, 500, quorums) assert.NoError(t, err) metadata = core.ConvertPaymentHeader(header) assert.Equal(t, big.NewInt(0), metadata.CumulativePayment) assert.Equal(t, isRotation([]uint64{1300, 0, 300}, mapRecordUsage(accountant.binRecords)), true) // Third call: Should use on-demand payment - header, _, err = accountant.AccountBlob(ctx, 200, quorums) + header, err = accountant.AccountBlob(ctx, 200, quorums) assert.NoError(t, err) assert.Equal(t, uint32(0), header.BinIndex) metadata = core.ConvertPaymentHeader(header) @@ -365,20 +358,19 @@ func TestAccountBlob_ReservationOverflowReset(t *testing.T) { privateKey1, err := crypto.GenerateKey() assert.NoError(t, err) - paymentSigner, err := auth.NewPaymentSigner(hex.EncodeToString(privateKey1.D.Bytes())) - assert.NoError(t, err) - accountant := NewAccountant(reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, paymentSigner, numBins) + accountId := hex.EncodeToString(privateKey1.D.Bytes()) + accountant := NewAccountant(accountId, reservation, onDemand, reservationWindow, pricePerSymbol, minNumSymbols, numBins) ctx := context.Background() quorums := []uint8{0, 1} // full reservation - _, _, err = accountant.AccountBlob(ctx, 1000, quorums) + _, err = accountant.AccountBlob(ctx, 1000, quorums) assert.NoError(t, err) assert.Equal(t, isRotation([]uint64{1000, 0, 0}, mapRecordUsage(accountant.binRecords)), true) // no overflow - header, _, err := accountant.AccountBlob(ctx, 500, quorums) + header, err := accountant.AccountBlob(ctx, 500, quorums) assert.NoError(t, err) assert.Equal(t, isRotation([]uint64{1000, 0, 0}, mapRecordUsage(accountant.binRecords)), true) metadata := core.ConvertPaymentHeader(header) @@ -388,7 +380,7 @@ func TestAccountBlob_ReservationOverflowReset(t *testing.T) { time.Sleep(time.Duration(reservationWindow) * time.Second) // Third call: Should use new bin and allow overflow again - _, _, err = accountant.AccountBlob(ctx, 500, quorums) + _, err = accountant.AccountBlob(ctx, 500, quorums) assert.NoError(t, err) assert.Equal(t, isRotation([]uint64{1000, 500, 0}, mapRecordUsage(accountant.binRecords)), true) } diff --git a/api/clients/mock/disperser_client.go b/api/clients/mock/disperser_client.go index ffdb0b4b9..3763e8130 100644 --- a/api/clients/mock/disperser_client.go +++ b/api/clients/mock/disperser_client.go @@ -80,6 +80,7 @@ func (c *MockDisperserClient) DisperseBlob(ctx context.Context, data []byte, quo return status, key, err } + func (c *MockDisperserClient) GetBlobStatus(ctx context.Context, key []byte) (*disperser_rpc.BlobStatusReply, error) { args := c.Called(key) var reply *disperser_rpc.BlobStatusReply diff --git a/core/auth/payment_signer.go b/core/auth/payment_signer.go deleted file mode 100644 index a6f11c28a..000000000 --- a/core/auth/payment_signer.go +++ /dev/null @@ -1,121 +0,0 @@ -package auth - -import ( - "crypto/ecdsa" - "encoding/hex" - "fmt" - "log" - - "github.com/Layr-Labs/eigenda/core" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -type paymentSigner struct { - PrivateKey *ecdsa.PrivateKey -} - -var _ core.PaymentSigner = &paymentSigner{} - -func NewPaymentSigner(privateKeyHex string) (*paymentSigner, error) { - if len(privateKeyHex) == 0 { - return nil, fmt.Errorf("private key cannot be empty") - } - privateKeyBytes := common.FromHex(privateKeyHex) - privateKey, err := crypto.ToECDSA(privateKeyBytes) - if err != nil { - return nil, fmt.Errorf("failed to convert hex to ECDSA private key: %w", err) - } - - return &paymentSigner{ - PrivateKey: privateKey, - }, nil -} - -// SignBlobPayment signs the payment header and returns the signature -func (s *paymentSigner) SignBlobPayment(pm *core.PaymentMetadata) ([]byte, error) { - hash, err := pm.Hash() - if err != nil { - return nil, fmt.Errorf("failed to hash payment header: %w", err) - } - - sig, err := crypto.Sign(hash[:], s.PrivateKey) - if err != nil { - return nil, fmt.Errorf("failed to sign hash: %w", err) - } - - return sig, nil -} - -type NoopPaymentSigner struct{} - -func NewNoopPaymentSigner() *NoopPaymentSigner { - return &NoopPaymentSigner{} -} - -func (s *NoopPaymentSigner) SignBlobPayment(header *core.PaymentMetadata) ([]byte, error) { - return nil, fmt.Errorf("noop signer cannot sign blob payment header") -} - -func (s *NoopPaymentSigner) GetAccountID() string { - return "" -} - -// VerifyPaymentSignature verifies the signature against the payment metadata -func VerifyPaymentSignature(paymentHeader *core.PaymentMetadata, paymentSignature []byte) error { - hash, err := paymentHeader.Hash() - if err != nil { - return fmt.Errorf("failed to hash payment header: %w", err) - } - - recoveredPubKey, err := crypto.SigToPub(hash[:], paymentSignature) - if err != nil { - return fmt.Errorf("failed to recover public key from signature: %w", err) - } - - recoveredAddress := crypto.PubkeyToAddress(*recoveredPubKey) - accountId := common.HexToAddress(paymentHeader.AccountID) - if recoveredAddress != accountId { - return fmt.Errorf("signature address %s does not match account id %s", recoveredAddress.Hex(), accountId.Hex()) - } - - ok := crypto.VerifySignature( - crypto.FromECDSAPub(recoveredPubKey), - hash[:], - paymentSignature[:len(paymentSignature)-1], // Remove recovery ID - ) - - if !ok { - return fmt.Errorf("invalid signature") - } - - return nil -} - -// VerifyAccountSignature verifies the signature against an account ID -func VerifyAccountSignature(accountID string, paymentSignature []byte) bool { - pubKeyBytes, err := hex.DecodeString(accountID) - if err != nil { - log.Printf("Failed to decode AccountId: %v\n", err) - return false - } - accountPubKey, err := crypto.UnmarshalPubkey(pubKeyBytes) - if err != nil { - log.Printf("Failed to unmarshal public key: %v\n", err) - return false - } - - return crypto.VerifySignature( - crypto.FromECDSAPub(accountPubKey), - []byte(accountID), - paymentSignature[:len(paymentSignature)-1], // Remove recovery ID - ) -} - -// GetAccountID returns the Ethereum address of the signer -func (s *paymentSigner) GetAccountID() string { - publicKey := crypto.FromECDSAPub(&s.PrivateKey.PublicKey) - hash := crypto.Keccak256(publicKey[1:]) - - return common.BytesToAddress(hash[12:]).Hex() -} diff --git a/core/auth/payment_signer_test.go b/core/auth/payment_signer_test.go deleted file mode 100644 index e2c1a172a..000000000 --- a/core/auth/payment_signer_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package auth_test - -import ( - "encoding/hex" - "math/big" - "testing" - - "github.com/Layr-Labs/eigenda/core" - "github.com/Layr-Labs/eigenda/core/auth" - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestPaymentSigner(t *testing.T) { - privateKey, err := crypto.GenerateKey() - require.NoError(t, err) - - privateKeyHex := hex.EncodeToString(crypto.FromECDSA(privateKey)) - signer, err := auth.NewPaymentSigner(privateKeyHex) - require.NoError(t, err) - - t.Run("SignBlobPayment", func(t *testing.T) { - header := &core.PaymentMetadata{ - AccountID: signer.GetAccountID(), - BinIndex: 1, - CumulativePayment: big.NewInt(1), - } - - signature, err := signer.SignBlobPayment(header) - require.NoError(t, err) - assert.NotEmpty(t, signature) - - // Verify the signature - err = auth.VerifyPaymentSignature(header, signature) - assert.NoError(t, err) - }) - - t.Run("VerifyPaymentSignature_InvalidSignature", func(t *testing.T) { - header := &core.PaymentMetadata{ - BinIndex: 1, - CumulativePayment: big.NewInt(1), - AccountID: signer.GetAccountID(), - } - - // Create an invalid signature - invalidSignature := make([]byte, 65) - err = auth.VerifyPaymentSignature(header, invalidSignature) - assert.Error(t, err) - }) - - t.Run("VerifyPaymentSignature_ModifiedHeader", func(t *testing.T) { - header := &core.PaymentMetadata{ - BinIndex: 1, - CumulativePayment: big.NewInt(1), - AccountID: signer.GetAccountID(), - } - - signature, err := signer.SignBlobPayment(header) - require.NoError(t, err) - - // Modify the header after signing - header.BinIndex = 2 - - err = auth.VerifyPaymentSignature(header, signature) - assert.Error(t, err) - }) -} - -func TestNoopPaymentSigner(t *testing.T) { - signer := auth.NewNoopPaymentSigner() - - t.Run("SignBlobRequest", func(t *testing.T) { - _, err := signer.SignBlobPayment(nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "noop signer cannot sign blob payment header") - }) -} diff --git a/disperser/apiserver/disperse_blob_v2.go b/disperser/apiserver/disperse_blob_v2.go index a56e6ca93..8149c34fe 100644 --- a/disperser/apiserver/disperse_blob_v2.go +++ b/disperser/apiserver/disperse_blob_v2.go @@ -9,7 +9,6 @@ import ( "github.com/Layr-Labs/eigenda/api" pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" "github.com/Layr-Labs/eigenda/core" - "github.com/Layr-Labs/eigenda/core/auth" corev2 "github.com/Layr-Labs/eigenda/core/v2" dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2" "github.com/Layr-Labs/eigenda/encoding" @@ -37,10 +36,6 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl if req.GetBlobHeader().GetPaymentHeader() != nil { binIndex := req.GetBlobHeader().GetPaymentHeader().GetBinIndex() cumulativePayment := new(big.Int).SetBytes(req.GetBlobHeader().GetPaymentHeader().GetCumulativePayment()) - signature := req.GetBlobHeader().GetSignature() - if err := auth.VerifyPaymentSignature(core.ConvertToPaymentMetadata(req.GetBlobHeader().GetPaymentHeader()), signature); err != nil { - return nil, api.NewErrorInvalidArg("payment signature is invalid") - } paymentHeader := core.PaymentMetadata{ AccountID: req.GetBlobHeader().GetPaymentHeader().GetAccountId(), @@ -54,7 +49,6 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl return nil, api.NewErrorResourceExhausted(err.Error()) } } else { - // Q: do we want a seprate check to use original rate limiter if there's no payment attached? return nil, api.NewErrorInvalidArg("payment header is required") } diff --git a/tools/traffic/generator_v2.go b/tools/traffic/generator_v2.go index 060aa4945..dc39b4af8 100644 --- a/tools/traffic/generator_v2.go +++ b/tools/traffic/generator_v2.go @@ -88,7 +88,7 @@ func NewTrafficGeneratorV2(config *config.Config) (*Generator, error) { unconfirmedKeyChannel := make(chan *workers.UnconfirmedKey, 100) - // TODO: create a dedicated reservation for traffic generator and create a payment signer + // TODO: create a dedicated reservation for traffic generator disperserClient, err := clients.NewDisperserClient(config.DisperserClientConfig, signer) if err != nil { cancel() From 04e19c51f4147f703b082f9349db3dfa88898c14 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 07:22:18 -0800 Subject: [PATCH 08/18] feat: add payment request validation and tests --- core/auth/v2/auth_test.go | 96 ++++++++++++++++++++++++++++++++ core/auth/v2/authenticator.go | 38 ++++++++++++- core/auth/v2/signer.go | 21 +++++++ core/v2/auth.go | 4 ++ disperser/apiserver/server_v2.go | 6 +- 5 files changed, 159 insertions(+), 6 deletions(-) diff --git a/core/auth/v2/auth_test.go b/core/auth/v2/auth_test.go index cf5a474c8..89dd760b4 100644 --- a/core/auth/v2/auth_test.go +++ b/core/auth/v2/auth_test.go @@ -1,14 +1,17 @@ package v2_test import ( + "crypto/sha256" "math/big" "testing" + pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" "github.com/Layr-Labs/eigenda/core" auth "github.com/Layr-Labs/eigenda/core/auth/v2" corev2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/encoding" "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" ) @@ -114,3 +117,96 @@ func testHeader(t *testing.T, accountID string) *corev2.BlobHeader { Signature: []byte{}, } } + +func TestAuthenticatePaymentStateRequestValid(t *testing.T) { + signer := auth.NewLocalBlobRequestSigner(privateKeyHex) + authenticator := auth.NewAuthenticator() + + signature, err := signer.SignPaymentStateRequest() + assert.NoError(t, err) + + accountId, err := signer.GetAccountID() + + assert.NoError(t, err) + + request := &pb.GetPaymentStateRequest{ + AccountId: accountId, + Signature: signature, + } + + err = authenticator.AuthenticatePaymentStateRequest(request) + assert.NoError(t, err) +} + +func TestAuthenticatePaymentStateRequestInvalidSignatureLength(t *testing.T) { + authenticator := auth.NewAuthenticator() + + request := &pb.GetPaymentStateRequest{ + AccountId: "0x123", + Signature: []byte{1, 2, 3}, // Invalid length + } + + err := authenticator.AuthenticatePaymentStateRequest(request) + assert.Error(t, err) + assert.Contains(t, err.Error(), "signature length is unexpected") +} + +func TestAuthenticatePaymentStateRequestInvalidPublicKey(t *testing.T) { + authenticator := auth.NewAuthenticator() + + request := &pb.GetPaymentStateRequest{ + AccountId: "not-hex-encoded", + Signature: make([]byte, 65), + } + + err := authenticator.AuthenticatePaymentStateRequest(request) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to decode public key") +} + +func TestAuthenticatePaymentStateRequestSignatureMismatch(t *testing.T) { + signer := auth.NewLocalBlobRequestSigner(privateKeyHex) + authenticator := auth.NewAuthenticator() + + // Create a different signer with wrong private key + wrongSigner := auth.NewLocalBlobRequestSigner("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcded") + + // Sign with wrong key + accountId, err := signer.GetAccountID() + assert.NoError(t, err) + + signature, err := wrongSigner.SignPaymentStateRequest() + assert.NoError(t, err) + + request := &pb.GetPaymentStateRequest{ + AccountId: accountId, + Signature: signature, + } + + err = authenticator.AuthenticatePaymentStateRequest(request) + assert.Error(t, err) + assert.Contains(t, err.Error(), "signature doesn't match with provided public key") +} + +func TestAuthenticatePaymentStateRequestCorruptedSignature(t *testing.T) { + signer := auth.NewLocalBlobRequestSigner(privateKeyHex) + authenticator := auth.NewAuthenticator() + + accountId, err := signer.GetAccountID() + assert.NoError(t, err) + + hash := sha256.Sum256([]byte(accountId)) + signature, err := crypto.Sign(hash[:], signer.PrivateKey) + assert.NoError(t, err) + + // Corrupt the signature + signature[0] ^= 0x01 + + request := &pb.GetPaymentStateRequest{ + AccountId: accountId, + Signature: signature, + } + + err = authenticator.AuthenticatePaymentStateRequest(request) + assert.Error(t, err) +} diff --git a/core/auth/v2/authenticator.go b/core/auth/v2/authenticator.go index 4d8c9615a..6d8963611 100644 --- a/core/auth/v2/authenticator.go +++ b/core/auth/v2/authenticator.go @@ -2,11 +2,12 @@ package v2 import ( "bytes" + "crypto/sha256" "errors" "fmt" + pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" core "github.com/Layr-Labs/eigenda/core/v2" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" ) @@ -40,7 +41,7 @@ func (*authenticator) AuthenticateBlobRequest(header *core.BlobHeader) error { // Decode public key pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes) if err != nil { - return fmt.Errorf("failed to decode public key (%v): %v", header.PaymentMetadata.AccountID, err) + return fmt.Errorf("failed to convert bytes to public key (%v): %v", header.PaymentMetadata.AccountID, err) } // Verify the signature @@ -55,3 +56,36 @@ func (*authenticator) AuthenticateBlobRequest(header *core.BlobHeader) error { return nil } + +func (*authenticator) AuthenticatePaymentStateRequest(request *pb.GetPaymentStateRequest) error { + // Ensure the signature is 65 bytes (Recovery ID is the last byte) + sig := request.GetSignature() + if len(sig) != 65 { + return fmt.Errorf("signature length is unexpected: %d", len(sig)) + } + + // Decode public key + publicKeyBytes, err := hexutil.Decode(request.GetAccountId()) + if err != nil { + return fmt.Errorf("failed to decode public key (%v): %v", request.GetAccountId(), err) + } + + // Convert bytes to public key + pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes) + if err != nil { + return fmt.Errorf("failed to convert bytes to public key (%v): %v", request.GetAccountId(), err) + } + + // Verify the signature + hash := sha256.Sum256([]byte(request.GetAccountId())) + sigPublicKeyECDSA, err := crypto.SigToPub(hash[:], sig) + if err != nil { + return fmt.Errorf("failed to recover public key from signature: %v", err) + } + + if !bytes.Equal(pubKey.X.Bytes(), sigPublicKeyECDSA.X.Bytes()) || !bytes.Equal(pubKey.Y.Bytes(), sigPublicKeyECDSA.Y.Bytes()) { + return errors.New("signature doesn't match with provided public key") + } + + return nil +} diff --git a/core/auth/v2/signer.go b/core/auth/v2/signer.go index bac6f3684..24b7e9cc4 100644 --- a/core/auth/v2/signer.go +++ b/core/auth/v2/signer.go @@ -2,6 +2,7 @@ package v2 import ( "crypto/ecdsa" + "crypto/sha256" "fmt" "log" @@ -44,6 +45,22 @@ func (s *LocalBlobRequestSigner) SignBlobRequest(header *core.BlobHeader) ([]byt return sig, nil } +func (s *LocalBlobRequestSigner) SignPaymentStateRequest() ([]byte, error) { + accountId, err := s.GetAccountID() + if err != nil { + return nil, fmt.Errorf("failed to get account ID: %v", err) + } + + hash := sha256.Sum256([]byte(accountId)) + // Sign the blob key using the private key + sig, err := crypto.Sign(hash[:], s.PrivateKey) + if err != nil { + return nil, fmt.Errorf("failed to sign hash: %v", err) + } + + return sig, nil +} + func (s *LocalBlobRequestSigner) GetAccountID() (string, error) { publicKeyBytes := crypto.FromECDSAPub(&s.PrivateKey.PublicKey) @@ -63,6 +80,10 @@ func (s *LocalNoopSigner) SignBlobRequest(header *core.BlobHeader) ([]byte, erro return nil, fmt.Errorf("noop signer cannot sign blob request") } +func (s *LocalNoopSigner) SignPaymentStateRequest() ([]byte, error) { + return nil, fmt.Errorf("noop signer cannot sign payment state request") +} + func (s *LocalNoopSigner) GetAccountID() (string, error) { return "", fmt.Errorf("noop signer cannot get accountID") } diff --git a/core/v2/auth.go b/core/v2/auth.go index 7ad714bf8..80e888b3b 100644 --- a/core/v2/auth.go +++ b/core/v2/auth.go @@ -1,10 +1,14 @@ package v2 +import pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" + type BlobRequestAuthenticator interface { AuthenticateBlobRequest(header *BlobHeader) error + AuthenticatePaymentStateRequest(request *pb.GetPaymentStateRequest) error } type BlobRequestSigner interface { SignBlobRequest(header *BlobHeader) ([]byte, error) + SignPaymentStateRequest() ([]byte, error) GetAccountID() (string, error) } diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index 100382e04..503dbc9a2 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -14,7 +14,6 @@ import ( "github.com/Layr-Labs/eigenda/common" healthcheck "github.com/Layr-Labs/eigenda/common/healthcheck" "github.com/Layr-Labs/eigenda/core" - "github.com/Layr-Labs/eigenda/core/auth" "github.com/Layr-Labs/eigenda/core/meterer" corev2 "github.com/Layr-Labs/eigenda/core/v2" v2 "github.com/Layr-Labs/eigenda/core/v2" @@ -213,10 +212,9 @@ func (s *DispersalServerV2) RefreshOnchainState(ctx context.Context) error { func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaymentStateRequest) (*pb.GetPaymentStateReply, error) { // validate the signature - if !auth.VerifyAccountSignature(req.AccountId, req.Signature) { - return nil, api.NewErrorInvalidArg("invalid signature") + if err := s.authenticator.AuthenticatePaymentStateRequest(req); err != nil { + return nil, api.NewErrorInvalidArg(fmt.Sprintf("authentication failed: %s", err.Error())) } - // on-chain global payment parameters globalSymbolsPerSecond := s.meterer.ChainPaymentState.GetGlobalSymbolsPerSecond() minNumSymbols := s.meterer.ChainPaymentState.GetMinNumSymbols() From 3e8633901a52e2cf700ecc175732a34c284305e3 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 09:13:17 -0800 Subject: [PATCH 09/18] fix: tests --- core/meterer/meterer.go | 2 + disperser/apiserver/disperse_blob_v2.go | 3 +- disperser/apiserver/server_v2.go | 2 + disperser/apiserver/server_v2_test.go | 49 ++++++++++++++++++++++++- disperser/cmd/apiserver/main.go | 1 + 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/core/meterer/meterer.go b/core/meterer/meterer.go index ba1f2cfc6..06374ce29 100644 --- a/core/meterer/meterer.go +++ b/core/meterer/meterer.go @@ -3,6 +3,7 @@ package meterer import ( "context" "fmt" + "log" "slices" "time" @@ -71,6 +72,7 @@ func (m *Meterer) Start(ctx context.Context) { // MeterRequest validates a blob header and adds it to the meterer's state // TODO: return error if there's a rejection (with reasoning) or internal error (should be very rare) func (m *Meterer) MeterRequest(ctx context.Context, header core.PaymentMetadata, numSymbols uint, quorumNumbers []uint8) error { + log.Println(m) // Validate against the payment method if header.CumulativePayment.Sign() == 0 { reservation, err := m.ChainPaymentState.GetActiveReservationByAccount(ctx, header.AccountID) diff --git a/disperser/apiserver/disperse_blob_v2.go b/disperser/apiserver/disperse_blob_v2.go index 8149c34fe..eb615ec58 100644 --- a/disperser/apiserver/disperse_blob_v2.go +++ b/disperser/apiserver/disperse_blob_v2.go @@ -36,9 +36,10 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl if req.GetBlobHeader().GetPaymentHeader() != nil { binIndex := req.GetBlobHeader().GetPaymentHeader().GetBinIndex() cumulativePayment := new(big.Int).SetBytes(req.GetBlobHeader().GetPaymentHeader().GetCumulativePayment()) + accountID := req.GetBlobHeader().GetPaymentHeader().GetAccountId() paymentHeader := core.PaymentMetadata{ - AccountID: req.GetBlobHeader().GetPaymentHeader().GetAccountId(), + AccountID: accountID, BinIndex: binIndex, CumulativePayment: cumulativePayment, } diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index 503dbc9a2..ad7452cf6 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -59,6 +59,7 @@ func NewDispersalServerV2( blobMetadataStore *blobstore.BlobMetadataStore, chainReader core.Reader, ratelimiter common.RateLimiter, + meterer *meterer.Meterer, authenticator corev2.BlobRequestAuthenticator, prover encoding.Prover, maxNumSymbolsPerBlob uint64, @@ -74,6 +75,7 @@ func NewDispersalServerV2( chainReader: chainReader, authenticator: authenticator, + meterer: meterer, prover: prover, logger: logger, diff --git a/disperser/apiserver/server_v2_test.go b/disperser/apiserver/server_v2_test.go index 77afef008..2a836c866 100644 --- a/disperser/apiserver/server_v2_test.go +++ b/disperser/apiserver/server_v2_test.go @@ -14,6 +14,7 @@ import ( "github.com/Layr-Labs/eigenda/common/aws/s3" "github.com/Layr-Labs/eigenda/core" auth "github.com/Layr-Labs/eigenda/core/auth/v2" + "github.com/Layr-Labs/eigenda/core/meterer" "github.com/Layr-Labs/eigenda/core/mock" corev2 "github.com/Layr-Labs/eigenda/core/v2" v2 "github.com/Layr-Labs/eigenda/core/v2" @@ -431,6 +432,52 @@ func newTestServerV2(t *testing.T) *testComponents { chainReader := &mock.MockWriter{} rateConfig := apiserver.RateConfig{} + // append test name to each table name for an unique store + mockState := &mock.MockOnchainPaymentState{} + mockState.On("RefreshOnchainPaymentState", tmock.Anything).Return(nil).Maybe() + mockState.On("GetReservationWindow", tmock.Anything).Return(uint32(1), nil) + mockState.On("GetPricePerSymbol", tmock.Anything).Return(uint32(2), nil) + mockState.On("GetGlobalSymbolsPerSecond", tmock.Anything).Return(uint64(1009), nil) + mockState.On("GetMinNumSymbols", tmock.Anything).Return(uint32(3), nil) + + now := uint64(time.Now().Unix()) + mockState.On("GetActiveReservationByAccount", tmock.Anything, tmock.Anything).Return(core.ActiveReservation{SymbolsPerSec: 100, StartTimestamp: now + 1200, EndTimestamp: now + 1800, QuorumSplit: []byte{50, 50}, QuorumNumbers: []uint8{0, 1}}, nil) + mockState.On("GetOnDemandPaymentByAccount", tmock.Anything, tmock.Anything).Return(core.OnDemandPayment{CumulativePayment: big.NewInt(3864)}, nil) + mockState.On("GetOnDemandQuorumNumbers", tmock.Anything).Return([]uint8{0, 1}, nil) + + if err := mockState.RefreshOnchainPaymentState(context.Background(), nil); err != nil { + panic("failed to make initial query to the on-chain state") + } + table_names := []string{"reservations_server_" + t.Name(), "ondemand_server_" + t.Name(), "global_server_" + t.Name()} + err = meterer.CreateReservationTable(awsConfig, table_names[0]) + if err != nil { + teardown() + panic("failed to create reservation table") + } + err = meterer.CreateOnDemandTable(awsConfig, table_names[1]) + if err != nil { + teardown() + panic("failed to create ondemand table") + } + err = meterer.CreateGlobalReservationTable(awsConfig, table_names[2]) + if err != nil { + teardown() + panic("failed to create global reservation table") + } + + store, err := meterer.NewOffchainStore( + awsConfig, + table_names[0], + table_names[1], + table_names[2], + logger, + ) + if err != nil { + teardown() + panic("failed to create offchain store") + } + meterer := meterer.NewMeterer(meterer.Config{}, mockState, store, logger) + chainReader.On("GetCurrentBlockNumber").Return(uint32(100), nil) chainReader.On("GetQuorumCount").Return(uint8(2), nil) chainReader.On("GetRequiredQuorumNumbers", tmock.Anything).Return([]uint8{0, 1}, nil) @@ -447,7 +494,7 @@ func newTestServerV2(t *testing.T) *testComponents { s := apiserver.NewDispersalServerV2(disperser.ServerConfig{ GrpcPort: "51002", GrpcTimeout: 1 * time.Second, - }, rateConfig, blobStore, blobMetadataStore, chainReader, nil, auth.NewAuthenticator(), prover, 10, time.Hour, logger) + }, rateConfig, blobStore, blobMetadataStore, chainReader, nil, meterer, auth.NewAuthenticator(), prover, 100, time.Hour, logger) err = s.RefreshOnchainState(context.Background()) assert.NoError(t, err) diff --git a/disperser/cmd/apiserver/main.go b/disperser/cmd/apiserver/main.go index 0be93b7ab..07ff7936c 100644 --- a/disperser/cmd/apiserver/main.go +++ b/disperser/cmd/apiserver/main.go @@ -176,6 +176,7 @@ func RunDisperserServer(ctx *cli.Context) error { blobMetadataStore, transactor, ratelimiter, + meterer, authv2.NewAuthenticator(), prover, uint64(config.MaxNumSymbolsPerBlob), From ea7f331a1cf6619720c5689f9fee1fb8806ae58f Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 10:29:39 -0800 Subject: [PATCH 10/18] fix: rebase --- disperser/apiserver/server_v2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disperser/apiserver/server_v2_test.go b/disperser/apiserver/server_v2_test.go index 2a836c866..17f84f510 100644 --- a/disperser/apiserver/server_v2_test.go +++ b/disperser/apiserver/server_v2_test.go @@ -494,7 +494,7 @@ func newTestServerV2(t *testing.T) *testComponents { s := apiserver.NewDispersalServerV2(disperser.ServerConfig{ GrpcPort: "51002", GrpcTimeout: 1 * time.Second, - }, rateConfig, blobStore, blobMetadataStore, chainReader, nil, meterer, auth.NewAuthenticator(), prover, 100, time.Hour, logger) + }, rateConfig, blobStore, blobMetadataStore, chainReader, nil, meterer, auth.NewAuthenticator(), prover, 10, time.Hour, logger) err = s.RefreshOnchainState(context.Background()) assert.NoError(t, err) From 8ea4f03e91d20dc8fb87a189b17853ed79214f21 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 22 Nov 2024 10:51:21 -0800 Subject: [PATCH 11/18] refactor: rm log --- core/meterer/meterer.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/meterer/meterer.go b/core/meterer/meterer.go index 06374ce29..ba1f2cfc6 100644 --- a/core/meterer/meterer.go +++ b/core/meterer/meterer.go @@ -3,7 +3,6 @@ package meterer import ( "context" "fmt" - "log" "slices" "time" @@ -72,7 +71,6 @@ func (m *Meterer) Start(ctx context.Context) { // MeterRequest validates a blob header and adds it to the meterer's state // TODO: return error if there's a rejection (with reasoning) or internal error (should be very rare) func (m *Meterer) MeterRequest(ctx context.Context, header core.PaymentMetadata, numSymbols uint, quorumNumbers []uint8) error { - log.Println(m) // Validate against the payment method if header.CumulativePayment.Sign() == 0 { reservation, err := m.ChainPaymentState.GetActiveReservationByAccount(ctx, header.AccountID) From 8dc8bc041c58f501f06f2156e6e5563cb990a3b5 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Tue, 26 Nov 2024 09:08:10 -0800 Subject: [PATCH 12/18] refactor: protobuf comments and rename --- api/grpc/disperser/v2/disperser_v2.pb.go | 214 +++++++++++----------- api/proto/disperser/v2/disperser_v2.proto | 10 +- disperser/apiserver/server_v2.go | 2 +- 3 files changed, 117 insertions(+), 109 deletions(-) diff --git a/api/grpc/disperser/v2/disperser_v2.pb.go b/api/grpc/disperser/v2/disperser_v2.pb.go index b716c88bf..4252de60e 100644 --- a/api/grpc/disperser/v2/disperser_v2.pb.go +++ b/api/grpc/disperser/v2/disperser_v2.pb.go @@ -430,6 +430,8 @@ type GetPaymentStateRequest struct { unknownFields protoimpl.UnknownFields AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` + // Signature over the account ID + // TODO: sign over a bin index to mitigate signature replay attacks Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` } @@ -494,7 +496,7 @@ type GetPaymentStateReply struct { // off-chain on-demand payment usage CumulativePayment []byte `protobuf:"bytes,4,opt,name=cumulative_payment,json=cumulativePayment,proto3" json:"cumulative_payment,omitempty"` // on-chain on-demand payment deposited - OnChainCumulativePayment []byte `protobuf:"bytes,5,opt,name=on_chain_cumulative_payment,json=onChainCumulativePayment,proto3" json:"on_chain_cumulative_payment,omitempty"` + OnchainCumulativePayment []byte `protobuf:"bytes,5,opt,name=onchain_cumulative_payment,json=onchainCumulativePayment,proto3" json:"onchain_cumulative_payment,omitempty"` } func (x *GetPaymentStateReply) Reset() { @@ -557,9 +559,9 @@ func (x *GetPaymentStateReply) GetCumulativePayment() []byte { return nil } -func (x *GetPaymentStateReply) GetOnChainCumulativePayment() []byte { +func (x *GetPaymentStateReply) GetOnchainCumulativePayment() []byte { if x != nil { - return x.OnChainCumulativePayment + return x.OnchainCumulativePayment } return nil } @@ -930,6 +932,8 @@ func (x *Reservation) GetQuorumSplit() []uint32 { return nil } +// BinRecord is the usage record of an account in a bin. The API should return +// the active bin record and the subsequent two records to include potential overflows. type BinRecord struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1036,7 +1040,7 @@ var file_disperser_v2_disperser_v2_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x14, + 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xd1, 0x02, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x55, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, @@ -1054,108 +1058,108 @@ var file_disperser_v2_disperser_v2_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x3d, 0x0a, 0x1b, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x63, 0x75, - 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x22, 0x7a, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, - 0x2e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, - 0x3b, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa5, 0x01, 0x0a, - 0x14, 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x62, 0x6c, 0x6f, - 0x62, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb0, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x6f, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, - 0x52, 0x10, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, - 0x79, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x6b, 0x5f, 0x67, 0x32, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x61, 0x70, 0x6b, 0x47, 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x71, 0x75, 0x6f, - 0x72, 0x75, 0x6d, 0x5f, 0x61, 0x70, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, - 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, - 0x67, 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, - 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x13, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, - 0x39, 0x0a, 0x19, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, - 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x16, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, - 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, - 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x53, 0x79, 0x6d, 0x62, 0x6f, - 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, - 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x70, 0x72, - 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x2d, 0x0a, 0x12, - 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x37, 0x0a, 0x18, 0x6f, - 0x6e, 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x15, 0x6f, - 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, - 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x10, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, - 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x65, - 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, - 0x6d, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0b, 0x71, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x22, 0x37, 0x0a, 0x09, 0x42, 0x69, - 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x14, 0x0a, - 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x75, 0x73, - 0x61, 0x67, 0x65, 0x2a, 0x6a, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, - 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, - 0x43, 0x4f, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x45, 0x52, 0x54, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, - 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, - 0x4e, 0x54, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x32, - 0xf2, 0x02, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x54, 0x0a, - 0x0c, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x2e, - 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, - 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, - 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, + 0x74, 0x12, 0x3c, 0x0a, 0x1a, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x63, 0x75, 0x6d, + 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x75, + 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x22, + 0x7a, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2e, + 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x3b, + 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x32, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, + 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa5, 0x01, 0x0a, 0x14, + 0x42, 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x62, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, + 0x6c, 0x6f, 0x62, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x22, 0xb0, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x6f, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x10, 0x6e, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, + 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x6b, 0x5f, 0x67, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x61, 0x70, 0x6b, 0x47, 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x71, 0x75, 0x6f, 0x72, + 0x75, 0x6d, 0x5f, 0x61, 0x70, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x71, + 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x41, 0x70, 0x6b, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, 0x67, + 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x69, 0x67, 0x6d, 0x61, 0x12, + 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x13, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x39, + 0x0a, 0x19, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, + 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x16, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, + 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, + 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x73, 0x12, 0x28, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, + 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x50, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, + 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6e, + 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x15, 0x6f, 0x6e, + 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x5f, 0x70, + 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x10, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x25, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, + 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0b, 0x71, 0x75, + 0x6f, 0x72, 0x75, 0x6d, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x22, 0x37, 0x0a, 0x09, 0x42, 0x69, 0x6e, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x14, 0x0a, 0x05, + 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x75, 0x73, 0x61, + 0x67, 0x65, 0x2a, 0x6a, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, + 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x43, + 0x4f, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, + 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, + 0x54, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x05, 0x32, 0xf2, + 0x02, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x0c, + 0x44, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x2e, 0x64, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x44, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, + 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, - 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, - 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, - 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, - 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, - 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, - 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x21, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x42, + 0x6c, 0x6f, 0x62, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, + 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, + 0x64, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, 0x65, + 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x69, 0x73, + 0x70, 0x65, 0x72, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/api/proto/disperser/v2/disperser_v2.proto b/api/proto/disperser/v2/disperser_v2.proto index 5a5ce1784..e365838ff 100644 --- a/api/proto/disperser/v2/disperser_v2.proto +++ b/api/proto/disperser/v2/disperser_v2.proto @@ -20,8 +20,8 @@ service Disperser { // GetBlobCommitment is a utility method that calculates commitment for a blob payload. rpc GetBlobCommitment(BlobCommitmentRequest) returns (BlobCommitmentReply) {} - // GetPaymentState is a utility method to get the payment state of a given account. - rpc GetPaymentState(GetPaymentStateRequest) returns (GetPaymentStateReply) {} + // GetPaymentState is a utility method to get the payment state of a given account. + rpc GetPaymentState(GetPaymentStateRequest) returns (GetPaymentStateReply) {} } // Requests and Replys @@ -69,6 +69,8 @@ message BlobCommitmentReply { // GetPaymentStateRequest contains parameters to query the payment state of an account. message GetPaymentStateRequest { string account_id = 1; + // Signature over the account ID + // TODO: sign over a bin index or a nonce to mitigate signature replay attacks bytes signature = 2; } @@ -83,7 +85,7 @@ message GetPaymentStateReply { // off-chain on-demand payment usage bytes cumulative_payment = 4; // on-chain on-demand payment deposited - bytes on_chain_cumulative_payment = 5; + bytes onchain_cumulative_payment = 5; } // Data Types @@ -165,6 +167,8 @@ message Reservation { repeated uint32 quorum_split = 5; } +// BinRecord is the usage record of an account in a bin. The API should return the active bin +// record and the subsequent two records that contains potential overflows. message BinRecord { uint32 index = 1; uint64 usage = 2; diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index ad7452cf6..a40f96f6b 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -279,7 +279,7 @@ func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaym QuorumNumbers: quorumNumbers, }, CumulativePayment: largestCumulativePayment.Bytes(), - OnChainCumulativePayment: onDemandPayment.CumulativePayment.Bytes(), + OnchainCumulativePayment: onDemandPayment.CumulativePayment.Bytes(), } return reply, nil } From 6edca729350154c1817fee36b3719f3a3c941a9e Mon Sep 17 00:00:00 2001 From: hopeyen Date: Tue, 26 Nov 2024 09:08:54 -0800 Subject: [PATCH 13/18] refactor: constants and comments --- api/clients/accountant.go | 4 ++-- core/auth/v2/signer.go | 2 +- core/meterer/offchain_store.go | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/api/clients/accountant.go b/api/clients/accountant.go index 08d714703..375494166 100644 --- a/api/clients/accountant.go +++ b/api/clients/accountant.go @@ -13,7 +13,6 @@ import ( "github.com/Layr-Labs/eigenda/core/meterer" ) -var minNumBins uint32 = 3 var requiredQuorums = []uint8{0, 1} type Accountant interface { @@ -37,6 +36,7 @@ type accountant struct { usageLock sync.Mutex cumulativePayment *big.Int + // number of bins in the circular accounting, restricted by minNumBins which is 3 numBins uint32 } @@ -62,7 +62,7 @@ func NewAccountant(accountID string, reservation *core.ActiveReservation, onDema minNumSymbols: minNumSymbols, binRecords: binRecords, cumulativePayment: big.NewInt(0), - numBins: max(numBins, minNumBins), + numBins: max(numBins, uint32(meterer.MinNumBins)), } // TODO: add a routine to refresh the on-chain state occasionally? return &a diff --git a/core/auth/v2/signer.go b/core/auth/v2/signer.go index 24b7e9cc4..7ceefbe00 100644 --- a/core/auth/v2/signer.go +++ b/core/auth/v2/signer.go @@ -52,7 +52,7 @@ func (s *LocalBlobRequestSigner) SignPaymentStateRequest() ([]byte, error) { } hash := sha256.Sum256([]byte(accountId)) - // Sign the blob key using the private key + // Sign the account ID using the private key sig, err := crypto.Sign(hash[:], s.PrivateKey) if err != nil { return nil, fmt.Errorf("failed to sign hash: %v", err) diff --git a/core/meterer/offchain_store.go b/core/meterer/offchain_store.go index 29686ebd2..88c9ea651 100644 --- a/core/meterer/offchain_store.go +++ b/core/meterer/offchain_store.go @@ -8,6 +8,7 @@ import ( "strconv" "time" + pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" commonaws "github.com/Layr-Labs/eigenda/common/aws" commondynamodb "github.com/Layr-Labs/eigenda/common/aws/dynamodb" "github.com/Layr-Labs/eigenda/core" @@ -17,6 +18,8 @@ import ( "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) +const MinNumBins int32 = 3 + type OffchainStore struct { dynamoClient commondynamodb.Client reservationTableName string From f43ec36a56cb15afb82b5cce578a55956ab66cbf Mon Sep 17 00:00:00 2001 From: hopeyen Date: Tue, 26 Nov 2024 09:09:39 -0800 Subject: [PATCH 14/18] refactor: dynamodb store query fn for BinRecords --- core/meterer/offchain_store.go | 46 ++++++++++++++++++++++---------- disperser/apiserver/server_v2.go | 17 ++---------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/core/meterer/offchain_store.go b/core/meterer/offchain_store.go index 88c9ea651..130bf3048 100644 --- a/core/meterer/offchain_store.go +++ b/core/meterer/offchain_store.go @@ -241,33 +241,33 @@ func (s *OffchainStore) GetRelevantOnDemandRecords(ctx context.Context, accountI return prevPayment, nextPayment, nextDataLength, nil } -func (s *OffchainStore) GetBinUsages(ctx context.Context, accountID string, binIndex uint32) (uint64, uint64, uint64, error) { +func (s *OffchainStore) GetBinRecords(ctx context.Context, accountID string, binIndex uint32) ([3]*pb.BinRecord, error) { // Fetch the 3 bins start from the current bin queryInput := &dynamodb.QueryInput{ TableName: aws.String(s.reservationTableName), - KeyConditionExpression: aws.String("AccountID = :account AND binIndex > :binIndex"), + KeyConditionExpression: aws.String("AccountID = :account AND BinIndex > :binIndex"), ExpressionAttributeValues: commondynamodb.ExpressionValues{ ":account": &types.AttributeValueMemberS{Value: accountID}, ":binIndex": &types.AttributeValueMemberN{Value: strconv.FormatUint(uint64(binIndex), 10)}, }, ScanIndexForward: aws.Bool(true), - Limit: aws.Int32(3), + Limit: aws.Int32(MinNumBins), } bins, err := s.dynamoClient.QueryWithInput(ctx, queryInput) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to query payments for account: %w", err) + return [3]*pb.BinRecord{}, fmt.Errorf("failed to query payments for account: %w", err) } - usages := make([]uint64, 3) + records := [3]*pb.BinRecord{} for i := 0; i < len(bins) && i < 3; i++ { - usage, err := parseBinUsage(bins[i]) + binRecord, err := parseBinRecord(bins[i]) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse bin %d usage: %w", i, err) + return [3]*pb.BinRecord{}, fmt.Errorf("failed to parse bin %d record: %w", i, err) } - usages[i] = usage + records[i] = binRecord } - return usages[0], usages[1], usages[2], nil + return records, nil } func (s *OffchainStore) GetLargestCumulativePayment(ctx context.Context, accountID string) (*big.Int, error) { @@ -298,21 +298,39 @@ func (s *OffchainStore) GetLargestCumulativePayment(ctx context.Context, account return new(big.Int).SetUint64(payment), nil } -func parseBinUsage(bin map[string]types.AttributeValue) (uint64, error) { +func parseBinRecord(bin map[string]types.AttributeValue) (*pb.BinRecord, error) { + binIndex, ok := bin["BinIndex"] + if !ok { + return nil, errors.New("BinIndex is not present in the response") + } + + binIndexAttr, ok := binIndex.(*types.AttributeValueMemberN) + if !ok { + return nil, fmt.Errorf("unexpected type for BinIndex: %T", binIndex) + } + + binIndexValue, err := strconv.ParseUint(binIndexAttr.Value, 10, 32) + if err != nil { + return nil, fmt.Errorf("failed to parse BinIndex: %w", err) + } + binUsage, ok := bin["BinUsage"] if !ok { - return 0, errors.New("BinUsage is not present in the response") + return nil, errors.New("BinUsage is not present in the response") } binUsageAttr, ok := binUsage.(*types.AttributeValueMemberN) if !ok { - return 0, fmt.Errorf("unexpected type for BinUsage: %T", binUsage) + return nil, fmt.Errorf("unexpected type for BinUsage: %T", binUsage) } binUsageValue, err := strconv.ParseUint(binUsageAttr.Value, 10, 32) if err != nil { - return 0, fmt.Errorf("failed to parse BinUsage: %w", err) + return nil, fmt.Errorf("failed to parse BinUsage: %w", err) } - return binUsageValue, nil + return &pb.BinRecord{ + Index: uint32(binIndexValue), + Usage: uint64(binUsageValue), + }, nil } diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index a40f96f6b..9cfa3b72d 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -226,7 +226,7 @@ func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaym // off-chain account specific payment state now := uint64(time.Now().Unix()) currentBinIndex := meterer.GetBinIndex(now, reservationWindow) - currentBinUsage, nextBinUsage, overflowBinUsage, err := s.meterer.OffchainStore.GetBinUsages(ctx, req.AccountId, currentBinIndex) + binRecords, err := s.meterer.OffchainStore.GetBinRecords(ctx, req.AccountId, currentBinIndex) if err != nil { return nil, api.NewErrorNotFound("failed to get active reservation") } @@ -258,20 +258,7 @@ func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaym // build reply reply := &pb.GetPaymentStateReply{ PaymentGlobalParams: &paymentGlobalParams, - BinRecords: []*pb.BinRecord{ - { - Index: uint32(currentBinIndex), - Usage: uint64(currentBinUsage), - }, - { - Index: uint32(currentBinIndex + 1), - Usage: uint64(nextBinUsage), - }, - { - Index: uint32(currentBinIndex + 2), - Usage: uint64(overflowBinUsage), - }, - }, + BinRecords: binRecords[:], Reservation: &pb.Reservation{ SymbolsPerSecond: reservation.SymbolsPerSec, StartTimestamp: uint32(reservation.StartTimestamp), From f015c38da838ccb9875ee3227f629b65a67585d5 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Tue, 26 Nov 2024 09:10:02 -0800 Subject: [PATCH 15/18] refactor: move payments into validateDispersalRequest --- disperser/apiserver/disperse_blob_v2.go | 45 ++++++++++++------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/disperser/apiserver/disperse_blob_v2.go b/disperser/apiserver/disperse_blob_v2.go index eb615ec58..01626ffb8 100644 --- a/disperser/apiserver/disperse_blob_v2.go +++ b/disperser/apiserver/disperse_blob_v2.go @@ -21,7 +21,7 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl return nil, api.NewErrorInternal("onchain state is nil") } - if err := s.validateDispersalRequest(req, onchainState); err != nil { + if err := s.validateDispersalRequest(ctx, req, onchainState); err != nil { return nil, err } @@ -32,27 +32,6 @@ func (s *DispersalServerV2) DisperseBlob(ctx context.Context, req *pb.DisperseBl } s.logger.Debug("received a new blob dispersal request", "blobSizeBytes", len(data), "quorums", req.GetBlobHeader().GetQuorumNumbers()) - // handle payments and check rate limits - if req.GetBlobHeader().GetPaymentHeader() != nil { - binIndex := req.GetBlobHeader().GetPaymentHeader().GetBinIndex() - cumulativePayment := new(big.Int).SetBytes(req.GetBlobHeader().GetPaymentHeader().GetCumulativePayment()) - accountID := req.GetBlobHeader().GetPaymentHeader().GetAccountId() - - paymentHeader := core.PaymentMetadata{ - AccountID: accountID, - BinIndex: binIndex, - CumulativePayment: cumulativePayment, - } - - blobLength := encoding.GetBlobLength(uint(len(data))) - err := s.meterer.MeterRequest(ctx, paymentHeader, blobLength, blobHeader.QuorumNumbers) - if err != nil { - return nil, api.NewErrorResourceExhausted(err.Error()) - } - } else { - return nil, api.NewErrorInvalidArg("payment header is required") - } - blobKey, err := s.StoreBlob(ctx, data, blobHeader, time.Now(), onchainState.TTL) if err != nil { return nil, err @@ -87,7 +66,7 @@ func (s *DispersalServerV2) StoreBlob(ctx context.Context, data []byte, blobHead return blobKey, err } -func (s *DispersalServerV2) validateDispersalRequest(req *pb.DisperseBlobRequest, onchainState *OnchainState) error { +func (s *DispersalServerV2) validateDispersalRequest(ctx context.Context, req *pb.DisperseBlobRequest, onchainState *OnchainState) error { data := req.GetData() blobSize := len(data) if blobSize == 0 { @@ -140,6 +119,26 @@ func (s *DispersalServerV2) validateDispersalRequest(req *pb.DisperseBlobRequest return api.NewErrorInvalidArg("invalid payment metadata") } + // handle payments and check rate limits + if blobHeaderProto.GetPaymentHeader() != nil { + binIndex := blobHeaderProto.GetPaymentHeader().GetBinIndex() + cumulativePayment := new(big.Int).SetBytes(blobHeaderProto.GetPaymentHeader().GetCumulativePayment()) + accountID := blobHeaderProto.GetPaymentHeader().GetAccountId() + + paymentHeader := core.PaymentMetadata{ + AccountID: accountID, + BinIndex: binIndex, + CumulativePayment: cumulativePayment, + } + + err := s.meterer.MeterRequest(ctx, paymentHeader, blobLength, blobHeader.QuorumNumbers) + if err != nil { + return api.NewErrorResourceExhausted(err.Error()) + } + } else { + return api.NewErrorInvalidArg("payment header is required") + } + commitments, err := s.prover.GetCommitmentsForPaddedLength(data) if err != nil { return api.NewErrorInternal(fmt.Sprintf("failed to get commitments: %v", err)) From a9a6f7952ed7eff1f25f43f5f8983fa0a3194371 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Tue, 26 Nov 2024 09:13:47 -0800 Subject: [PATCH 16/18] refactor: generate new proto file --- api/grpc/disperser/v2/disperser_v2.pb.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/grpc/disperser/v2/disperser_v2.pb.go b/api/grpc/disperser/v2/disperser_v2.pb.go index 4252de60e..6e1db037b 100644 --- a/api/grpc/disperser/v2/disperser_v2.pb.go +++ b/api/grpc/disperser/v2/disperser_v2.pb.go @@ -431,7 +431,7 @@ type GetPaymentStateRequest struct { AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` // Signature over the account ID - // TODO: sign over a bin index to mitigate signature replay attacks + // TODO: sign over a bin index or a nonce to mitigate signature replay attacks Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` } @@ -932,8 +932,8 @@ func (x *Reservation) GetQuorumSplit() []uint32 { return nil } -// BinRecord is the usage record of an account in a bin. The API should return -// the active bin record and the subsequent two records to include potential overflows. +// BinRecord is the usage record of an account in a bin. The API should return the active bin +// record and the subsequent two records that contains potential overflows. type BinRecord struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache From aa6d68d8a50c31bf9053fc29ae1de725515b4485 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Mon, 2 Dec 2024 08:32:53 -0800 Subject: [PATCH 17/18] refactor: AuthenticatePaymentStateRequest args --- core/auth/v2/auth_test.go | 37 +++++--------------------------- core/auth/v2/authenticator.go | 12 +++++------ core/v2/auth.go | 4 +--- disperser/apiserver/server_v2.go | 2 +- 4 files changed, 12 insertions(+), 43 deletions(-) diff --git a/core/auth/v2/auth_test.go b/core/auth/v2/auth_test.go index 89dd760b4..e700e3b9e 100644 --- a/core/auth/v2/auth_test.go +++ b/core/auth/v2/auth_test.go @@ -5,7 +5,6 @@ import ( "math/big" "testing" - pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" "github.com/Layr-Labs/eigenda/core" auth "github.com/Layr-Labs/eigenda/core/auth/v2" corev2 "github.com/Layr-Labs/eigenda/core/v2" @@ -126,27 +125,16 @@ func TestAuthenticatePaymentStateRequestValid(t *testing.T) { assert.NoError(t, err) accountId, err := signer.GetAccountID() - assert.NoError(t, err) - request := &pb.GetPaymentStateRequest{ - AccountId: accountId, - Signature: signature, - } - - err = authenticator.AuthenticatePaymentStateRequest(request) + err = authenticator.AuthenticatePaymentStateRequest(signature, accountId) assert.NoError(t, err) } func TestAuthenticatePaymentStateRequestInvalidSignatureLength(t *testing.T) { authenticator := auth.NewAuthenticator() - request := &pb.GetPaymentStateRequest{ - AccountId: "0x123", - Signature: []byte{1, 2, 3}, // Invalid length - } - - err := authenticator.AuthenticatePaymentStateRequest(request) + err := authenticator.AuthenticatePaymentStateRequest([]byte{1, 2, 3}, "0x123") assert.Error(t, err) assert.Contains(t, err.Error(), "signature length is unexpected") } @@ -154,12 +142,7 @@ func TestAuthenticatePaymentStateRequestInvalidSignatureLength(t *testing.T) { func TestAuthenticatePaymentStateRequestInvalidPublicKey(t *testing.T) { authenticator := auth.NewAuthenticator() - request := &pb.GetPaymentStateRequest{ - AccountId: "not-hex-encoded", - Signature: make([]byte, 65), - } - - err := authenticator.AuthenticatePaymentStateRequest(request) + err := authenticator.AuthenticatePaymentStateRequest(make([]byte, 65), "not-hex-encoded") assert.Error(t, err) assert.Contains(t, err.Error(), "failed to decode public key") } @@ -178,12 +161,7 @@ func TestAuthenticatePaymentStateRequestSignatureMismatch(t *testing.T) { signature, err := wrongSigner.SignPaymentStateRequest() assert.NoError(t, err) - request := &pb.GetPaymentStateRequest{ - AccountId: accountId, - Signature: signature, - } - - err = authenticator.AuthenticatePaymentStateRequest(request) + err = authenticator.AuthenticatePaymentStateRequest(signature, accountId) assert.Error(t, err) assert.Contains(t, err.Error(), "signature doesn't match with provided public key") } @@ -202,11 +180,6 @@ func TestAuthenticatePaymentStateRequestCorruptedSignature(t *testing.T) { // Corrupt the signature signature[0] ^= 0x01 - request := &pb.GetPaymentStateRequest{ - AccountId: accountId, - Signature: signature, - } - - err = authenticator.AuthenticatePaymentStateRequest(request) + err = authenticator.AuthenticatePaymentStateRequest(signature, accountId) assert.Error(t, err) } diff --git a/core/auth/v2/authenticator.go b/core/auth/v2/authenticator.go index 6d8963611..055a0edfb 100644 --- a/core/auth/v2/authenticator.go +++ b/core/auth/v2/authenticator.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" - pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" core "github.com/Layr-Labs/eigenda/core/v2" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -57,27 +56,26 @@ func (*authenticator) AuthenticateBlobRequest(header *core.BlobHeader) error { return nil } -func (*authenticator) AuthenticatePaymentStateRequest(request *pb.GetPaymentStateRequest) error { +func (*authenticator) AuthenticatePaymentStateRequest(sig []byte, accountId string) error { // Ensure the signature is 65 bytes (Recovery ID is the last byte) - sig := request.GetSignature() if len(sig) != 65 { return fmt.Errorf("signature length is unexpected: %d", len(sig)) } // Decode public key - publicKeyBytes, err := hexutil.Decode(request.GetAccountId()) + publicKeyBytes, err := hexutil.Decode(accountId) if err != nil { - return fmt.Errorf("failed to decode public key (%v): %v", request.GetAccountId(), err) + return fmt.Errorf("failed to decode public key (%v): %v", accountId, err) } // Convert bytes to public key pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes) if err != nil { - return fmt.Errorf("failed to convert bytes to public key (%v): %v", request.GetAccountId(), err) + return fmt.Errorf("failed to convert bytes to public key (%v): %v", accountId, err) } // Verify the signature - hash := sha256.Sum256([]byte(request.GetAccountId())) + hash := sha256.Sum256([]byte(accountId)) sigPublicKeyECDSA, err := crypto.SigToPub(hash[:], sig) if err != nil { return fmt.Errorf("failed to recover public key from signature: %v", err) diff --git a/core/v2/auth.go b/core/v2/auth.go index 80e888b3b..555825f5e 100644 --- a/core/v2/auth.go +++ b/core/v2/auth.go @@ -1,10 +1,8 @@ package v2 -import pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" - type BlobRequestAuthenticator interface { AuthenticateBlobRequest(header *BlobHeader) error - AuthenticatePaymentStateRequest(request *pb.GetPaymentStateRequest) error + AuthenticatePaymentStateRequest(signature []byte, accountId string) error } type BlobRequestSigner interface { diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go index 9cfa3b72d..114f24409 100644 --- a/disperser/apiserver/server_v2.go +++ b/disperser/apiserver/server_v2.go @@ -214,7 +214,7 @@ func (s *DispersalServerV2) RefreshOnchainState(ctx context.Context) error { func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaymentStateRequest) (*pb.GetPaymentStateReply, error) { // validate the signature - if err := s.authenticator.AuthenticatePaymentStateRequest(req); err != nil { + if err := s.authenticator.AuthenticatePaymentStateRequest(req.GetSignature(), req.GetAccountId()); err != nil { return nil, api.NewErrorInvalidArg(fmt.Sprintf("authentication failed: %s", err.Error())) } // on-chain global payment parameters From 5c4b83cff279cb33c99fb21ee52fca25ac692efc Mon Sep 17 00:00:00 2001 From: hopeyen Date: Mon, 2 Dec 2024 11:47:59 -0800 Subject: [PATCH 18/18] refactor: tabs and constants --- api/proto/disperser/v2/disperser_v2.proto | 48 +++++++++++------------ core/meterer/offchain_store.go | 10 ++--- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/api/proto/disperser/v2/disperser_v2.proto b/api/proto/disperser/v2/disperser_v2.proto index e365838ff..4107023bc 100644 --- a/api/proto/disperser/v2/disperser_v2.proto +++ b/api/proto/disperser/v2/disperser_v2.proto @@ -68,24 +68,24 @@ message BlobCommitmentReply { // GetPaymentStateRequest contains parameters to query the payment state of an account. message GetPaymentStateRequest { - string account_id = 1; + string account_id = 1; // Signature over the account ID // TODO: sign over a bin index or a nonce to mitigate signature replay attacks - bytes signature = 2; + bytes signature = 2; } // GetPaymentStateReply contains the payment state of an account. message GetPaymentStateReply { - // global payment vault parameters - PaymentGlobalParams payment_global_params = 1; - // off-chain account reservation usage records - repeated BinRecord bin_records = 2; - // on-chain account reservation setting - Reservation reservation = 3; - // off-chain on-demand payment usage - bytes cumulative_payment = 4; - // on-chain on-demand payment deposited - bytes onchain_cumulative_payment = 5; + // global payment vault parameters + PaymentGlobalParams payment_global_params = 1; + // off-chain account reservation usage records + repeated BinRecord bin_records = 2; + // on-chain account reservation setting + Reservation reservation = 3; + // off-chain on-demand payment usage + bytes cumulative_payment = 4; + // on-chain on-demand payment deposited + bytes onchain_cumulative_payment = 5; } // Data Types @@ -152,24 +152,24 @@ message Attestation { } message PaymentGlobalParams { - uint64 global_symbols_per_second = 1; - uint32 min_num_symbols = 2; - uint32 price_per_symbol = 3; - uint32 reservation_window = 4; - repeated uint32 on_demand_quorum_numbers = 5; + uint64 global_symbols_per_second = 1; + uint32 min_num_symbols = 2; + uint32 price_per_symbol = 3; + uint32 reservation_window = 4; + repeated uint32 on_demand_quorum_numbers = 5; } message Reservation { - uint64 symbols_per_second = 1; - uint32 start_timestamp = 2; - uint32 end_timestamp = 3; - repeated uint32 quorum_numbers = 4; - repeated uint32 quorum_split = 5; + uint64 symbols_per_second = 1; + uint32 start_timestamp = 2; + uint32 end_timestamp = 3; + repeated uint32 quorum_numbers = 4; + repeated uint32 quorum_split = 5; } // BinRecord is the usage record of an account in a bin. The API should return the active bin // record and the subsequent two records that contains potential overflows. message BinRecord { - uint32 index = 1; - uint64 usage = 2; + uint32 index = 1; + uint64 usage = 2; } diff --git a/core/meterer/offchain_store.go b/core/meterer/offchain_store.go index 130bf3048..bb5f8e185 100644 --- a/core/meterer/offchain_store.go +++ b/core/meterer/offchain_store.go @@ -241,7 +241,7 @@ func (s *OffchainStore) GetRelevantOnDemandRecords(ctx context.Context, accountI return prevPayment, nextPayment, nextDataLength, nil } -func (s *OffchainStore) GetBinRecords(ctx context.Context, accountID string, binIndex uint32) ([3]*pb.BinRecord, error) { +func (s *OffchainStore) GetBinRecords(ctx context.Context, accountID string, binIndex uint32) ([MinNumBins]*pb.BinRecord, error) { // Fetch the 3 bins start from the current bin queryInput := &dynamodb.QueryInput{ TableName: aws.String(s.reservationTableName), @@ -255,14 +255,14 @@ func (s *OffchainStore) GetBinRecords(ctx context.Context, accountID string, bin } bins, err := s.dynamoClient.QueryWithInput(ctx, queryInput) if err != nil { - return [3]*pb.BinRecord{}, fmt.Errorf("failed to query payments for account: %w", err) + return [MinNumBins]*pb.BinRecord{}, fmt.Errorf("failed to query payments for account: %w", err) } - records := [3]*pb.BinRecord{} - for i := 0; i < len(bins) && i < 3; i++ { + records := [MinNumBins]*pb.BinRecord{} + for i := 0; i < len(bins) && i < int(MinNumBins); i++ { binRecord, err := parseBinRecord(bins[i]) if err != nil { - return [3]*pb.BinRecord{}, fmt.Errorf("failed to parse bin %d record: %w", i, err) + return [MinNumBins]*pb.BinRecord{}, fmt.Errorf("failed to parse bin %d record: %w", i, err) } records[i] = binRecord }