From 787fd09a4f09935632e3dd2391457ab78c278238 Mon Sep 17 00:00:00 2001 From: faultytolly <137398096+faultytolly@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:51:31 +0100 Subject: [PATCH] feat(validation): sequencer misbehavior detection (#1167) Co-authored-by: Sergi Rene Co-authored-by: Faulty Tolly <@faulttolerance.net> Co-authored-by: omritoptix --- block/manager_test.go | 2 +- block/slvalidator.go | 35 +++++ block/slvalidator_test.go | 68 ++++++++-- block/validate.go | 2 +- .../dymension/rollapp/state_info.proto | 3 + rpc/client/client_test.go | 1 + settlement/dymension/events.go | 7 +- settlement/dymension/utils.go | 1 + settlement/errors.go | 17 +++ settlement/settlement.go | 2 + testutil/types.go | 57 ++++++++ .../dymension/rollapp/state_info.pb.go | 126 +++++++++++++----- 12 files changed, 270 insertions(+), 51 deletions(-) diff --git a/block/manager_test.go b/block/manager_test.go index 422f729c2..d80f78481 100644 --- a/block/manager_test.go +++ b/block/manager_test.go @@ -374,7 +374,7 @@ func TestApplyLocalBlock_WithFraudCheck(t *testing.T) { assert.True(t, manager.State.Height() == 0) // enough time to sync and produce blocks - ctx, cancel := context.WithTimeout(context.Background(), time.Second*4) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() // Capture the error returned by manager.Start. diff --git a/block/slvalidator.go b/block/slvalidator.go index 343714261..4fb4b8033 100644 --- a/block/slvalidator.go +++ b/block/slvalidator.go @@ -146,6 +146,11 @@ func (v *SettlementValidator) ValidateDaBlocks(slBatch *settlement.ResultRetriev return types.NewErrStateUpdateNumBlocksNotMatchingFraud(slBatch.EndHeight, numSLBlocks, numSLBlocks) } + currentProposer := v.blockManager.State.GetProposer() + if currentProposer == nil { + return fmt.Errorf("proposer is not set") + } + // we compare all DA blocks against the information included in the state info block descriptors for i, bd := range slBatch.BlockDescriptors { // height check @@ -167,6 +172,35 @@ func (v *SettlementValidator) ValidateDaBlocks(slBatch *settlement.ResultRetriev if err != nil { return err } + + // we compare the sequencer address between SL state info and DA block + // if next sequencer is not set, we check if the sequencer hash is equal to the next sequencer hash + // because it did not change. If the next sequencer is set, we check if the next sequencer hash is equal on the + // last block of the batch + isLastBlock := i == len(slBatch.BlockDescriptors)-1 + if slBatch.NextSequencer != currentProposer.SettlementAddress && isLastBlock { + err := v.blockManager.UpdateSequencerSetFromSL() + if err != nil { + return fmt.Errorf("update sequencer set from SL: %w", err) + } + nextSequencer, found := v.blockManager.Sequencers.GetByAddress(slBatch.NextSequencer) + if !found { + return fmt.Errorf("next sequencer not found") + } + if !bytes.Equal(nextSequencer.MustHash(), daBlocks[i].Header.NextSequencersHash[:]) { + return types.NewErrInvalidNextSequencersHashFraud( + [32]byte(nextSequencer.MustHash()), + daBlocks[i].Header.NextSequencersHash, + ) + } + } else { + if !bytes.Equal(daBlocks[i].Header.SequencerHash[:], daBlocks[i].Header.NextSequencersHash[:]) { + return types.NewErrInvalidNextSequencersHashFraud( + daBlocks[i].Header.SequencerHash, + daBlocks[i].Header.NextSequencersHash, + ) + } + } } v.logger.Debug("DA blocks validated successfully", "start height", daBlocks[0].Header.Height, "end height", daBlocks[len(daBlocks)-1].Header.Height) return nil @@ -198,6 +232,7 @@ func (v *SettlementValidator) NextValidationHeight() uint64 { } // validateDRS compares the DRS version stored for the specific height, obtained from rollapp params. +// DRS checks will work only for non-finalized heights, since it does not store the whole history, but it will never validate finalized heights. func (v *SettlementValidator) validateDRS(stateIndex uint64, height uint64, version string) error { drs, err := v.blockManager.Store.LoadDRSVersion(height) if err != nil { diff --git a/block/slvalidator_test.go b/block/slvalidator_test.go index 7417a3858..51d77239c 100644 --- a/block/slvalidator_test.go +++ b/block/slvalidator_test.go @@ -2,6 +2,9 @@ package block_test import ( "crypto/rand" + "encoding/hex" + "github.com/tendermint/tendermint/crypto/ed25519" + tmtypes "github.com/tendermint/tendermint/types" "reflect" "testing" "time" @@ -26,7 +29,6 @@ import ( ) func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { - // Init app app := testutil.GetAppMock(testutil.EndBlock) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{ @@ -49,6 +51,13 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { proposerKey, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(t, err) + fakeProposerKey, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + nextProposerKey := ed25519.GenPrivKey() + nextSequencerKey, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + doubleSigned, err := testutil.GenerateBlocks(1, 10, proposerKey, [32]byte{}) require.NoError(t, err) @@ -59,6 +68,7 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { doubleSignedBlocks []*types.Block stateUpdateFraud string expectedErrType error + last bool }{ { name: "Successful validation applied from DA", @@ -123,6 +133,14 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { doubleSignedBlocks: nil, expectedErrType: &types.ErrStateUpdateDRSVersionFraud{}, }, + { + name: "Failed validation next sequencer", + p2pBlocks: false, + stateUpdateFraud: "nextsequencer", + doubleSignedBlocks: nil, + expectedErrType: &types.ErrInvalidNextSequencersHashFraud{}, + last: true, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -132,13 +150,37 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { require.NoError(t, err) require.NotNil(t, manager) + if tc.last { + proposerPubKey := nextProposerKey.PubKey() + pubKeybytes := proposerPubKey.Bytes() + if err != nil { + panic(err) + } + + // Set next sequencer + raw, _ := nextSequencerKey.GetPublic().Raw() + pubkey := ed25519.PubKey(raw) + manager.State.SetProposer(types.NewSequencer(pubkey, hex.EncodeToString(pubKeybytes), "", nil)) + + // set proposer + raw, _ = proposerKey.GetPublic().Raw() + pubkey = ed25519.PubKey(raw) + manager.State.Proposer.Store(types.NewSequencer(pubkey, "", "", nil)) + } + // Create DA manager.DAClient = testutil.GetMockDALC(log.TestingLogger()) manager.Retriever = manager.DAClient.(da.BatchRetriever) // Generate batch - batch, err := testutil.GenerateBatch(1, 10, proposerKey, [32]byte{}) - assert.NoError(t, err) + var batch *types.Batch + if tc.last { + batch, err = testutil.GenerateLastBatch(1, 10, proposerKey, fakeProposerKey, [32]byte{}) + assert.NoError(t, err) + } else { + batch, err = testutil.GenerateBatch(1, 10, proposerKey, [32]byte{}) + assert.NoError(t, err) + } // Submit batch to DA daResultSubmitBatch := manager.DAClient.SubmitBatch(batch) @@ -149,7 +191,7 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { require.NoError(t, err) // create the batch in settlement - slBatch := getSLBatch(bds, daResultSubmitBatch.SubmitMetaData, 1, 10) + slBatch := getSLBatch(bds, daResultSubmitBatch.SubmitMetaData, 1, 10, manager.State.GetProposer().SettlementAddress) // Create the StateUpdateValidator validator := block.NewSettlementValidator(testutil.NewLogger(t), manager) @@ -170,7 +212,9 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { } // otherwise load them from DA } else { - manager.ApplyBatchFromSL(slBatch.Batch) + if !tc.last { + manager.ApplyBatchFromSL(slBatch.Batch) + } } for _, bd := range bds { @@ -200,6 +244,9 @@ func TestStateUpdateValidator_ValidateStateUpdate(t *testing.T) { case "height": // add blockdescriptor with wrong height slBatch.BlockDescriptors[0].Height = 2 + case "nextsequencer": + seq := types.NewSequencerFromValidator(*tmtypes.NewValidator(nextProposerKey.PubKey(), 1)) + slBatch.NextSequencer = seq.SettlementAddress } // validate the state update @@ -332,7 +379,7 @@ func TestStateUpdateValidator_ValidateDAFraud(t *testing.T) { bds, err := getBlockDescriptors(batch) require.NoError(t, err) // Generate batch with block descriptors - slBatch := getSLBatch(bds, daResultSubmitBatch.SubmitMetaData, 1, 10) + slBatch := getSLBatch(bds, daResultSubmitBatch.SubmitMetaData, 1, 10, manager.State.GetProposer().SettlementAddress) for _, bd := range bds { manager.Store.SaveDRSVersion(bd.Height, bd.DrsVersion, nil) @@ -371,7 +418,7 @@ func getBlockDescriptors(batch *types.Batch) ([]rollapp.BlockDescriptor, error) return bds, nil } -func getSLBatch(bds []rollapp.BlockDescriptor, daMetaData *da.DASubmitMetaData, startHeight uint64, endHeight uint64) *settlement.ResultRetrieveBatch { +func getSLBatch(bds []rollapp.BlockDescriptor, daMetaData *da.DASubmitMetaData, startHeight uint64, endHeight uint64, nextSequencer string) *settlement.ResultRetrieveBatch { // create the batch in settlement return &settlement.ResultRetrieveBatch{ Batch: &settlement.Batch{ @@ -379,9 +426,10 @@ func getSLBatch(bds []rollapp.BlockDescriptor, daMetaData *da.DASubmitMetaData, MetaData: &settlement.BatchMetaData{ DA: daMetaData, }, - StartHeight: startHeight, - EndHeight: endHeight, - NumBlocks: endHeight - startHeight + 1, + StartHeight: startHeight, + EndHeight: endHeight, + NumBlocks: endHeight - startHeight + 1, + NextSequencer: nextSequencer, }, ResultBase: settlement.ResultBase{ StateIndex: 1, diff --git a/block/validate.go b/block/validate.go index a7f0e0df2..eaaea7bb3 100644 --- a/block/validate.go +++ b/block/validate.go @@ -22,7 +22,7 @@ func (m *Manager) onNewStateUpdateFinalized(event pubsub.Message) { m.SettlementValidator.UpdateLastValidatedHeight(eventData.EndHeight) } -// ValidateLoop listens for syncing events (from new state update or from initial syncing) and validates state updates to the last submitted height. +// SettlementValidateLoop listens for syncing events (from new state update or from initial syncing) and validates state updates to the last submitted height. func (m *Manager) SettlementValidateLoop(ctx context.Context) error { for { select { diff --git a/proto/types/dymensionxyz/dymension/rollapp/state_info.proto b/proto/types/dymensionxyz/dymension/rollapp/state_info.proto index 2b3049234..9989c2f6c 100644 --- a/proto/types/dymensionxyz/dymension/rollapp/state_info.proto +++ b/proto/types/dymensionxyz/dymension/rollapp/state_info.proto @@ -56,6 +56,9 @@ message StateInfo { (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"created_at\"" ]; + // next sequencer is the bech32-encoded address of the next sequencer after the current sequencer + // if empty, it means there is no change in the sequencer + string nextProposer = 11; } // StateInfoSummary is a compact representation of StateInfo diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index 86ff71a26..eba9fe7a9 100644 --- a/rpc/client/client_test.go +++ b/rpc/client/client_test.go @@ -834,6 +834,7 @@ func TestValidatorSetHandling(t *testing.T) { }, ValidatorUpdates: []abci.ValidatorUpdate{{PubKey: pbValKey, Power: 100}}, }) + waitCh := make(chan interface{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}).Times(5) diff --git a/settlement/dymension/events.go b/settlement/dymension/events.go index be541029f..fde8d738a 100644 --- a/settlement/dymension/events.go +++ b/settlement/dymension/events.go @@ -111,15 +111,15 @@ func convertToNewBatchEvent(rawEventData ctypes.ResultEvent) (*settlement.EventD return nil, fmt.Errorf("missing expected attributes in event") } - numBlocks, err := strconv.ParseInt(rawEventData.Events["state_update.num_blocks"][0], 10, 64) + numBlocks, err := strconv.ParseInt(events["state_update.num_blocks"][0], 10, 64) if err != nil { errs = append(errs, err) } - startHeight, err := strconv.ParseInt(rawEventData.Events["state_update.start_height"][0], 10, 64) + startHeight, err := strconv.ParseInt(events["state_update.start_height"][0], 10, 64) if err != nil { errs = append(errs, err) } - stateIndex, err := strconv.ParseInt(rawEventData.Events["state_update.state_info_index"][0], 10, 64) + stateIndex, err := strconv.ParseInt(events["state_update.state_info_index"][0], 10, 64) if err != nil { errs = append(errs, err) } @@ -127,6 +127,7 @@ func convertToNewBatchEvent(rawEventData ctypes.ResultEvent) (*settlement.EventD return nil, errors.Join(errs...) } endHeight := uint64(startHeight + numBlocks - 1) + NewBatchEvent := &settlement.EventDataNewBatch{ StartHeight: uint64(startHeight), EndHeight: endHeight, diff --git a/settlement/dymension/utils.go b/settlement/dymension/utils.go index f0eff2c27..def62fb91 100644 --- a/settlement/dymension/utils.go +++ b/settlement/dymension/utils.go @@ -48,6 +48,7 @@ func convertStateInfoToResultRetrieveBatch(stateInfo *rollapptypes.StateInfo) (* }, BlockDescriptors: stateInfo.BDs.BD, NumBlocks: stateInfo.NumBlocks, + NextSequencer: stateInfo.NextProposer, } return &settlement.ResultRetrieveBatch{ diff --git a/settlement/errors.go b/settlement/errors.go index 05d012c5d..b2b4073b7 100644 --- a/settlement/errors.go +++ b/settlement/errors.go @@ -8,3 +8,20 @@ import ( // ErrBatchNotAccepted is returned when a batch is not accepted by the settlement layer. var ErrBatchNotAccepted = fmt.Errorf("batch not accepted: %w", gerrc.ErrUnknown) + +type ErrNextSequencerAddressFraud struct { + Expected string + Actual string +} + +func NewErrNextSequencerAddressFraud(expected string, actual string) *ErrNextSequencerAddressFraud { + return &ErrNextSequencerAddressFraud{Expected: expected, Actual: actual} +} + +func (e ErrNextSequencerAddressFraud) Error() string { + return fmt.Sprintf("next sequencer address fraud: expected %s, got %s", e.Expected, e.Actual) +} + +func (e ErrNextSequencerAddressFraud) Wrap(err error) error { + return gerrc.ErrFault +} diff --git a/settlement/settlement.go b/settlement/settlement.go index 3a851a416..734bd68a5 100644 --- a/settlement/settlement.go +++ b/settlement/settlement.go @@ -38,6 +38,8 @@ type Batch struct { StartHeight uint64 EndHeight uint64 BlockDescriptors []rollapp.BlockDescriptor + NextSequencer string + // MetaData about the batch in the DA layer MetaData *BatchMetaData NumBlocks uint64 diff --git a/testutil/types.go b/testutil/types.go index 9f17ab105..f0cca12f6 100644 --- a/testutil/types.go +++ b/testutil/types.go @@ -221,6 +221,63 @@ func GenerateBatch(startHeight uint64, endHeight uint64, proposerKey crypto.Priv return batch, nil } +// GenerateLastBatch generates a final batch with LastBatch flag set to true and different NextSequencerHash +func GenerateLastBatch(startHeight uint64, endHeight uint64, proposerKey crypto.PrivKey, nextSequencerKey crypto.PrivKey, lastHeaderHash [32]byte) (*types.Batch, error) { + nextSequencerRaw, _ := nextSequencerKey.Raw() + nextSeq := types.NewSequencerFromValidator(*tmtypes.NewValidator(ed25519.PrivKey(nextSequencerRaw).PubKey(), 1)) + nextSequencerHash := nextSeq.MustHash() + + blocks, err := GenerateLastBlocks(startHeight, endHeight-startHeight+1, proposerKey, lastHeaderHash, [32]byte(nextSequencerHash)) + if err != nil { + return nil, err + } + + commits, err := GenerateCommits(blocks, proposerKey) + if err != nil { + return nil, err + } + + batch := &types.Batch{ + Blocks: blocks, + Commits: commits, + LastBatch: true, + } + + return batch, nil +} + +// GenerateLastBlocks es similar a GenerateBlocks pero incluye el NextSequencerHash +func GenerateLastBlocks(startHeight uint64, num uint64, proposerKey crypto.PrivKey, lastHeaderHash [32]byte, nextSequencerHash [32]byte) ([]*types.Block, error) { + r, _ := proposerKey.Raw() + seq := types.NewSequencerFromValidator(*tmtypes.NewValidator(ed25519.PrivKey(r).PubKey(), 1)) + proposerHash := seq.MustHash() + blocks := make([]*types.Block, num) + + for i := uint64(0); i < num; i++ { + if i > 0 { + lastHeaderHash = blocks[i-1].Header.Hash() + } + block := generateBlock(i+startHeight, proposerHash, lastHeaderHash) + + if i == num-1 { + copy(block.Header.NextSequencersHash[:], nextSequencerHash[:]) + } + + copy(block.Header.DataHash[:], types.GetDataHash(block)) + if i > 0 { + copy(block.Header.LastCommitHash[:], types.GetLastCommitHash(&blocks[i-1].LastCommit, &block.Header)) + } + + signature, err := generateSignature(proposerKey, &block.Header) + if err != nil { + return nil, err + } + block.LastCommit.Signatures = []types.Signature{signature} + blocks[i] = block + } + return blocks, nil +} + func MustGenerateBatch(startHeight uint64, endHeight uint64, proposerKey crypto.PrivKey) *types.Batch { blocks, err := GenerateBlocks(startHeight, endHeight-startHeight+1, proposerKey, [32]byte{}) if err != nil { diff --git a/types/pb/dymensionxyz/dymension/rollapp/state_info.pb.go b/types/pb/dymensionxyz/dymension/rollapp/state_info.pb.go index 008fc76e1..44da77466 100644 --- a/types/pb/dymensionxyz/dymension/rollapp/state_info.pb.go +++ b/types/pb/dymensionxyz/dymension/rollapp/state_info.pb.go @@ -112,6 +112,9 @@ type StateInfo struct { BDs BlockDescriptors `protobuf:"bytes,9,opt,name=BDs,proto3" json:"BDs"` // created_at is the timestamp at which the StateInfo was created CreatedAt time.Time `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at" yaml:"created_at"` + // next sequencer is the bech32-encoded address of the next sequencer after the current sequencer + // if empty, it means there is no change in the sequencer + NextProposer string `protobuf:"bytes,11,opt,name=nextProposer,proto3" json:"nextProposer,omitempty"` } func (m *StateInfo) Reset() { *m = StateInfo{} } @@ -210,6 +213,13 @@ func (m *StateInfo) GetCreatedAt() time.Time { return time.Time{} } +func (m *StateInfo) GetNextProposer() string { + if m != nil { + return m.NextProposer + } + return "" +} + // StateInfoSummary is a compact representation of StateInfo type StateInfoSummary struct { // stateInfoIndex defines what rollapp the state belongs to @@ -343,42 +353,43 @@ func init() { } var fileDescriptor_deebb9ffbcdd017e = []byte{ - // 553 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x41, 0x6a, 0xdb, 0x40, - 0x14, 0xf5, 0xc4, 0x8e, 0x13, 0x4d, 0xc0, 0x24, 0x43, 0x28, 0xc2, 0xb4, 0xb2, 0x11, 0xb4, 0x78, - 0x25, 0x85, 0x94, 0x6e, 0x5a, 0xba, 0x88, 0x31, 0x21, 0xee, 0xaa, 0x55, 0xb2, 0x28, 0xa5, 0xe0, - 0x8e, 0xa4, 0xb1, 0x3c, 0x54, 0x9a, 0x51, 0x35, 0x23, 0x88, 0x72, 0x8a, 0x1c, 0xa4, 0x07, 0xc9, - 0x32, 0xbb, 0x76, 0x95, 0x16, 0xfb, 0x02, 0xa5, 0x27, 0x28, 0x1a, 0x29, 0x56, 0x62, 0xbb, 0x49, - 0x09, 0x74, 0xe7, 0xff, 0xfd, 0xdf, 0xd3, 0xfb, 0xef, 0x3f, 0x06, 0xbe, 0x90, 0x59, 0x4c, 0x84, - 0xed, 0x67, 0x11, 0x61, 0x82, 0x72, 0x76, 0x9a, 0x9d, 0x55, 0x85, 0x9d, 0xf0, 0x30, 0xc4, 0x71, - 0x6c, 0x0b, 0x89, 0x25, 0x19, 0x51, 0x36, 0xe6, 0x56, 0x9c, 0x70, 0xc9, 0x91, 0x71, 0x13, 0x60, - 0xcd, 0x0b, 0xab, 0x04, 0xb4, 0x77, 0x03, 0x1e, 0x70, 0x35, 0x6a, 0xe7, 0xbf, 0x0a, 0x54, 0xbb, - 0x13, 0x70, 0x1e, 0x84, 0xc4, 0x56, 0x95, 0x9b, 0x8e, 0x6d, 0x49, 0x23, 0x22, 0x24, 0x8e, 0xe2, - 0x72, 0xe0, 0xd5, 0x3f, 0xa9, 0x71, 0x43, 0xee, 0x7d, 0x1e, 0xf9, 0x44, 0x78, 0x09, 0x8d, 0x25, - 0x4f, 0x4a, 0xf0, 0xde, 0x9d, 0x60, 0x8f, 0x47, 0x11, 0x67, 0x6a, 0x93, 0x54, 0x14, 0x08, 0x73, - 0x00, 0x5b, 0xc7, 0xf9, 0x66, 0x43, 0x36, 0xe6, 0x43, 0xe6, 0x93, 0x53, 0xf4, 0x18, 0x6a, 0xe5, - 0x57, 0x86, 0xbe, 0x0e, 0xba, 0xa0, 0xa7, 0x39, 0x55, 0x03, 0xed, 0xc2, 0x75, 0x9a, 0x8f, 0xe9, - 0x6b, 0x5d, 0xd0, 0x6b, 0x38, 0x45, 0x61, 0xfe, 0xaa, 0x43, 0x6d, 0x4e, 0x83, 0x3e, 0xc2, 0x96, - 0xb8, 0xc5, 0xa9, 0x68, 0xb6, 0xf6, 0x2d, 0xeb, 0x6e, 0xcb, 0xac, 0xdb, 0x4a, 0xfa, 0x8d, 0x8b, - 0xab, 0x4e, 0xcd, 0x59, 0xe0, 0xca, 0xf5, 0x09, 0xf2, 0x25, 0x25, 0xcc, 0x23, 0x89, 0x52, 0xa1, - 0x39, 0x55, 0x03, 0x75, 0xe1, 0x96, 0x90, 0x38, 0x91, 0x47, 0x84, 0x06, 0x13, 0xa9, 0xd7, 0x95, - 0xca, 0x9b, 0xad, 0x1c, 0xcf, 0xd2, 0xa8, 0x9f, 0x1b, 0x28, 0xf4, 0x86, 0xfa, 0xbf, 0x6a, 0xa0, - 0x47, 0xb0, 0x39, 0x38, 0x78, 0x8b, 0xe5, 0x44, 0x5f, 0x57, 0xd4, 0x65, 0x85, 0x9e, 0xc1, 0x96, - 0x97, 0x10, 0x2c, 0x29, 0x67, 0x25, 0xf5, 0x86, 0x82, 0x2e, 0x74, 0xd1, 0x6b, 0xd8, 0x2c, 0xfc, - 0xd5, 0x37, 0xbb, 0xa0, 0xd7, 0xda, 0x7f, 0xfa, 0xb7, 0x9d, 0x8b, 0x63, 0xa8, 0x95, 0x53, 0xe1, - 0x94, 0x20, 0x74, 0x04, 0xeb, 0xfd, 0x81, 0xd0, 0x35, 0xe5, 0xd7, 0xde, 0x7d, 0x7e, 0x29, 0xcd, - 0x83, 0x79, 0x08, 0x44, 0xe9, 0x58, 0x4e, 0x81, 0xde, 0x43, 0xa8, 0xa4, 0x11, 0x7f, 0x84, 0xa5, - 0x0e, 0x15, 0x61, 0xdb, 0x2a, 0xd2, 0x67, 0x5d, 0xa7, 0xcf, 0x3a, 0xb9, 0x4e, 0x5f, 0xff, 0x49, - 0x0e, 0xfd, 0x7d, 0xd5, 0xd9, 0xc9, 0x70, 0x14, 0xbe, 0x34, 0x2b, 0xac, 0x79, 0xfe, 0xa3, 0x03, - 0x1c, 0xad, 0x6c, 0x1c, 0xc8, 0x37, 0x8d, 0xcd, 0xe6, 0xf6, 0x86, 0xf9, 0x0d, 0xc0, 0xed, 0xf9, - 0xbd, 0x8e, 0xd3, 0x28, 0xc2, 0x49, 0xf6, 0x9f, 0x2f, 0x5f, 0x79, 0xbb, 0xf6, 0x10, 0x6f, 0x97, - 0x4f, 0x58, 0x5f, 0x75, 0x42, 0xf3, 0x2b, 0x80, 0x86, 0x72, 0xb6, 0xa8, 0x4f, 0xf8, 0x21, 0x65, - 0x38, 0xa4, 0x67, 0x6a, 0xe6, 0x5d, 0x4a, 0x52, 0xb2, 0x82, 0x0a, 0xac, 0x4c, 0x83, 0x0b, 0x77, - 0xc6, 0x8b, 0x60, 0x7d, 0xad, 0x5b, 0x7f, 0xb0, 0x25, 0xcb, 0x74, 0xfd, 0x4f, 0x17, 0x53, 0x03, - 0x5c, 0x4e, 0x0d, 0xf0, 0x73, 0x6a, 0x80, 0xf3, 0x99, 0x51, 0xbb, 0x9c, 0x19, 0xb5, 0xef, 0x33, - 0xa3, 0xf6, 0xe1, 0x30, 0xa0, 0x72, 0x92, 0xba, 0xb9, 0x1d, 0x4b, 0x4f, 0x02, 0x65, 0xd2, 0x2e, - 0x1e, 0x8b, 0xd8, 0xbd, 0xe7, 0xb1, 0x71, 0x9b, 0x2a, 0x2e, 0xcf, 0xff, 0x04, 0x00, 0x00, 0xff, - 0xff, 0xd2, 0xe2, 0x5a, 0x02, 0x29, 0x05, 0x00, 0x00, + // 572 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcb, 0x6e, 0xd3, 0x40, + 0x14, 0xcd, 0x34, 0x69, 0x5a, 0x4f, 0x50, 0xd4, 0x8e, 0x2a, 0x64, 0x45, 0xe0, 0x44, 0x96, 0x40, + 0x59, 0xd9, 0x55, 0x11, 0x1b, 0x10, 0x8b, 0x46, 0x51, 0xd5, 0xb0, 0x2a, 0x6e, 0x17, 0x08, 0x21, + 0x05, 0x3b, 0x99, 0x38, 0x23, 0xec, 0x19, 0x33, 0x33, 0x96, 0xe2, 0x7e, 0x45, 0x17, 0x7c, 0x06, + 0x1f, 0xd2, 0x65, 0x77, 0xb0, 0x2a, 0x28, 0xf9, 0x03, 0xbe, 0x00, 0x79, 0xec, 0xc6, 0xcd, 0x83, + 0x16, 0x55, 0x62, 0x97, 0x7b, 0x73, 0xcf, 0xf1, 0xb9, 0xe7, 0x1e, 0x0d, 0x7c, 0x29, 0x93, 0x08, + 0x0b, 0x7b, 0x98, 0x84, 0x98, 0x0a, 0xc2, 0xe8, 0x24, 0x39, 0x2f, 0x0a, 0x9b, 0xb3, 0x20, 0x70, + 0xa3, 0xc8, 0x16, 0xd2, 0x95, 0xb8, 0x4f, 0xe8, 0x88, 0x59, 0x11, 0x67, 0x92, 0x21, 0xe3, 0x36, + 0xc0, 0x9a, 0x17, 0x56, 0x0e, 0x68, 0xec, 0xf9, 0xcc, 0x67, 0x6a, 0xd4, 0x4e, 0x7f, 0x65, 0xa8, + 0x46, 0xd3, 0x67, 0xcc, 0x0f, 0xb0, 0xad, 0x2a, 0x2f, 0x1e, 0xd9, 0x92, 0x84, 0x58, 0x48, 0x37, + 0x8c, 0xf2, 0x81, 0xd7, 0xff, 0xa4, 0xc6, 0x0b, 0xd8, 0xe0, 0x73, 0x7f, 0x88, 0xc5, 0x80, 0x93, + 0x48, 0x32, 0x9e, 0x83, 0xf7, 0xef, 0x04, 0x0f, 0x58, 0x18, 0x32, 0xaa, 0x36, 0x89, 0x45, 0x86, + 0x30, 0xbb, 0xb0, 0x7e, 0x9a, 0x6e, 0xd6, 0xa3, 0x23, 0xd6, 0xa3, 0x43, 0x3c, 0x41, 0x4f, 0xa0, + 0x96, 0x7f, 0xa5, 0x37, 0xd4, 0x41, 0x0b, 0xb4, 0x35, 0xa7, 0x68, 0xa0, 0x3d, 0xb8, 0x49, 0xd2, + 0x31, 0x7d, 0xa3, 0x05, 0xda, 0x15, 0x27, 0x2b, 0xcc, 0xaf, 0x15, 0xa8, 0xcd, 0x69, 0xd0, 0x47, + 0x58, 0x17, 0x0b, 0x9c, 0x8a, 0xa6, 0x76, 0x60, 0x59, 0x77, 0x5b, 0x66, 0x2d, 0x2a, 0xe9, 0x54, + 0x2e, 0xaf, 0x9b, 0x25, 0x67, 0x89, 0x2b, 0xd5, 0x27, 0xf0, 0x97, 0x18, 0xd3, 0x01, 0xe6, 0x4a, + 0x85, 0xe6, 0x14, 0x0d, 0xd4, 0x82, 0x35, 0x21, 0x5d, 0x2e, 0x8f, 0x31, 0xf1, 0xc7, 0x52, 0x2f, + 0x2b, 0x95, 0xb7, 0x5b, 0x29, 0x9e, 0xc6, 0x61, 0x27, 0x35, 0x50, 0xe8, 0x15, 0xf5, 0x7f, 0xd1, + 0x40, 0x8f, 0x61, 0xb5, 0x7b, 0x78, 0xe2, 0xca, 0xb1, 0xbe, 0xa9, 0xa8, 0xf3, 0x0a, 0x3d, 0x87, + 0xf5, 0x01, 0xc7, 0xae, 0x24, 0x8c, 0xe6, 0xd4, 0x5b, 0x0a, 0xba, 0xd4, 0x45, 0x6f, 0x60, 0x35, + 0xf3, 0x57, 0xdf, 0x6e, 0x81, 0x76, 0xfd, 0xe0, 0xd9, 0xdf, 0x76, 0xce, 0x8e, 0xa1, 0x56, 0x8e, + 0x85, 0x93, 0x83, 0xd0, 0x31, 0x2c, 0x77, 0xba, 0x42, 0xd7, 0x94, 0x5f, 0xfb, 0xf7, 0xf9, 0xa5, + 0x34, 0x77, 0xe7, 0x21, 0x10, 0xb9, 0x63, 0x29, 0x05, 0x7a, 0x0f, 0xa1, 0x92, 0x86, 0x87, 0x7d, + 0x57, 0xea, 0x50, 0x11, 0x36, 0xac, 0x2c, 0x7d, 0xd6, 0x4d, 0xfa, 0xac, 0xb3, 0x9b, 0xf4, 0x75, + 0x9e, 0xa6, 0xd0, 0xdf, 0xd7, 0xcd, 0xdd, 0xc4, 0x0d, 0x83, 0x57, 0x66, 0x81, 0x35, 0x2f, 0x7e, + 0x36, 0x81, 0xa3, 0xe5, 0x8d, 0x43, 0x89, 0x4c, 0xf8, 0x88, 0xe2, 0x89, 0x3c, 0xe1, 0x2c, 0x62, + 0x02, 0x73, 0xbd, 0xa6, 0x8c, 0x5a, 0xe8, 0xbd, 0xad, 0x6c, 0x57, 0x77, 0xb6, 0xcc, 0xef, 0x00, + 0xee, 0xcc, 0x6f, 0x7a, 0x1a, 0x87, 0xa1, 0xcb, 0x93, 0xff, 0x9c, 0x8e, 0xc2, 0xff, 0x8d, 0x87, + 0xf8, 0xbf, 0x7a, 0xe6, 0xf2, 0xba, 0x33, 0x9b, 0xdf, 0x00, 0x34, 0x94, 0xfb, 0x59, 0x7d, 0xc6, + 0x8e, 0x08, 0x75, 0x03, 0x72, 0xae, 0x66, 0xde, 0xc5, 0x38, 0xc6, 0x6b, 0xa8, 0xc0, 0xda, 0xc4, + 0x78, 0x70, 0x77, 0xb4, 0x0c, 0xd6, 0x37, 0x5a, 0xe5, 0x07, 0x5b, 0xb2, 0x4a, 0xd7, 0xf9, 0x74, + 0x39, 0x35, 0xc0, 0xd5, 0xd4, 0x00, 0xbf, 0xa6, 0x06, 0xb8, 0x98, 0x19, 0xa5, 0xab, 0x99, 0x51, + 0xfa, 0x31, 0x33, 0x4a, 0x1f, 0x8e, 0x7c, 0x22, 0xc7, 0xb1, 0x97, 0xda, 0xb1, 0xf2, 0x6c, 0x10, + 0x2a, 0xed, 0xec, 0x41, 0x89, 0xbc, 0x7b, 0x1e, 0x24, 0xaf, 0xaa, 0x22, 0xf5, 0xe2, 0x4f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x52, 0x1d, 0xf5, 0xb6, 0x4d, 0x05, 0x00, 0x00, } func (m *StateInfoIndex) Marshal() (dAtA []byte, err error) { @@ -436,6 +447,13 @@ func (m *StateInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.NextProposer) > 0 { + i -= len(m.NextProposer) + copy(dAtA[i:], m.NextProposer) + i = encodeVarintStateInfo(dAtA, i, uint64(len(m.NextProposer))) + i-- + dAtA[i] = 0x5a + } n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) if err1 != nil { return 0, err1 @@ -645,6 +663,10 @@ func (m *StateInfo) Size() (n int) { n += 1 + l + sovStateInfo(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovStateInfo(uint64(l)) + l = len(m.NextProposer) + if l > 0 { + n += 1 + l + sovStateInfo(uint64(l)) + } return n } @@ -1058,6 +1080,38 @@ func (m *StateInfo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NextProposer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStateInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStateInfo + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStateInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NextProposer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStateInfo(dAtA[iNdEx:])