Skip to content

Commit

Permalink
move blob validation early
Browse files Browse the repository at this point in the history
  • Loading branch information
ian-shim committed Mar 18, 2024
1 parent 39aa5ac commit a2ac1f1
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 53 deletions.
29 changes: 15 additions & 14 deletions contracts/src/core/EigenDAServiceManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,27 @@ abstract contract EigenDAServiceManagerStorage is IEigenDAServiceManager {
*/
uint32 public constant BLOCK_STALE_MEASURE = 150;

/**
* @notice The quorum adversary threshold percentages stored as an ordered bytes array
* this is the percentage of the total stake that must be adversarial to consider a blob invalid
/**
* @notice The quorum adversary threshold percentages stored as an ordered bytes array
* this is the percentage of the total stake that must be adversarial to consider a blob invalid.
* The first byte is the threshold for quorum 0, the second byte is the threshold for quorum 1, etc.
*/
bytes public constant quorumAdversaryThresholdPercentages = hex"2121";

/**
* @notice The quorum confirmation threshold percentages stored as an ordered bytes array
* this is the percentage of the total stake needed to confirm a blob
/**
* @notice The quorum confirmation threshold percentages stored as an ordered bytes array
* this is the percentage of the total stake needed to confirm a blob.
* The first byte is the threshold for quorum 0, the second byte is the threshold for quorum 1, etc.
*/
bytes public constant quorumConfirmationThresholdPercentages = hex"4242";

/**
* @notice The quorum numbers required for confirmation stored as an ordered bytes array
/**
* @notice The quorum numbers required for confirmation stored as an ordered bytes array
* these quorum numbers have respective canonical thresholds in the
* quorumConfirmationThresholdPercentages and quorumAdversaryThresholdPercentages above
* quorumConfirmationThresholdPercentages and quorumAdversaryThresholdPercentages above.
*/
bytes public constant quorumNumbersRequired = hex"0001";

/// @notice The current batchId
uint32 public batchId;

Expand All @@ -54,8 +56,7 @@ abstract contract EigenDAServiceManagerStorage is IEigenDAServiceManager {
/// @notice address that is permissioned to confirm batches
address public batchConfirmer;

// storage gap for upgradeability
// slither-disable-next-line shadowing-state
uint256[47] private __GAP;

// storage gap for upgradeability
// slither-disable-next-line shadowing-state
uint256[47] private __GAP;
}
13 changes: 6 additions & 7 deletions core/auth/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ func NewAuthenticator(config AuthConfig) core.BlobRequestAuthenticator {
}

func (*authenticator) AuthenticateBlobRequest(header core.BlobAuthHeader) error {
sig := header.AuthenticationData

// Ensure the signature is 65 bytes (Recovery ID is the last byte)
if sig == nil || len(sig) != 65 {
return fmt.Errorf("signature length is unexpected: %d", len(sig))
}

buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, header.Nonce)
Expand All @@ -37,19 +43,12 @@ func (*authenticator) AuthenticateBlobRequest(header core.BlobAuthHeader) error
return fmt.Errorf("failed to decode public key (%v): %v", header.AccountID, err)
}

sig := header.AuthenticationData

// Decode public key
pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes)
if err != nil {
return fmt.Errorf("failed to decode public key (%v): %v", header.AccountID, err)
}

// Ensure the signature is 65 bytes (Recovery ID is the last byte)
if sig == nil || len(sig) != 65 {
return fmt.Errorf("signature length is unexpected: %d", len(sig))
}

// Verify the signature
sigPublicKeyECDSA, err := crypto.SigToPub(hash, sig)
if err != nil {
Expand Down
20 changes: 9 additions & 11 deletions core/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,15 @@ type BlobRequestHeader struct {
SecurityParams []*SecurityParam `json:"security_params"`
}

func (h *BlobRequestHeader) Validate() error {
for _, quorum := range h.SecurityParams {
if quorum.ConfirmationThreshold < quorum.AdversaryThreshold+10 {
return errors.New("invalid request: quorum threshold must be >= 10 + adversary threshold")
}
if quorum.ConfirmationThreshold > 100 {
return errors.New("invalid request: quorum threshold exceeds 100")
}
if quorum.AdversaryThreshold == 0 {
return errors.New("invalid request: adversary threshold equals 0")
}
func (sp *SecurityParam) Validate() error {
if sp.ConfirmationThreshold < sp.AdversaryThreshold+10 {
return errors.New("invalid request: quorum threshold must be >= 10 + adversary threshold")
}
if sp.ConfirmationThreshold > 100 {
return errors.New("invalid request: quorum threshold exceeds 100")
}
if sp.AdversaryThreshold == 0 {
return errors.New("invalid request: adversary threshold equals 0")
}
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions core/eth/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ func (t *Transactor) GetQuorumCount(ctx context.Context, blockNumber uint32) (ui
})
}

func (t *Transactor) GetQuorumSecurityParams(ctx context.Context, blockNumber uint32) ([]*core.SecurityParam, error) {
func (t *Transactor) GetQuorumSecurityParams(ctx context.Context, blockNumber uint32) ([]core.SecurityParam, error) {
adversaryThresholdPercentegesBytes, err := t.Bindings.EigenDAServiceManager.QuorumAdversaryThresholdPercentages(&bind.CallOpts{
Context: ctx,
BlockNumber: big.NewInt(int64(blockNumber)),
Expand All @@ -707,10 +707,10 @@ func (t *Transactor) GetQuorumSecurityParams(ctx context.Context, blockNumber ui
return nil, errors.New("adversaryThresholdPercentegesBytes and confirmationThresholdPercentegesBytes have different lengths")
}

securityParams := make([]*core.SecurityParam, len(adversaryThresholdPercentegesBytes))
securityParams := make([]core.SecurityParam, len(adversaryThresholdPercentegesBytes))

for i := range adversaryThresholdPercentegesBytes {
securityParams[i] = &core.SecurityParam{
securityParams[i] = core.SecurityParam{
QuorumID: core.QuorumID(i),
AdversaryThreshold: adversaryThresholdPercentegesBytes[i],
ConfirmationThreshold: confirmationThresholdPercentegesBytes[i],
Expand Down
4 changes: 2 additions & 2 deletions core/mock/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ func (t *MockTransactor) GetQuorumCount(ctx context.Context, blockNumber uint32)
return result.(uint8), args.Error(1)
}

func (t *MockTransactor) GetQuorumSecurityParams(ctx context.Context, blockNumber uint32) ([]*core.SecurityParam, error) {
func (t *MockTransactor) GetQuorumSecurityParams(ctx context.Context, blockNumber uint32) ([]core.SecurityParam, error) {
args := t.Called()
result := args.Get(0)
return result.([]*core.SecurityParam), args.Error(1)
return result.([]core.SecurityParam), args.Error(1)
}

func (t *MockTransactor) GetRequiredQuorumNumbers(ctx context.Context, blockNumber uint32) ([]uint8, error) {
Expand Down
2 changes: 1 addition & 1 deletion core/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ type Transactor interface {
GetQuorumCount(ctx context.Context, blockNumber uint32) (uint8, error)

// GetQuorumSecurityParams returns the security params for the registered quorums.
GetQuorumSecurityParams(ctx context.Context, blockNumber uint32) ([]*SecurityParam, error)
GetQuorumSecurityParams(ctx context.Context, blockNumber uint32) ([]SecurityParam, error)

// GetRequiredQuorumNumbers returns set of required quorum numbers
GetRequiredQuorumNumbers(ctx context.Context, blockNumber uint32) ([]QuorumID, error)
Expand Down
24 changes: 13 additions & 11 deletions disperser/apiserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type DispersalServer struct {
type QuorumConfig struct {
RequiredQuorums []core.QuorumID
QuorumCount uint8
SecurityParams []*core.SecurityParam
SecurityParams map[core.QuorumID]core.SecurityParam
}

// NewServer creates a new Server struct with the provided parameters.
Expand Down Expand Up @@ -205,8 +205,6 @@ func (s *DispersalServer) disperseBlob(ctx context.Context, blob *core.Blob, aut
defer timer.ObserveDuration()

securityParams := blob.RequestHeader.SecurityParams

// securityParams := blob.RequestHeader.SecurityParams
securityParamsStrings := make([]string, len(securityParams))
for i, sp := range securityParams {
securityParamsStrings[i] = sp.String()
Expand Down Expand Up @@ -605,7 +603,12 @@ func (s *DispersalServer) updateQuorumConfig(ctx context.Context) (QuorumConfig,
return QuorumConfig{}, err
}
} else {
newConfig.SecurityParams = securityParams
if newConfig.SecurityParams == nil {
newConfig.SecurityParams = make(map[core.QuorumID]core.SecurityParam)
}
for _, sp := range securityParams {
newConfig.SecurityParams[sp.QuorumID] = sp
}
}

requiredQuorums, err := s.tx.GetRequiredQuorumNumbers(ctx, currentBlock)
Expand Down Expand Up @@ -705,8 +708,12 @@ func (s *DispersalServer) validateRequestAndGetBlob(ctx context.Context, req *pb
for quorumID := range seenQuorums {
params[i] = &core.SecurityParam{
QuorumID: core.QuorumID(quorumID),
AdversaryThreshold: quorumConfig.SecurityParams[i].AdversaryThreshold,
ConfirmationThreshold: quorumConfig.SecurityParams[i].ConfirmationThreshold,
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++
}
Expand All @@ -718,11 +725,6 @@ func (s *DispersalServer) validateRequestAndGetBlob(ctx context.Context, req *pb
SecurityParams: params,
}

if err := header.Validate(); err != nil {
s.logger.Warn("invalid header", "err", err)
return nil, err
}

blob := &core.Blob{
RequestHeader: header,
Data: data,
Expand Down
4 changes: 2 additions & 2 deletions disperser/apiserver/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func TestDisperseBlobWithRequiredQuorums(t *testing.T) {
transactor := &mock.MockTransactor{}
transactor.On("GetCurrentBlockNumber").Return(uint32(100), nil)
transactor.On("GetQuorumCount").Return(uint8(2), nil)
quorumParams := []*core.SecurityParam{
quorumParams := []core.SecurityParam{
{QuorumID: 0, AdversaryThreshold: 80, ConfirmationThreshold: 100},
{QuorumID: 1, AdversaryThreshold: 80, ConfirmationThreshold: 100},
}
Expand Down Expand Up @@ -349,7 +349,7 @@ func setup(m *testing.M) {
transactor := &mock.MockTransactor{}
transactor.On("GetCurrentBlockNumber").Return(uint32(100), nil)
transactor.On("GetQuorumCount").Return(uint8(2), nil)
quorumParams := []*core.SecurityParam{
quorumParams := []core.SecurityParam{
{QuorumID: 0, AdversaryThreshold: 80, ConfirmationThreshold: 100},
{QuorumID: 1, AdversaryThreshold: 80, ConfirmationThreshold: 100},
}
Expand Down
11 changes: 9 additions & 2 deletions operators/churner/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,18 @@ func (s *Server) validateChurnRequest(ctx context.Context, req *pb.ChurnRequest)
}

// TODO: ensure that all quorumIDs are valid
if len(req.QuorumIds) == 0 {
return errors.New("invalid quorumIds length")
if len(req.QuorumIds) == 0 || len(req.QuorumIds) > 255 {
return fmt.Errorf("invalid quorumIds length %d", len(req.QuorumIds))
}

seenQuorums := make(map[int]struct{})
for quorumID := range req.GetQuorumIds() {
// make sure there are no duplicate quorum IDs
if _, ok := seenQuorums[quorumID]; ok {
return errors.New("invalid request: security_params must not contain duplicate quorum_id")
}
seenQuorums[quorumID] = struct{}{}

if quorumID >= int(s.churner.QuorumCount) {
err := s.churner.UpdateQuorumCount(ctx)
if err != nil {
Expand Down

0 comments on commit a2ac1f1

Please sign in to comment.