Skip to content

Commit e964f35

Browse files
anupsvanupsv
andauthored
feat: Validator blacklisting dispersers (#1588)
* initial implementation of the blacklist addition * adding the blacklist struct and funcs * checking if the blacklist was hit or not * changing to use disperser id * removing api * add explicit flags * fixing naming * small changes * adding basic unit tests * interfaces and comments * small changes, logs * fixing mock calls * linter fix * adding more test * naming fix * testing validator e2e * adding latest block * unmerged * getting test working * final all parts tested * Update golangci-lint.yml * Update kms_fuzz_test.go * Update config.go * adding cleanup * merge conflict fixes * clean up, comments and old tests * adding deletions after 2 weeks * fixing share state problem in tests * fixing test * cleanup of test --------- Co-authored-by: anupsv <[email protected]> Co-authored-by: anupsv <[email protected]>
1 parent 0a61560 commit e964f35

16 files changed

+1616
-26
lines changed

.github/workflows/buf-proto.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
buf:
3030
runs-on: ubuntu-latest
3131
steps:
32-
- uses: actions/checkout@v4
32+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #4.2.2
3333
- uses: bufbuild/buf-action@v1
3434
with:
3535
token: ${{ secrets.BUF_TOKEN }}

.github/workflows/golangci-lint.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,5 @@ jobs:
2121
version: ${{ env.MISE_VERSION }}
2222
experimental: true
2323
- run: go version
24-
2524
- run: make lint
26-
2725
- run: make fmt-check

inabox/deploy/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,7 @@ func (env *Config) GenerateAllVariables() {
769769
if err != nil {
770770
log.Panicf("Error: %s", err.Error())
771771
}
772+
772773
writeFile(composeFile, composeYaml)
773774
}
774775
}

inabox/tests/integration_suite_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ var _ = BeforeSuite(func() {
143143

144144
fmt.Println("Deploying experiment")
145145
testConfig.DeployExperiment()
146-
147146
pk := testConfig.Pks.EcdsaMap[deployer.Name].PrivateKey
148147
pk = strings.TrimPrefix(pk, "0x")
149148
pk = strings.TrimPrefix(pk, "0X")

inabox/tests/integration_v2_test.go

Lines changed: 179 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,193 @@ import (
55
"crypto/rand"
66
"encoding/hex"
77
"fmt"
8+
"math/big"
9+
"time"
10+
11+
"github.com/Layr-Labs/eigenda/api"
12+
"github.com/Layr-Labs/eigenda/encoding"
13+
"github.com/docker/go-units"
14+
"google.golang.org/grpc"
15+
16+
"github.com/Layr-Labs/eigenda/api/clients/v2"
17+
commonpb "github.com/Layr-Labs/eigenda/api/grpc/common/v2"
18+
nodegrpc "github.com/Layr-Labs/eigenda/api/grpc/validator"
19+
"github.com/Layr-Labs/eigenda/api/hashing"
20+
"github.com/Layr-Labs/eigenda/core"
821

922
"github.com/Layr-Labs/eigenda/api/clients/v2/coretypes"
23+
aws2 "github.com/Layr-Labs/eigenda/common/aws"
24+
caws "github.com/Layr-Labs/eigenda/common/aws"
25+
corev2 "github.com/Layr-Labs/eigenda/core/v2"
26+
"github.com/aws/aws-sdk-go-v2/aws"
27+
"github.com/aws/aws-sdk-go-v2/service/kms"
28+
"github.com/consensys/gnark-crypto/ecc/bn254"
29+
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
1030
"github.com/ethereum/go-ethereum/accounts/abi/bind"
1131
gethcommon "github.com/ethereum/go-ethereum/common"
12-
"golang.org/x/crypto/sha3"
13-
1432
. "github.com/onsi/ginkgo/v2"
1533
. "github.com/onsi/gomega"
34+
"golang.org/x/crypto/sha3"
1635
)
1736

37+
func RandomG1Point() (encoding.G1Commitment, error) {
38+
// 1) pick r ← 𝐹ᵣ at random
39+
var r fr.Element
40+
if _, err := r.SetRandom(); err != nil {
41+
return encoding.G1Commitment{}, err
42+
}
43+
44+
// 2) compute P = r·G₁ in Jacobian form
45+
G1Jac, _, _, _ := bn254.Generators()
46+
var Pjac bn254.G1Jac
47+
48+
var rBigInt big.Int
49+
r.BigInt(&rBigInt)
50+
Pjac.ScalarMultiplication(&G1Jac, &rBigInt)
51+
52+
// 3) convert to affine (x, y)
53+
var Paff bn254.G1Affine
54+
Paff.FromJacobian(&Pjac)
55+
return encoding.G1Commitment(Paff), nil
56+
}
57+
58+
func RandomG2Point() (encoding.G2Commitment, error) {
59+
60+
// 1) pick r ← 𝐹ᵣ at random
61+
var r fr.Element
62+
if _, err := r.SetRandom(); err != nil {
63+
return encoding.G2Commitment{}, err
64+
}
65+
66+
// 2) compute P = r·G₂ in Jacobian form
67+
_, g2Jac, _, _ := bn254.Generators()
68+
var Pjac bn254.G2Jac
69+
70+
var rBigInt big.Int
71+
r.BigInt(&rBigInt)
72+
Pjac.ScalarMultiplication(&g2Jac, &rBigInt)
73+
74+
// 3) convert to affine (x, y)
75+
var Paff bn254.G2Affine
76+
Paff.FromJacobian(&Pjac)
77+
return encoding.G2Commitment(Paff), nil
78+
}
79+
80+
var _ = Describe("Inabox v2 blacklisting Integration test", func() {
81+
It("test end to end scenario of blacklisting", func() {
82+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
83+
defer cancel()
84+
85+
// random G1 point
86+
g1Commitment, err := RandomG1Point()
87+
if err != nil {
88+
Fail("failed to generate random G1 point")
89+
}
90+
91+
g2Commitment, err := RandomG2Point()
92+
if err != nil {
93+
Fail("failed to generate random G2 point")
94+
}
95+
96+
// random data blob certificate
97+
blobCert := &corev2.BlobCertificate{
98+
BlobHeader: &corev2.BlobHeader{
99+
BlobVersion: 2,
100+
BlobCommitments: encoding.BlobCommitments{
101+
Commitment: &g1Commitment,
102+
LengthCommitment: &g2Commitment,
103+
LengthProof: &g2Commitment,
104+
Length: 100,
105+
},
106+
QuorumNumbers: []core.QuorumID{0, 1},
107+
PaymentMetadata: core.PaymentMetadata{
108+
AccountID: gethcommon.HexToAddress("0x1234567890123456789012345678901234567890"),
109+
Timestamp: time.Now().UnixNano(),
110+
CumulativePayment: big.NewInt(100),
111+
},
112+
},
113+
Signature: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65},
114+
RelayKeys: []corev2.RelayKey{0, 1},
115+
}
116+
117+
blobCertProto, err := blobCert.ToProtobuf()
118+
if err != nil {
119+
Fail("failed to convert blob certificate to protobuf")
120+
}
121+
fmt.Println("blobCertProto size", len(blobCertProto.String()))
122+
123+
mineAnvilBlocks(1)
124+
// println("latest block number", deploy.GetLatestBlockNumber("http://localhost:8545"))
125+
126+
request := &nodegrpc.StoreChunksRequest{
127+
Batch: &commonpb.Batch{
128+
Header: &commonpb.BatchHeader{
129+
BatchRoot: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
130+
ReferenceBlockNumber: 70,
131+
},
132+
BlobCertificates: []*commonpb.BlobCertificate{
133+
blobCertProto,
134+
},
135+
},
136+
DisperserID: api.EigenLabsDisperserID,
137+
Timestamp: uint32(time.Now().Unix()),
138+
Signature: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65},
139+
}
140+
141+
hash, err := hashing.HashStoreChunksRequest(request)
142+
if err != nil {
143+
Fail("failed to hash request")
144+
}
145+
146+
keyManager := kms.New(kms.Options{
147+
Region: "us-east-1",
148+
BaseEndpoint: aws.String("http://localhost:4570"),
149+
})
150+
151+
// pick the first key in the key manager
152+
keys, err := keyManager.ListKeys(ctx, &kms.ListKeysInput{})
153+
if err != nil {
154+
Fail("failed to list keys")
155+
}
156+
keyID := keys.Keys[0].KeyId
157+
158+
publicKey, err := caws.LoadPublicKeyKMS(ctx, keyManager, *keyID)
159+
if err != nil {
160+
Fail("failed to load public key")
161+
}
162+
163+
signature, err := aws2.SignKMS(ctx, keyManager, *keyID, publicKey, hash)
164+
if err != nil {
165+
Fail("failed to sign request")
166+
}
167+
168+
request.Signature = signature
169+
170+
addr := fmt.Sprintf("%v:%v", "localhost", "32017")
171+
dialOptions := clients.GetGrpcDialOptions(false, 4*units.MiB)
172+
// conn, err := grpc.NewClient(addr, dialOptions...)
173+
// if err != nil {
174+
// Fail("failed to create grpc connection")
175+
// }
176+
conn, err := grpc.NewClient(addr, dialOptions...)
177+
if err != nil {
178+
Fail("failed to create grpc connection")
179+
}
180+
dispersalClient := nodegrpc.NewDispersalClient(conn)
181+
182+
// after this request, the disperser should be blacklisted
183+
_, err = dispersalClient.StoreChunks(ctx, request)
184+
Expect(err).To(Not(BeNil()))
185+
Expect(err.Error()).To(ContainSubstring("failed to validate blob request"))
186+
187+
// should get error saying disperser is blacklisted
188+
_, err = dispersalClient.StoreChunks(ctx, request)
189+
Expect(err).To(Not(BeNil()))
190+
Expect(err.Error()).To(ContainSubstring("disperser is blacklisted"))
191+
192+
})
193+
})
194+
18195
var _ = Describe("Inabox v2 Integration", func() {
19196
/*
20197
This end to end test ensures that:

node/blacklist.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// This file contains the structs which are converted to JSON and stored in the blacklist store
2+
3+
package node
4+
5+
import (
6+
"encoding/json"
7+
"time"
8+
)
9+
10+
// Blacklist contains entries of blacklisted dispersers
11+
type Blacklist struct {
12+
Entries []BlacklistEntry `json:"entries"`
13+
LastUpdated uint64 `json:"last_updated"`
14+
}
15+
16+
// BlacklistEntry represents a single blacklist record
17+
type BlacklistEntry struct {
18+
DisperserID uint32 `json:"disperser_id"`
19+
Metadata BlacklistMetadata `json:"metadata"`
20+
Timestamp uint64 `json:"timestamp"`
21+
}
22+
23+
// BlacklistMetadata contains additional information about the blacklisting
24+
type BlacklistMetadata struct {
25+
ContextId string `json:"context_id"`
26+
Reason string `json:"reason"`
27+
}
28+
29+
// ToBytes serializes the Blacklist to JSON bytes
30+
func (b *Blacklist) ToBytes() ([]byte, error) {
31+
return json.Marshal(b)
32+
}
33+
34+
// FromBytes deserializes JSON bytes into the current Blacklist
35+
func (b *Blacklist) FromBytes(data []byte) error {
36+
return json.Unmarshal(data, b)
37+
}
38+
39+
// AddEntry adds a new blacklist entry
40+
func (b *Blacklist) AddEntry(disperserId uint32, contextId, reason string) {
41+
b.LastUpdated = uint64(time.Now().Unix())
42+
b.Entries = append(b.Entries, BlacklistEntry{
43+
DisperserID: disperserId,
44+
Metadata: BlacklistMetadata{
45+
ContextId: contextId,
46+
Reason: reason,
47+
},
48+
Timestamp: b.LastUpdated,
49+
})
50+
}

0 commit comments

Comments
 (0)