Skip to content

Commit 80ddb60

Browse files
authored
Merge pull request #17 from greg-szabo/greg/blobs
feat(consensus): blobs feature
1 parent 6ddcc13 commit 80ddb60

66 files changed

Lines changed: 3999 additions & 708 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.golangci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,25 @@ linters-settings:
7373
- github.com/stretchr/testify/require
7474
- github.com/syndtr/goleveldb
7575
- github.com/decred/dcrd/dcrec/secp256k1/v4
76+
- google.golang.org/protobuf/proto
77+
- google.golang.org/protobuf/types/known/timestamppb
78+
- golang.org/x/sync/errgroup
79+
- golang.org/x/net/netutil
80+
- golang.org/x/crypto/chacha20poly1305
81+
- golang.org/x/net/netutil
82+
- google.golang.org/grpc
83+
- golang.org/x/net/context
84+
- google.golang.org/grpc
85+
- golang.org/x/crypto/openpgp/armor
86+
- gonum.org/v1/gonum/stat
87+
- golang.org/x/crypto/chacha20poly1305
88+
- golang.org/x/crypto/curve25519
89+
- golang.org/x/crypto/hkdf
90+
- golang.org/x/crypto/nacl/box
91+
- google.golang.org/grpc
92+
- google.golang.org/grpc/credentials/insecure
93+
- golang.org/x/crypto/nacl/secretbox
94+
- golang.org/x/sync/semaphore
7695
test:
7796
files:
7897
- "$test"
@@ -94,6 +113,11 @@ linters-settings:
94113
- github.com/spf13
95114
- github.com/stretchr/testify
96115
- github.com/decred/dcrd/dcrec/secp256k1/v4
116+
- google.golang.org/grpc
117+
- golang.org/x/net/context
118+
- golang.org/x/crypto/bcrypt
119+
- golang.org/x/crypto/chacha20poly1305
120+
- google.golang.org/protobuf/types/known/timestamppb
97121

98122
revive:
99123
enable-all-rules: true

abci/example/kvstore/kvstore.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
var (
2323
stateKey = []byte("stateKey")
2424
kvPairPrefixKey = []byte("kvPairKey:")
25+
26+
_testBlob = []byte("testBlob")
2527
)
2628

2729
const (
@@ -49,6 +51,9 @@ type Application struct {
4951
// If true, the app will generate block events in BeginBlock. Used to test the event indexer
5052
// Should be false by default to avoid generating too much data.
5153
genBlockEvents bool
54+
55+
// Generate blobs
56+
generateBlobs bool
5257
}
5358

5459
// NewApplication creates an instance of the kvstore from the provided database
@@ -80,6 +85,17 @@ func (app *Application) SetGenBlockEvents() {
8085
app.genBlockEvents = true
8186
}
8287

88+
func (app *Application) SetGenerateBlobs() {
89+
app.generateBlobs = true
90+
}
91+
92+
// TestBlob returns the blob that the app returns in PrepareProposal.
93+
// TestBlob is only used in testing, and is not part of the abci.Application
94+
// interface.
95+
func (*Application) TestBlob() []byte {
96+
return _testBlob
97+
}
98+
8399
// Info returns information about the state of the application. This is generally used everytime a Tendermint instance
84100
// begins and let's the application know what Tendermint versions it's interacting with. Based from this information,
85101
// Tendermint will ensure it is in sync with the application by potentially replaying the blocks it has. If the
@@ -162,6 +178,9 @@ func isValidTx(tx []byte) bool {
162178
// quite a trivial example of transaction modification.
163179
// NOTE: we assume that CometBFT will never provide more transactions than can fit in a block.
164180
func (app *Application) PrepareProposal(ctx context.Context, req *types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) {
181+
if app.generateBlobs {
182+
return &types.ResponsePrepareProposal{Txs: app.formatTxs(ctx, req.Txs), Blob: _testBlob}, nil
183+
}
165184
return &types.ResponsePrepareProposal{Txs: app.formatTxs(ctx, req.Txs)}, nil
166185
}
167186

@@ -186,6 +205,10 @@ func (app *Application) ProcessProposal(ctx context.Context, req *types.RequestP
186205
return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}, nil
187206
}
188207
}
208+
209+
if app.generateBlobs && !bytes.Equal(req.Blob, _testBlob) {
210+
return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}, nil
211+
}
189212
return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT}, nil
190213
}
191214

abci/types/types.pb.go

Lines changed: 316 additions & 204 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

blocksync/reactor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ FOR_LOOP:
479479
// Try again quickly next loop.
480480
didProcessCh <- struct{}{}
481481

482-
firstParts, err := first.MakePartSet(types.BlockPartSizeBytes)
482+
firstParts, err := first.MakePartSet(types.PartSizeBytes)
483483
if err != nil {
484484
bcR.Logger.Error("failed to make ",
485485
"height", first.Height,

blocksync/reactor_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func newReactor(
140140

141141
thisBlock := state.MakeBlock(blockHeight, nil, lastExtCommit.ToCommit(), nil, state.Validators.Proposer.Address)
142142

143-
thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes)
143+
thisParts, err := thisBlock.MakePartSet(types.PartSizeBytes)
144144
require.NoError(t, err)
145145
blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()}
146146

consensus/byzantine_test.go

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,10 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
210210
}
211211
proposerAddr := lazyProposer.privValidatorPubKey.Address()
212212

213-
block, err := lazyProposer.blockExec.CreateProposalBlock(
213+
block, _, err := lazyProposer.blockExec.CreateProposalBlock(
214214
ctx, lazyProposer.Height, lazyProposer.state, extCommit, proposerAddr)
215215
require.NoError(t, err)
216-
blockParts, err := block.MakePartSet(types.BlockPartSizeBytes)
216+
blockParts, err := block.MakePartSet(types.PartSizeBytes)
217217
require.NoError(t, err)
218218

219219
// Flush the WAL. Otherwise, we may not recompute the same proposal to sign,
@@ -224,7 +224,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
224224

225225
// Make proposal
226226
propBlockID := types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
227-
proposal := types.NewProposal(height, round, lazyProposer.ValidRound, propBlockID)
227+
proposal := types.NewProposal(height, round, lazyProposer.ValidRound, propBlockID, types.BlobID{})
228228
p := proposal.ToProto()
229229
if err := lazyProposer.privValidator.SignProposal(lazyProposer.state.ChainID, p); err == nil {
230230
proposal.Signature = p.Signature
@@ -304,7 +304,7 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
304304
ctx, cancel := context.WithCancel(context.Background())
305305
defer cancel()
306306

307-
app := newKVStore
307+
app := newKVStoreWithBlob
308308
css, cleanup := randConsensusNet(t, N, "consensus_byzantine_test", newMockTickerFunc(false), app)
309309
defer cleanup()
310310

@@ -342,7 +342,7 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
342342
}
343343
// We are setting the prevote function to do nothing because the prevoting
344344
// and precommitting are done alongside the proposal.
345-
css[i].doPrevote = func(height int64, round int32) {}
345+
css[i].doPrevote = func(_ int64, _ int32) {}
346346
}
347347

348348
eventBus := css[i].eventBus
@@ -461,12 +461,16 @@ func byzantineDecideProposalFunc(ctx context.Context, t *testing.T, height int64
461461
// Avoid sending on internalMsgQueue and running consensus state.
462462

463463
// Create a new proposal block from state/txs from the mempool.
464-
block1, err := cs.createProposalBlock(ctx)
465-
require.NoError(t, err)
466-
blockParts1, err := block1.MakePartSet(types.BlockPartSizeBytes)
467-
require.NoError(t, err)
468-
polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()}
469-
proposal1 := types.NewProposal(height, round, polRound, propBlockID)
464+
block1, blockParts1, propBlockID, blob := createProposalBlockAndBlob(t, cs)
465+
466+
blobParts := types.NewPartSetFromData(blob, types.PartSizeBytes)
467+
blobID := types.BlobID{
468+
Hash: blob.Hash(),
469+
PartSetHeader: blobParts.Header(),
470+
}
471+
472+
polRound := cs.ValidRound
473+
proposal1 := types.NewProposal(height, round, polRound, propBlockID, blobID)
470474
p1 := proposal1.ToProto()
471475
if err := cs.privValidator.SignProposal(cs.state.ChainID, p1); err != nil {
472476
t.Error(err)
@@ -478,12 +482,12 @@ func byzantineDecideProposalFunc(ctx context.Context, t *testing.T, height int64
478482
deliverTxsRange(t, cs, 0, 1)
479483

480484
// Create a new proposal block from state/txs from the mempool.
481-
block2, err := cs.createProposalBlock(ctx)
485+
block2, _, err := cs.createProposalBlock(ctx)
482486
require.NoError(t, err)
483-
blockParts2, err := block2.MakePartSet(types.BlockPartSizeBytes)
487+
blockParts2, err := block2.MakePartSet(types.PartSizeBytes)
484488
require.NoError(t, err)
485489
polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()}
486-
proposal2 := types.NewProposal(height, round, polRound, propBlockID)
490+
proposal2 := types.NewProposal(height, round, polRound, propBlockID, blobID)
487491
p2 := proposal2.ToProto()
488492
if err := cs.privValidator.SignProposal(cs.state.ChainID, p2); err != nil {
489493
t.Error(err)
@@ -499,9 +503,9 @@ func byzantineDecideProposalFunc(ctx context.Context, t *testing.T, height int64
499503
t.Logf("Byzantine: broadcasting conflicting proposals to %d peers", len(peers))
500504
for i, peer := range peers {
501505
if i < len(peers)/2 {
502-
go sendProposalAndParts(height, round, cs, peer, proposal1, block1Hash, blockParts1)
506+
go sendProposalAndParts(height, round, cs, peer, proposal1, block1Hash, blockParts1, blobParts)
503507
} else {
504-
go sendProposalAndParts(height, round, cs, peer, proposal2, block2Hash, blockParts2)
508+
go sendProposalAndParts(height, round, cs, peer, proposal2, block2Hash, blockParts2, blobParts)
505509
}
506510
}
507511
}
@@ -513,17 +517,17 @@ func sendProposalAndParts(
513517
peer p2p.Peer,
514518
proposal *types.Proposal,
515519
blockHash []byte,
516-
parts *types.PartSet,
520+
blockParts, blobParts *types.PartSet,
517521
) {
518522
// proposal
519523
peer.Send(p2p.Envelope{
520524
ChannelID: DataChannel,
521525
Message: &cmtcons.Proposal{Proposal: *proposal.ToProto()},
522526
})
523527

524-
// parts
525-
for i := 0; i < int(parts.Total()); i++ {
526-
part := parts.GetPart(i)
528+
// block parts
529+
for i := 0; i < int(blockParts.Total()); i++ {
530+
part := blockParts.GetPart(i)
527531
pp, err := part.ToProto()
528532
if err != nil {
529533
panic(err) // TODO: wbanfield better error handling
@@ -538,10 +542,29 @@ func sendProposalAndParts(
538542
})
539543
}
540544

545+
// blob parts
546+
if blobParts != nil {
547+
for i := 0; i < int(blobParts.Total()); i++ {
548+
part := blobParts.GetPart(i)
549+
pp, err := part.ToProto()
550+
if err != nil {
551+
panic(err)
552+
}
553+
peer.Send(p2p.Envelope{
554+
ChannelID: DataChannel,
555+
Message: &cmtcons.BlobPart{
556+
Height: height, // This tells peer that this part applies to us.
557+
Round: round, // This tells peer that this part applies to us.
558+
Part: *pp,
559+
},
560+
})
561+
}
562+
}
563+
541564
// votes
542565
cs.mtx.Lock()
543-
prevote, _ := cs.signVote(cmtproto.PrevoteType, blockHash, parts.Header(), nil)
544-
precommit, _ := cs.signVote(cmtproto.PrecommitType, blockHash, parts.Header(), nil)
566+
prevote, _ := cs.signVote(cmtproto.PrevoteType, blockHash, blockParts.Header(), nil)
567+
precommit, _ := cs.signVote(cmtproto.PrecommitType, blockHash, blockParts.Header(), nil)
545568
cs.mtx.Unlock()
546569
peer.Send(p2p.Envelope{
547570
ChannelID: VoteChannel,

0 commit comments

Comments
 (0)