forked from Layr-Labs/eigenda
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add eth accounts to allowlist (Layr-Labs#175)
- Loading branch information
1 parent
1355bd9
commit 669be3d
Showing
7 changed files
with
401 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package mock | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
"github.com/Layr-Labs/eigenda/api/grpc/disperser" | ||
|
||
"google.golang.org/grpc" | ||
) | ||
|
||
func MakeStreamMock(ctx context.Context) *StreamMock { | ||
return &StreamMock{ | ||
ctx: ctx, | ||
recvToServer: make(chan *disperser.AuthenticatedRequest, 10), | ||
sentFromServer: make(chan *disperser.AuthenticatedReply, 10), | ||
} | ||
} | ||
|
||
type StreamMock struct { | ||
grpc.ServerStream | ||
ctx context.Context | ||
recvToServer chan *disperser.AuthenticatedRequest | ||
sentFromServer chan *disperser.AuthenticatedReply | ||
} | ||
|
||
func (m *StreamMock) Context() context.Context { | ||
return m.ctx | ||
} | ||
|
||
func (m *StreamMock) Send(resp *disperser.AuthenticatedReply) error { | ||
m.sentFromServer <- resp | ||
return nil | ||
} | ||
|
||
func (m *StreamMock) Recv() (*disperser.AuthenticatedRequest, error) { | ||
req, more := <-m.recvToServer | ||
if !more { | ||
return nil, errors.New("empty") | ||
} | ||
return req, nil | ||
} | ||
|
||
func (m *StreamMock) SendFromClient(req *disperser.AuthenticatedRequest) error { | ||
m.recvToServer <- req | ||
return nil | ||
} | ||
|
||
func (m *StreamMock) RecvToClient() (*disperser.AuthenticatedReply, error) { | ||
response, more := <-m.sentFromServer | ||
if !more { | ||
return nil, errors.New("empty") | ||
} | ||
return response, nil | ||
} | ||
|
||
func (m *StreamMock) Close() { | ||
close(m.recvToServer) | ||
close(m.sentFromServer) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
package apiserver_test | ||
|
||
import ( | ||
"context" | ||
"crypto/rand" | ||
"net" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/Layr-Labs/eigenda/api/grpc/disperser" | ||
pb "github.com/Layr-Labs/eigenda/api/grpc/disperser" | ||
"github.com/Layr-Labs/eigenda/api/grpc/mock" | ||
"github.com/Layr-Labs/eigenda/core" | ||
"github.com/Layr-Labs/eigenda/core/auth" | ||
"github.com/stretchr/testify/assert" | ||
"google.golang.org/grpc/peer" | ||
) | ||
|
||
func TestRatelimit(t *testing.T) { | ||
data50KiB := make([]byte, 50*1024) | ||
_, err := rand.Read(data50KiB) | ||
assert.NoError(t, err) | ||
data1KiB := make([]byte, 1024) | ||
_, err = rand.Read(data1KiB) | ||
assert.NoError(t, err) | ||
|
||
// Try with a non-allowlisted IP | ||
p := &peer.Peer{ | ||
Addr: &net.TCPAddr{ | ||
IP: net.ParseIP("1.1.1.1"), | ||
Port: 51001, | ||
}, | ||
} | ||
ctx := peer.NewContext(context.Background(), p) | ||
|
||
// Try with non-allowlisted IP | ||
// Should fail with account throughput limit because unauth throughput limit is 20 KiB/s for quorum 0 | ||
_, err = dispersalServer.DisperseBlob(ctx, &pb.DisperseBlobRequest{ | ||
Data: data50KiB, | ||
SecurityParams: []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 0, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, | ||
}) | ||
assert.ErrorContains(t, err, "account throughput limit") | ||
|
||
// Try with non-allowlisted IP. Should fail with account blob limit because blob rate (3 blobs/s) X bucket size (3s) is smaller than 20 blobs. | ||
numLimited := 0 | ||
for i := 0; i < 20; i++ { | ||
_, err = dispersalServer.DisperseBlob(ctx, &pb.DisperseBlobRequest{ | ||
Data: data1KiB, | ||
SecurityParams: []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 1, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, | ||
}) | ||
if err != nil && strings.Contains(err.Error(), "account blob limit") { | ||
numLimited++ | ||
} | ||
} | ||
assert.Greater(t, numLimited, 0) | ||
|
||
// Now try with an allowlisted IP | ||
// This should succeed because the account throughput limit is 100 KiB/s for quorum 0 | ||
p = &peer.Peer{ | ||
Addr: &net.TCPAddr{ | ||
IP: net.ParseIP("1.2.3.4"), | ||
Port: 51001, | ||
}, | ||
} | ||
ctx = peer.NewContext(context.Background(), p) | ||
|
||
_, err = dispersalServer.DisperseBlob(ctx, &pb.DisperseBlobRequest{ | ||
Data: data50KiB, | ||
SecurityParams: []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 0, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, | ||
}) | ||
assert.NoError(t, err) | ||
|
||
// This should succeed because the account blob limit (5 blobs/s) X bucket size (3s) is larger than 10 blobs. | ||
for i := 0; i < 10; i++ { | ||
_, err = dispersalServer.DisperseBlob(ctx, &pb.DisperseBlobRequest{ | ||
Data: data1KiB, | ||
SecurityParams: []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 1, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, | ||
}) | ||
assert.NoError(t, err) | ||
} | ||
} | ||
|
||
func TestAuthRatelimit(t *testing.T) { | ||
|
||
data50KiB := make([]byte, 50*1024) | ||
_, err := rand.Read(data50KiB) | ||
assert.NoError(t, err) | ||
data1KiB := make([]byte, 1024) | ||
_, err = rand.Read(data1KiB) | ||
assert.NoError(t, err) | ||
|
||
// Use an unauthenticated signer | ||
privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdeb" | ||
signer := auth.NewSigner(privateKeyHex) | ||
|
||
errorChan := make(chan error, 10) | ||
|
||
// Should fail with account throughput limit because unauth throughput limit is 20 KiB/s for quorum 0 | ||
simulateClient(t, signer, "2.2.2.2", data50KiB, []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 0, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, errorChan, false) | ||
|
||
err = <-errorChan | ||
assert.ErrorContains(t, err, "account throughput limit") | ||
|
||
// Should fail with account blob limit because blob rate (3 blobs/s) X bucket size (3s) is smaller than 10 blobs. | ||
for i := 0; i < 20; i++ { | ||
simulateClient(t, signer, "3.3.3.3", data1KiB, []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 1, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, errorChan, false) | ||
} | ||
numLimited := 0 | ||
for i := 0; i < 20; i++ { | ||
err = <-errorChan | ||
if err != nil && strings.Contains(err.Error(), "account blob limit") { | ||
numLimited++ | ||
} | ||
} | ||
assert.Greater(t, numLimited, 0) | ||
|
||
// Use an authenticated signer | ||
privateKeyHex = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcded" | ||
signer = auth.NewSigner(privateKeyHex) | ||
|
||
// This should succeed because the account throughput limit is 100 KiB/s for quorum 0 | ||
simulateClient(t, signer, "4.4.4.4", data50KiB, []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 0, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, errorChan, false) | ||
|
||
err = <-errorChan | ||
assert.NoError(t, err) | ||
|
||
// This should succeed because the account blob limit (5 blobs/s) X bucket size (3s) is larger than 10 blobs. | ||
for i := 0; i < 10; i++ { | ||
simulateClient(t, signer, "5.5.5.5", data1KiB, []*pb.SecurityParams{ | ||
{ | ||
QuorumId: 1, | ||
AdversaryThreshold: 50, | ||
QuorumThreshold: 100, | ||
}, | ||
}, errorChan, false) | ||
} | ||
numLimited = 0 | ||
for i := 0; i < 10; i++ { | ||
err = <-errorChan | ||
if err != nil && strings.Contains(err.Error(), "account blob limit") { | ||
numLimited++ | ||
} | ||
} | ||
assert.Equal(t, numLimited, 0) | ||
|
||
} | ||
|
||
func simulateClient(t *testing.T, signer core.BlobRequestSigner, origin string, data []byte, params []*pb.SecurityParams, errorChan chan error, shouldSucceed bool) { | ||
|
||
p := &peer.Peer{ | ||
Addr: &net.TCPAddr{ | ||
IP: net.ParseIP(origin), | ||
Port: 51001, | ||
}, | ||
} | ||
ctx := peer.NewContext(context.Background(), p) | ||
stream := mock.MakeStreamMock(ctx) | ||
|
||
go func() { | ||
err := dispersalServer.DisperseBlobAuthenticated(stream) | ||
errorChan <- err | ||
stream.Close() | ||
}() | ||
|
||
err := stream.SendFromClient(&pb.AuthenticatedRequest{ | ||
Payload: &pb.AuthenticatedRequest_DisperseRequest{ | ||
DisperseRequest: &pb.DisperseBlobRequest{ | ||
Data: data, | ||
SecurityParams: params, | ||
AccountId: signer.GetAccountID(), | ||
}, | ||
}, | ||
}) | ||
assert.NoError(t, err) | ||
|
||
reply, err := stream.RecvToClient() | ||
assert.NoError(t, err) | ||
|
||
authHeaderReply, ok := reply.Payload.(*disperser.AuthenticatedReply_BlobAuthHeader) | ||
assert.True(t, ok) | ||
|
||
authHeader := core.BlobAuthHeader{ | ||
BlobCommitments: core.BlobCommitments{}, | ||
AccountID: "", | ||
Nonce: authHeaderReply.BlobAuthHeader.ChallengeParameter, | ||
} | ||
|
||
authData, err := signer.SignBlobRequest(authHeader) | ||
assert.NoError(t, err) | ||
|
||
// Process challenge and send back challenge_reply | ||
err = stream.SendFromClient(&disperser.AuthenticatedRequest{Payload: &disperser.AuthenticatedRequest_AuthenticationData{ | ||
AuthenticationData: &disperser.AuthenticationData{ | ||
AuthenticationData: authData, | ||
}, | ||
}}) | ||
assert.NoError(t, err) | ||
|
||
if shouldSucceed { | ||
|
||
reply, err = stream.RecvToClient() | ||
assert.NoError(t, err) | ||
|
||
disperseReply, ok := reply.Payload.(*disperser.AuthenticatedReply_DisperseReply) | ||
assert.True(t, ok) | ||
|
||
assert.Equal(t, disperseReply.DisperseReply.Result, disperser.BlobStatus_PROCESSING) | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.