From 34018b9f0e9833365397a827d3a411a1b896e16e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 21 Nov 2024 10:51:18 +0100 Subject: [PATCH] feat(manager): max skew based on time instead of batches (#1140) --- block/block.go | 4 +- block/executor.go | 1 - block/initchain.go | 2 + block/manager.go | 30 +++- block/manager_test.go | 2 +- block/produce.go | 7 +- block/state.go | 1 - block/submit.go | 81 ++++++---- block/submit_loop_test.go | 64 +++++--- block/submit_test.go | 9 +- block/sync.go | 3 + block/validate.go | 1 + config/config.go | 8 +- config/config_test.go | 6 +- config/defaults.go | 2 +- config/toml.go | 2 +- indexers/blockindexer/kv/kv.go | 1 + indexers/txindex/kv/kv.go | 5 +- .../dymensionxyz/dymint/store/mock_Store.go | 114 ++++++++++++++ node/node_test.go | 2 +- proto/types/dymint/state.proto | 3 +- rpc/client/client_test.go | 10 +- rpc/json/service_test.go | 2 +- store/storeIface.go | 2 + testutil/block.go | 2 +- testutil/node.go | 2 +- testutil/types.go | 1 + types/metrics.go | 5 + types/pb/dymint/state.pb.go | 144 ++++++------------ 29 files changed, 323 insertions(+), 193 deletions(-) diff --git a/block/block.go b/block/block.go index c7a8a4445..be383bc14 100644 --- a/block/block.go +++ b/block/block.go @@ -121,12 +121,14 @@ func (m *Manager) applyBlock(block *types.Block, commit *types.Commit, blockMeta m.logger.Debug("pruning channel full. skipping pruning", "retainHeight", retainHeight) } } - // Update the state with the new app hash, and store height from the commit. // Every one of those, if happens before commit, prevents us from re-executing the block in case failed during commit. m.Executor.UpdateStateAfterCommit(m.State, responses, appHash, block.Header.Height, block.Header.Hash()) + } + // save last block time used to calculate batch skew time + m.LastBlockTime.Store(block.Header.GetTimestamp().UTC().UnixNano()) // Update the store: // 1. Save the proposer for the current height to the store. // 2. Update the proposer in the state in case of rotation. diff --git a/block/executor.go b/block/executor.go index ef334ef5e..9650cb86a 100644 --- a/block/executor.go +++ b/block/executor.go @@ -175,7 +175,6 @@ func (e *Executor) CreateBlock( copy(block.Header.DataHash[:], types.GetDataHash(block)) copy(block.Header.SequencerHash[:], state.GetProposerHash()) copy(block.Header.NextSequencersHash[:], nextSeqHash[:]) - return block } diff --git a/block/initchain.go b/block/initchain.go index f9c3659e2..93b5ee2cc 100644 --- a/block/initchain.go +++ b/block/initchain.go @@ -22,11 +22,13 @@ func (m *Manager) RunInitChain(ctx context.Context) error { if err != nil { return err } + // update the state with only the consensus pubkey m.Executor.UpdateStateAfterInitChain(m.State, res) m.Executor.UpdateMempoolAfterInitChain(m.State) if _, err := m.Store.SaveState(m.State, nil); err != nil { return err } + return nil } diff --git a/block/manager.go b/block/manager.go index f8d3a711e..71794ce62 100644 --- a/block/manager.go +++ b/block/manager.go @@ -72,6 +72,12 @@ type Manager struct { // context used when freezing node Cancel context.CancelFunc Ctx context.Context + + // LastBlockTimeInSettlement is the time of last submitted block, used to measure batch skew time + LastBlockTimeInSettlement atomic.Int64 + + // LastBlockTime is the time of last produced block, used to measure batch skew time + LastBlockTime atomic.Int64 /* Sequencer and full-node */ @@ -303,20 +309,28 @@ func (m *Manager) updateFromLastSettlementState() error { // The SL hasn't got any batches for this chain yet. m.logger.Info("No batches for chain found in SL.") m.LastSettlementHeight.Store(uint64(m.Genesis.InitialHeight - 1)) + m.LastBlockTimeInSettlement.Store(m.Genesis.GenesisTime.UTC().UnixNano()) return nil } - if err != nil { // TODO: separate between fresh rollapp and non-registered rollapp return err } - m.LastSettlementHeight.Store(latestHeight) - if latestHeight >= m.State.NextHeight() { m.UpdateTargetHeight(latestHeight) } + m.LastSettlementHeight.Store(latestHeight) + + // init last block in settlement time in dymint state to calculate batch submit skew time + m.SetLastBlockTimeInSettlementFromHeight(latestHeight) + + // init last block time in dymint state to calculate batch submit skew time + block, err := m.Store.LoadBlock(m.State.Height()) + if err == nil { + m.LastBlockTime.Store(block.Header.GetTimestamp().UTC().UnixNano()) + } return nil } @@ -402,3 +416,13 @@ func (m *Manager) freezeNode(err error) { uevent.MustPublish(m.Ctx, m.Pubsub, &events.DataHealthStatus{Error: err}, events.HealthStatusList) m.Cancel() } + +// SetLastBlockTimeInSettlementFromHeight is used to initialize LastBlockTimeInSettlement from rollapp height in settlement +func (m *Manager) SetLastBlockTimeInSettlementFromHeight(lastSettlementHeight uint64) { + block, err := m.Store.LoadBlock(lastSettlementHeight) + if err != nil { + // if settlement height block is not found it will be updated after, when syncing + return + } + m.LastBlockTimeInSettlement.Store(block.Header.GetTimestamp().UTC().UnixNano()) +} diff --git a/block/manager_test.go b/block/manager_test.go index 215540937..6e2012858 100644 --- a/block/manager_test.go +++ b/block/manager_test.go @@ -190,7 +190,7 @@ func TestProduceOnlyAfterSynced(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*10) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*4) defer cancel() // Capture the error returned by manager.Start. diff --git a/block/produce.go b/block/produce.go index ef723286e..c6a2e5352 100644 --- a/block/produce.go +++ b/block/produce.go @@ -76,7 +76,7 @@ func (m *Manager) ProduceBlockLoop(ctx context.Context, bytesProducedC chan int) } bytesProducedN := block.SizeBytes() + commit.SizeBytes() - m.logger.Info("New block.", "size", uint64(block.ToProto().Size())) + select { case <-ctx.Done(): return nil @@ -84,8 +84,7 @@ func (m *Manager) ProduceBlockLoop(ctx context.Context, bytesProducedC chan int) default: evt := &events.DataHealthStatus{Error: fmt.Errorf("bytes produced channel is full: %w", gerrc.ErrResourceExhausted)} uevent.MustPublish(ctx, m.Pubsub, evt, events.HealthStatusList) - m.logger.Error("Enough bytes to build a batch have been accumulated, but too many batches are pending submission. " + - "Pausing block production until a signal is consumed.") + m.logger.Error("Pausing block production until new batch is submitted.", "Batch skew time", m.GetBatchSkewTime(), "Max batch skew time", m.Conf.MaxSkewTime) select { case <-ctx.Done(): return nil @@ -184,7 +183,7 @@ func (m *Manager) produceBlock(opts ProduceBlockOptions) (*types.Block, *types.C return nil, nil, fmt.Errorf("create commit: %w: %w", err, ErrNonRecoverable) } - m.logger.Info("Block created.", "height", newHeight, "num_tx", len(block.Data.Txs)) + m.logger.Info("Block created.", "height", newHeight, "num_tx", len(block.Data.Txs), "size", block.SizeBytes()+commit.SizeBytes()) types.RollappBlockSizeBytesGauge.Set(float64(len(block.Data.Txs))) types.RollappBlockSizeTxsGauge.Set(float64(len(block.Data.Txs))) return block, commit, nil diff --git a/block/state.go b/block/state.go index 97d865635..70d5202c2 100644 --- a/block/state.go +++ b/block/state.go @@ -122,7 +122,6 @@ func (e *Executor) UpdateStateAfterCommit(s *types.State, resp *tmstate.ABCIResp copy(s.LastHeaderHash[:], lastHeaderHash[:]) s.SetHeight(height) - if resp.EndBlock.ConsensusParamUpdates != nil { s.ConsensusParams.Block.MaxGas = resp.EndBlock.ConsensusParamUpdates.Block.MaxGas s.ConsensusParams.Block.MaxBytes = resp.EndBlock.ConsensusParamUpdates.Block.MaxBytes diff --git a/block/submit.go b/block/submit.go index 9facdeef4..2105578d6 100644 --- a/block/submit.go +++ b/block/submit.go @@ -14,7 +14,6 @@ import ( "github.com/dymensionxyz/dymint/da" "github.com/dymensionxyz/dymint/settlement" "github.com/dymensionxyz/dymint/types" - uatomic "github.com/dymensionxyz/dymint/utils/atomic" uchannel "github.com/dymensionxyz/dymint/utils/channel" ) @@ -30,8 +29,10 @@ func (m *Manager) SubmitLoop(ctx context.Context, ctx, m.logger, bytesProduced, - m.Conf.BatchSkew, + m.Conf.MaxSkewTime, m.GetUnsubmittedBlocks, + m.GetUnsubmittedBytes, + m.GetBatchSkewTime, m.Conf.BatchSubmitTime, m.Conf.BatchSubmitBytes, m.CreateAndSubmitBatchGetSizeBlocksCommits, @@ -43,11 +44,13 @@ func SubmitLoopInner( ctx context.Context, logger types.Logger, bytesProduced chan int, // a channel of block and commit bytes produced - maxBatchSkew uint64, // max number of blocks that submitter is allowed to have pending - unsubmittedBlocks func() uint64, - maxBatchTime time.Duration, // max time to allow between batches - maxBatchBytes uint64, // max size of serialised batch in bytes - createAndSubmitBatch func(maxSizeBytes uint64) (sizeBlocksCommits uint64, err error), + maxProduceSubmitSkewTime time.Duration, // max time between last submitted block and last produced block allowed. if this threshold is reached block production is stopped. + unsubmittedBlocksNum func() uint64, + unsubmittedBlocksBytes func() int, + batchSkewTime func() time.Duration, + maxBatchSubmitTime time.Duration, // max time to allow between batches + maxBatchSubmitBytes uint64, // max size of serialised batch in bytes + createAndSubmitBatch func(maxSizeBytes uint64) (bytes uint64, err error), ) error { eg, ctx := errgroup.WithContext(ctx) @@ -60,7 +63,17 @@ func SubmitLoopInner( // 'trigger': this thread is responsible for waking up the submitter when a new block arrives, and back-pressures the block production loop // if it gets too far ahead. for { - if maxBatchSkew*maxBatchBytes < pendingBytes.Load() { + select { + case <-ctx.Done(): + return ctx.Err() + case n := <-bytesProduced: + pendingBytes.Add(uint64(n)) + logger.Debug("Added bytes produced to bytes pending submission counter.", "bytes added", n, "pending", pendingBytes.Load()) + } + + submitter.Nudge() + + if maxProduceSubmitSkewTime < batchSkewTime() { // too much stuff is pending submission // we block here until we get a progress nudge from the submitter thread select { @@ -68,26 +81,14 @@ func SubmitLoopInner( return ctx.Err() case <-trigger.C: } - } else { - select { - case <-ctx.Done(): - return ctx.Err() - case n := <-bytesProduced: - pendingBytes.Add(uint64(n)) - logger.Debug("Added bytes produced to bytes pending submission counter.", "bytes added", n, "pending", pendingBytes.Load()) - } } - types.RollappPendingSubmissionsSkewBytes.Set(float64(pendingBytes.Load())) - types.RollappPendingSubmissionsSkewBlocks.Set(float64(unsubmittedBlocks())) - submitter.Nudge() } }) eg.Go(func() error { // 'submitter': this thread actually creates and submits batches, and will do it on a timer if he isn't nudged by block production - timeLastSubmission := time.Now() - ticker := time.NewTicker(maxBatchTime / 10) // interval does not need to match max batch time since we keep track anyway, it's just to wakeup + ticker := time.NewTicker(maxBatchSubmitTime / 10) // interval does not need to match max batch time since we keep track anyway, it's just to wakeup for { select { case <-ctx.Done(): @@ -97,21 +98,22 @@ func SubmitLoopInner( } pending := pendingBytes.Load() - types.RollappPendingSubmissionsSkewBytes.Set(float64(pendingBytes.Load())) - types.RollappPendingSubmissionsSkewBlocks.Set(float64(unsubmittedBlocks())) - types.RollappPendingSubmissionsSkewBatches.Set(float64(pendingBytes.Load() / maxBatchBytes)) // while there are accumulated blocks, create and submit batches!! for { done := ctx.Err() != nil nothingToSubmit := pending == 0 - lastSubmissionIsRecent := time.Since(timeLastSubmission) < maxBatchTime - maxDataNotExceeded := pending <= maxBatchBytes + + lastSubmissionIsRecent := batchSkewTime() < maxBatchSubmitTime + maxDataNotExceeded := pending <= maxBatchSubmitBytes + + UpdateBatchSubmissionGauges(pending, unsubmittedBlocksNum(), batchSkewTime()) + if done || nothingToSubmit || (lastSubmissionIsRecent && maxDataNotExceeded) { break } - nConsumed, err := createAndSubmitBatch(min(pending, maxBatchBytes)) + nConsumed, err := createAndSubmitBatch(maxBatchSubmitBytes) if err != nil { err = fmt.Errorf("create and submit batch: %w", err) if errors.Is(err, gerrc.ErrInternal) { @@ -126,9 +128,8 @@ func SubmitLoopInner( } return err } - timeLastSubmission = time.Now() - ticker.Reset(maxBatchTime) - pending = uatomic.Uint64Sub(&pendingBytes, nConsumed) + ticker.Reset(maxBatchSubmitTime) + pending = uint64(unsubmittedBlocksBytes()) logger.Info("Submitted a batch to both sub-layers.", "n bytes consumed from pending", nConsumed, "pending after", pending) // TODO: debug level } trigger.Nudge() @@ -219,7 +220,7 @@ func (m *Manager) CreateBatch(maxBatchSize uint64, startHeight uint64, endHeight batch.DRSVersion = batch.DRSVersion[:len(batch.DRSVersion)-1] if h == startHeight { - return nil, fmt.Errorf("block size exceeds max batch size: h %d: size: %d: %w", h, totalSize, gerrc.ErrOutOfRange) + return nil, fmt.Errorf("block size exceeds max batch size: h %d: batch size: %d: max size: %d err:%w", h, totalSize, maxBatchSize, gerrc.ErrOutOfRange) } break } @@ -246,7 +247,10 @@ func (m *Manager) SubmitBatch(batch *types.Batch) error { types.RollappHubHeightGauge.Set(float64(batch.EndHeight())) m.LastSettlementHeight.Store(batch.EndHeight()) - return nil + // update last submitted block time with batch last block (used to calculate max skew time) + m.LastBlockTimeInSettlement.Store(batch.Blocks[len(batch.Blocks)-1].Header.GetTimestamp().UTC().UnixNano()) + + return err } // GetUnsubmittedBytes returns the total number of unsubmitted bytes produced an element on a channel @@ -300,3 +304,16 @@ func (m *Manager) UpdateLastSubmittedHeight(event pubsub.Message) { } } } + +// GetBatchSkewTime returns the time between the last produced block and the last block submitted to SL +func (m *Manager) GetBatchSkewTime() time.Duration { + lastProducedTime := time.Unix(0, m.LastBlockTime.Load()) + lastSubmittedTime := time.Unix(0, m.LastBlockTimeInSettlement.Load()) + return lastProducedTime.Sub(lastSubmittedTime) +} + +func UpdateBatchSubmissionGauges(skewBytes uint64, skewBlocks uint64, skewTime time.Duration) { + types.RollappPendingSubmissionsSkewBytes.Set(float64(skewBytes)) + types.RollappPendingSubmissionsSkewBlocks.Set(float64(skewBlocks)) + types.RollappPendingSubmissionsSkewTimeMinutes.Set(float64(skewTime.Minutes())) +} diff --git a/block/submit_loop_test.go b/block/submit_loop_test.go index 403adda52..d6ed9d56c 100644 --- a/block/submit_loop_test.go +++ b/block/submit_loop_test.go @@ -2,6 +2,7 @@ package block_test import ( "context" + "fmt" "math/rand" "sync" "sync/atomic" @@ -16,7 +17,8 @@ import ( type testArgs struct { nParallel int // number of instances to run in parallel testDuration time.Duration // how long to run one instance of the test (should be short) - batchSkew uint64 // max number of batches to get ahead + batchSkew time.Duration // time between last block produced and submitted + skewMargin time.Duration // skew margin allowed batchBytes uint64 // max number of bytes in a batch maxTime time.Duration // maximum time to wait before submitting submissions submitTime time.Duration // how long it takes to submit a batch @@ -54,14 +56,24 @@ func testSubmitLoopInner( return time.Duration(base + rand.Intn(factor)) } - pendingBlocks := atomic.Uint64{} // pending blocks to be submitted. gap between produced and submitted. - + pendingBlocks := atomic.Uint64{} // pending blocks to be submitted. gap between produced and submitted. nProducedBytes := atomic.Uint64{} // tracking how many actual bytes have been produced but not submitted so far producedBytesC := make(chan int) // producer sends on here, and can be blocked by not consuming from here - // the time of the last block produced or the last batch submitted or the last starting of the node - timeLastProgress := atomic.Int64{} + lastSettlementBlockTime := atomic.Int64{} + lastBlockTime := atomic.Int64{} + lastSettlementBlockTime.Store(time.Now().UTC().UnixNano()) + lastBlockTime.Store(time.Now().UTC().UnixNano()) + skewTime := func() time.Duration { + blockTime := time.Unix(0, lastBlockTime.Load()) + settlementTime := time.Unix(0, lastSettlementBlockTime.Load()) + return blockTime.Sub(settlementTime) + } + skewNow := func() time.Duration { + settlementTime := time.Unix(0, lastSettlementBlockTime.Load()) + return time.Now().Sub(settlementTime) + } go func() { // simulate block production go func() { // another thread to check system properties for { @@ -71,9 +83,7 @@ func testSubmitLoopInner( default: } // producer shall not get too far ahead - absoluteMax := (args.batchSkew + 1) * args.batchBytes // +1 is because the producer is always blocked after the fact - nProduced := nProducedBytes.Load() - require.True(t, nProduced < absoluteMax, "produced bytes not less than maximum", "nProduced", nProduced, "max", absoluteMax) + require.True(t, skewTime() < args.batchSkew+args.skewMargin, fmt.Sprintf("last produced blocks time not less than maximum skew time. produced block skew time: %s max skew: %s", skewTime(), args.batchSkew+args.skewMargin)) } }() for { @@ -82,13 +92,19 @@ func testSubmitLoopInner( return default: } + time.Sleep(approx(args.produceTime)) + + if args.batchSkew <= skewNow() { + continue + } + nBytes := rand.Intn(args.produceBytes) // simulate block production nProducedBytes.Add(uint64(nBytes)) producedBytesC <- nBytes - pendingBlocks.Add(1) // increase pending blocks to be submitted counter + lastBlockTime.Store(time.Now().UTC().UnixNano()) - timeLastProgress.Store(time.Now().Unix()) + pendingBlocks.Add(1) // increase pending blocks to be submitted counter } }() @@ -96,25 +112,21 @@ func testSubmitLoopInner( time.Sleep(approx(args.submitTime)) if rand.Float64() < args.submissionHaltProbability { time.Sleep(args.submissionHaltTime) - timeLastProgress.Store(time.Now().Unix()) // we have now recovered } consumed := rand.Intn(int(maxSize)) nProducedBytes.Add(^uint64(consumed - 1)) // subtract - - timeLastProgressT := time.Unix(timeLastProgress.Load(), 0) - absoluteMax := int64(2 * float64(args.maxTime)) // allow some leeway for code execution. Tests may run on small boxes (GH actions) - timeSinceLast := time.Since(timeLastProgressT).Milliseconds() - require.True(t, timeSinceLast < absoluteMax, "too long since last update", "timeSinceLast", timeSinceLast, "max", absoluteMax) - pendingBlocks.Store(0) // no pending blocks to be submitted - timeLastProgress.Store(time.Now().Unix()) // we have submitted batch + lastSettlementBlockTime.Store(lastBlockTime.Load()) return uint64(consumed), nil } accumulatedBlocks := func() uint64 { return pendingBlocks.Load() } + pendingBytes := func() int { + return int(nProducedBytes.Load()) + } - block.SubmitLoopInner(ctx, log.NewNopLogger(), producedBytesC, args.batchSkew, accumulatedBlocks, args.maxTime, args.batchBytes, submitBatch) + block.SubmitLoopInner(ctx, log.NewNopLogger(), producedBytesC, args.batchSkew, accumulatedBlocks, pendingBytes, skewTime, args.maxTime, args.batchBytes, submitBatch) } // Make sure the producer does not get too far ahead @@ -123,8 +135,9 @@ func TestSubmitLoopFastProducerHaltingSubmitter(t *testing.T) { t, testArgs{ nParallel: 50, - testDuration: 2 * time.Second, - batchSkew: 10, + testDuration: 4 * time.Second, + batchSkew: 100 * time.Millisecond, + skewMargin: 10 * time.Millisecond, batchBytes: 100, maxTime: 10 * time.Millisecond, submitTime: 2 * time.Millisecond, @@ -132,8 +145,8 @@ func TestSubmitLoopFastProducerHaltingSubmitter(t *testing.T) { produceTime: 2 * time.Millisecond, // a relatively long possibility of the submitter halting // tests the case where we need to stop the producer getting too far ahead - submissionHaltTime: 50 * time.Millisecond, - submissionHaltProbability: 0.01, + submissionHaltTime: 150 * time.Millisecond, + submissionHaltProbability: 0.05, }, ) } @@ -144,8 +157,9 @@ func TestSubmitLoopTimer(t *testing.T) { t, testArgs{ nParallel: 50, - testDuration: 2 * time.Second, - batchSkew: 10, + testDuration: 4 * time.Second, + batchSkew: 100 * time.Millisecond, + skewMargin: 10 * time.Millisecond, batchBytes: 100, maxTime: 10 * time.Millisecond, submitTime: 2 * time.Millisecond, diff --git a/block/submit_test.go b/block/submit_test.go index 0cf54f6d8..c6511785e 100644 --- a/block/submit_test.go +++ b/block/submit_test.go @@ -39,6 +39,7 @@ func TestBatchOverhead(t *testing.T) { manager, err := testutil.GetManager(testutil.GetManagerConfig(), nil, 1, 1, 0, nil, nil) require.NoError(t, err) require.NotNil(t, manager) + maxBatchSize := uint64(10_000) // 10KB maxTxData := uint64(float64(maxBatchSize) * types.MaxBlockSizeAdjustment) // 90% of maxBatchSize @@ -211,12 +212,12 @@ func TestBatchSubmissionFailedSubmission(t *testing.T) { assert.Zero(t, manager.LastSettlementHeight.Load()) // try to submit, we expect failure - slmock.On("SubmitBatch", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("submit batch")).Once() + slmock.On("SubmitBatch", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("submit batch")).Once() _, err = manager.CreateAndSubmitBatch(manager.Conf.BatchSubmitBytes, false) assert.Error(t, err) // try to submit again, we expect success - slmock.On("SubmitBatch", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + slmock.On("SubmitBatch", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() manager.CreateAndSubmitBatch(manager.Conf.BatchSubmitBytes, false) assert.EqualValues(t, manager.State.Height(), manager.LastSettlementHeight.Load()) } @@ -254,7 +255,7 @@ func TestSubmissionByTime(t *testing.T) { managerConfig := config.BlockManagerConfig{ BlockTime: blockTime, MaxIdleTime: 0, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, BatchSubmitTime: submitTimeout, BatchSubmitBytes: 1000, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, @@ -266,6 +267,7 @@ func TestSubmissionByTime(t *testing.T) { manager.DAClient = testutil.GetMockDALC(log.TestingLogger()) manager.Retriever = manager.DAClient.(da.BatchRetriever) + manager.LastBlockTimeInSettlement.Store(time.Now().UTC().UnixNano()) // Check initial height initialHeight := uint64(0) require.Equal(initialHeight, manager.State.Height()) @@ -338,6 +340,7 @@ func TestSubmissionByBatchSize(t *testing.T) { managerConfig.BatchSubmitBytes = c.blockBatchMaxSizeBytes manager, err := testutil.GetManager(managerConfig, nil, 1, 1, 0, proxyApp, nil) require.NoError(err) + manager.LastBlockTimeInSettlement.Store(time.Now().UTC().UnixNano()) manager.DAClient = testutil.GetMockDALC(log.TestingLogger()) manager.Retriever = manager.DAClient.(da.BatchRetriever) diff --git a/block/sync.go b/block/sync.go index 1f7b6a53e..319411ba5 100644 --- a/block/sync.go +++ b/block/sync.go @@ -75,6 +75,9 @@ func (m *Manager) SettlementSyncLoop(ctx context.Context) error { } m.logger.Info("Retrieved state update from SL.", "state_index", settlementBatch.StateIndex) + // we update LastBlockTimeInSettlement to be able to measure batch skew time with last block time in settlement + m.LastBlockTimeInSettlement.Store(settlementBatch.BlockDescriptors[len(settlementBatch.BlockDescriptors)-1].GetTimestamp().UTC().UnixNano()) + err = m.ApplyBatchFromSL(settlementBatch.Batch) if err != nil { return fmt.Errorf("process next DA batch. err:%w", err) diff --git a/block/validate.go b/block/validate.go index 281f49f44..939dd7ee1 100644 --- a/block/validate.go +++ b/block/validate.go @@ -39,6 +39,7 @@ func (m *Manager) SettlementValidateLoop(ctx context.Context) error { uevent.MustPublish(ctx, m.Pubsub, &events.DataHealthStatus{Error: err}, events.HealthStatusList) return err } + // validate batch err = m.SettlementValidator.ValidateStateUpdate(batch) if err != nil { diff --git a/config/config.go b/config/config.go index 9c7a6e783..c19c58277 100644 --- a/config/config.go +++ b/config/config.go @@ -55,8 +55,8 @@ type BlockManagerConfig struct { MaxProofTime time.Duration `mapstructure:"max_proof_time"` // BatchSubmitMaxTime is how long should block manager wait for before submitting batch BatchSubmitTime time.Duration `mapstructure:"batch_submit_time"` - // BatchSkew is the number of batches waiting to be submitted. Block production will be paused if this limit is reached. - BatchSkew uint64 `mapstructure:"max_batch_skew"` + // MaxSkewTime is the number of batches waiting to be submitted. Block production will be paused if this limit is reached. + MaxSkewTime time.Duration `mapstructure:"max_skew_time"` // The size of the batch of blocks and commits in Bytes. We'll write every batch to the DA and the settlement layer. BatchSubmitBytes uint64 `mapstructure:"batch_submit_bytes"` // SequencerSetUpdateInterval defines the interval at which to fetch sequencer updates from the settlement layer @@ -161,8 +161,8 @@ func (c BlockManagerConfig) Validate() error { return fmt.Errorf("batch_submit_bytes must be positive") } - if c.BatchSkew <= 0 { - return fmt.Errorf("max_batch_skew must be positive") + if c.MaxSkewTime < c.BatchSubmitTime { + return fmt.Errorf("max_skew_time cannot be less than batch_submit_time. max_skew_time: %s batch_submit_time: %s", c.MaxSkewTime, c.BatchSubmitTime) } if c.SequencerSetUpdateInterval <= 0 { diff --git a/config/config_test.go b/config/config_test.go index dd1bfaa3a..b74514a25 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -98,9 +98,9 @@ func TestNodeConfig_Validate(t *testing.T) { }, wantErr: assert.Error, }, { - name: "max_batch_skew 0", + name: "max_skew_time 0", malleate: func(nc *config.NodeConfig) { - nc.BlockManagerConfig.BatchSkew = 0 + nc.BlockManagerConfig.MaxSkewTime = 0 }, wantErr: assert.Error, }, { @@ -187,7 +187,7 @@ func fullNodeConfig() config.NodeConfig { MaxIdleTime: 20 * time.Second, MaxProofTime: 20 * time.Second, BatchSubmitTime: 20 * time.Second, - BatchSkew: 10, + MaxSkewTime: 24 * 7 * time.Hour, BatchSubmitBytes: 10000, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, diff --git a/config/defaults.go b/config/defaults.go index e3f8f776e..b72ef3aac 100644 --- a/config/defaults.go +++ b/config/defaults.go @@ -28,7 +28,7 @@ func DefaultConfig(home string) *NodeConfig { MaxIdleTime: 3600 * time.Second, MaxProofTime: 5 * time.Second, BatchSubmitTime: 3600 * time.Second, - BatchSkew: 10, + MaxSkewTime: 24 * 7 * time.Hour, BatchSubmitBytes: 500000, SequencerSetUpdateInterval: DefaultSequencerSetUpdateInterval, }, diff --git a/config/toml.go b/config/toml.go index 14e2ee800..637e4b19c 100644 --- a/config/toml.go +++ b/config/toml.go @@ -70,7 +70,7 @@ block_time = "{{ .BlockManagerConfig.BlockTime }}" # block production interval in case of no transactions ("0s" produces empty blocks) max_idle_time = "{{ .BlockManagerConfig.MaxIdleTime }}" max_proof_time = "{{ .BlockManagerConfig.MaxProofTime }}" -max_batch_skew = {{ .BlockManagerConfig.BatchSkew }} +max_skew_time = "{{ .BlockManagerConfig.MaxSkewTime }}" # triggers to submit batch to DA and settlement (both required) diff --git a/indexers/blockindexer/kv/kv.go b/indexers/blockindexer/kv/kv.go index 673323561..e88f24224 100644 --- a/indexers/blockindexer/kv/kv.go +++ b/indexers/blockindexer/kv/kv.go @@ -567,6 +567,7 @@ func (idx *BlockerIndexer) pruneBlocks(from, to uint64, logger log.Logger) (uint if !ok { continue } + key, err := heightKey(h) if err != nil { logger.Debug("pruning block indexer getting height key", "height", h, "err", err) diff --git a/indexers/txindex/kv/kv.go b/indexers/txindex/kv/kv.go index aeca26fc6..e7548dc98 100644 --- a/indexers/txindex/kv/kv.go +++ b/indexers/txindex/kv/kv.go @@ -607,12 +607,12 @@ func (txi *TxIndex) pruneTxsAndEvents(from, to uint64, logger log.Logger) (uint6 // first all events are pruned associated to the same height prunedEvents, err := txi.pruneEvents(h, batch) + pruned += prunedEvents + toFlush += prunedEvents if err != nil { logger.Error("pruning txs indexer events by height", "height", h, "error", err) continue } - pruned += prunedEvents - toFlush += prunedEvents // then all txs indexed are iterated by height it := txi.store.PrefixIterator(prefixForHeight(int64(h))) @@ -624,7 +624,6 @@ func (txi *TxIndex) pruneTxsAndEvents(from, to uint64, logger log.Logger) (uint6 logger.Error("pruning txs indexer event key", "height", h, "error", err) continue } - if err := batch.Delete(it.Value()); err != nil { logger.Error("pruning txs indexer event val", "height", h, "error", err) continue diff --git a/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go b/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go index 5cb0aee0f..3afabcaa7 100644 --- a/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go +++ b/mocks/github.com/dymensionxyz/dymint/store/mock_Store.go @@ -694,6 +694,61 @@ func (_c *MockStore_LoadIndexerBaseHeight_Call) RunAndReturn(run func() (uint64, return _c } +// LoadLastSettlementBlockTime provides a mock function with given fields: +func (_m *MockStore) LoadLastSettlementBlockTime() (uint64, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for LoadLastSettlementBlockTime") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func() (uint64, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() uint64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_LoadLastSettlementBlockTime_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoadLastSettlementBlockTime' +type MockStore_LoadLastSettlementBlockTime_Call struct { + *mock.Call +} + +// LoadLastSettlementBlockTime is a helper method to define mock.On call +func (_e *MockStore_Expecter) LoadLastSettlementBlockTime() *MockStore_LoadLastSettlementBlockTime_Call { + return &MockStore_LoadLastSettlementBlockTime_Call{Call: _e.mock.On("LoadLastSettlementBlockTime")} +} + +func (_c *MockStore_LoadLastSettlementBlockTime_Call) Run(run func()) *MockStore_LoadLastSettlementBlockTime_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockStore_LoadLastSettlementBlockTime_Call) Return(_a0 uint64, _a1 error) *MockStore_LoadLastSettlementBlockTime_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_LoadLastSettlementBlockTime_Call) RunAndReturn(run func() (uint64, error)) *MockStore_LoadLastSettlementBlockTime_Call { + _c.Call.Return(run) + return _c +} + // LoadProposer provides a mock function with given fields: height func (_m *MockStore) LoadProposer(height uint64) (types.Sequencer, error) { ret := _m.Called(height) @@ -1450,6 +1505,65 @@ func (_c *MockStore_SaveIndexerBaseHeight_Call) RunAndReturn(run func(uint64) er return _c } +// SaveLastSettlementBlockTime provides a mock function with given fields: height, batch +func (_m *MockStore) SaveLastSettlementBlockTime(height uint64, batch store.KVBatch) (store.KVBatch, error) { + ret := _m.Called(height, batch) + + if len(ret) == 0 { + panic("no return value specified for SaveLastSettlementBlockTime") + } + + var r0 store.KVBatch + var r1 error + if rf, ok := ret.Get(0).(func(uint64, store.KVBatch) (store.KVBatch, error)); ok { + return rf(height, batch) + } + if rf, ok := ret.Get(0).(func(uint64, store.KVBatch) store.KVBatch); ok { + r0 = rf(height, batch) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.KVBatch) + } + } + + if rf, ok := ret.Get(1).(func(uint64, store.KVBatch) error); ok { + r1 = rf(height, batch) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_SaveLastSettlementBlockTime_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveLastSettlementBlockTime' +type MockStore_SaveLastSettlementBlockTime_Call struct { + *mock.Call +} + +// SaveLastSettlementBlockTime is a helper method to define mock.On call +// - height uint64 +// - batch store.KVBatch +func (_e *MockStore_Expecter) SaveLastSettlementBlockTime(height interface{}, batch interface{}) *MockStore_SaveLastSettlementBlockTime_Call { + return &MockStore_SaveLastSettlementBlockTime_Call{Call: _e.mock.On("SaveLastSettlementBlockTime", height, batch)} +} + +func (_c *MockStore_SaveLastSettlementBlockTime_Call) Run(run func(height uint64, batch store.KVBatch)) *MockStore_SaveLastSettlementBlockTime_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64), args[1].(store.KVBatch)) + }) + return _c +} + +func (_c *MockStore_SaveLastSettlementBlockTime_Call) Return(_a0 store.KVBatch, _a1 error) *MockStore_SaveLastSettlementBlockTime_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_SaveLastSettlementBlockTime_Call) RunAndReturn(run func(uint64, store.KVBatch) (store.KVBatch, error)) *MockStore_SaveLastSettlementBlockTime_Call { + _c.Call.Return(run) + return _c +} + // SaveProposer provides a mock function with given fields: height, proposer, batch func (_m *MockStore) SaveProposer(height uint64, proposer types.Sequencer, batch store.KVBatch) (store.KVBatch, error) { ret := _m.Called(height, proposer, batch) diff --git a/node/node_test.go b/node/node_test.go index 342ab33b1..9b953e01e 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -80,7 +80,7 @@ func TestMempoolDirectly(t *testing.T) { BlockTime: 1 * time.Second, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 100000, - BatchSkew: 10, + MaxSkewTime: 24 * 7 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, DAConfig: "", diff --git a/proto/types/dymint/state.proto b/proto/types/dymint/state.proto index 21d6a39cb..48b4c4181 100755 --- a/proto/types/dymint/state.proto +++ b/proto/types/dymint/state.proto @@ -21,8 +21,8 @@ message State { int64 last_block_height = 4; tendermint.types.BlockID last_block_id = 5 [(gogoproto.nullable) = false, (gogoproto.customname) = "LastBlockID"]; - google.protobuf.Timestamp last_block_time = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + reserved 6; reserved 7; reserved 8; tendermint.types.ValidatorSet validators = 9 [deprecated = true]; @@ -50,6 +50,7 @@ message State { Sequencer proposer = 20; int64 revision_start_height = 21; + } //rollapp params defined in genesis and updated via gov proposal diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index f49afdf35..1434b142f 100644 --- a/rpc/client/client_test.go +++ b/rpc/client/client_test.go @@ -109,7 +109,7 @@ func TestGenesisChunked(t *testing.T) { BlockTime: 100 * time.Millisecond, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 1000, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, DAConfig: "", @@ -858,7 +858,7 @@ func TestValidatorSetHandling(t *testing.T) { BlockTime: 10 * time.Millisecond, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 1000, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, SettlementConfig: settlement.Config{ @@ -1022,7 +1022,7 @@ func getRPCInternal(t *testing.T, sequencer bool) (*tmmocks.MockApplication, *cl BlockTime: 100 * time.Millisecond, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 1000, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, DAConfig: "", @@ -1129,7 +1129,7 @@ func TestMempool2Nodes(t *testing.T) { BlockTime: 100 * time.Millisecond, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 1000, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, MempoolConfig: *tmcfg.DefaultMempoolConfig(), @@ -1146,7 +1146,7 @@ func TestMempool2Nodes(t *testing.T) { BlockTime: 100 * time.Millisecond, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 1000, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, }, P2PConfig: config.P2PConfig{ diff --git a/rpc/json/service_test.go b/rpc/json/service_test.go index 7f0243bca..fd644295a 100644 --- a/rpc/json/service_test.go +++ b/rpc/json/service_test.go @@ -316,7 +316,7 @@ func getRPC(t *testing.T) (*tmmocks.MockApplication, *client.Client) { BlockManagerConfig: config.BlockManagerConfig{ BlockTime: 1 * time.Second, MaxIdleTime: 0, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, BatchSubmitTime: 30 * time.Minute, BatchSubmitBytes: 1000, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, diff --git a/store/storeIface.go b/store/storeIface.go index 5f49031be..b2a127e11 100644 --- a/store/storeIface.go +++ b/store/storeIface.go @@ -47,6 +47,7 @@ type Store interface { // LoadBlock returns block at given height, or error if it's not found in Store. LoadBlock(height uint64) (*types.Block, error) + // LoadBlockByHash returns block with given block header hash, or error if it's not found in Store. LoadBlockByHash(hash [32]byte) (*types.Block, error) @@ -58,6 +59,7 @@ type Store interface { // LoadCommit returns commit for a block at given height, or error if it's not found in Store. LoadCommit(height uint64) (*types.Commit, error) + // LoadCommitByHash returns commit for a block with given block header hash, or error if it's not found in Store. LoadCommitByHash(hash [32]byte) (*types.Commit, error) diff --git a/testutil/block.go b/testutil/block.go index df4e9922e..f60257055 100644 --- a/testutil/block.go +++ b/testutil/block.go @@ -175,7 +175,7 @@ func GetManagerConfig() config.BlockManagerConfig { BlockTime: 100 * time.Millisecond, BatchSubmitBytes: 1000000, BatchSubmitTime: 30 * time.Minute, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, } } diff --git a/testutil/node.go b/testutil/node.go index 49bd4a820..1f7f0955f 100644 --- a/testutil/node.go +++ b/testutil/node.go @@ -56,7 +56,7 @@ func CreateNode(isSequencer bool, blockManagerConfig *config.BlockManagerConfig, BlockTime: 100 * time.Millisecond, BatchSubmitTime: 60 * time.Second, BatchSubmitBytes: 1000, - BatchSkew: 10, + MaxSkewTime: 24 * time.Hour, SequencerSetUpdateInterval: config.DefaultSequencerSetUpdateInterval, } } diff --git a/testutil/types.go b/testutil/types.go index a99a8b2ae..c71c90192 100644 --- a/testutil/types.go +++ b/testutil/types.go @@ -156,6 +156,7 @@ func GenerateBlocks(startHeight uint64, num uint64, proposerKey crypto.PrivKey, } block.LastCommit.Signatures = []types.Signature{signature} block.Header.ProposerAddress = ed25519.PrivKey(r).PubKey().Address() + block.Header.Time = time.Now().UTC().UnixNano() blocks[i] = block lastHeaderHash = block.Header.Hash() } diff --git a/types/metrics.go b/types/metrics.go index 5ad097313..0b5bb5813 100644 --- a/types/metrics.go +++ b/types/metrics.go @@ -35,6 +35,11 @@ var RollappPendingSubmissionsSkewBatches = promauto.NewGauge(prometheus.GaugeOpt Help: "The number of batches which have been accumulated but not yet submitted.", }) +var RollappPendingSubmissionsSkewTimeMinutes = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "rollapp_pending_submissions_skew_time_minutes", + Help: "Time between the last block produced and the last block submitted in minutes.", +}) + var RollappPendingSubmissionsSkewBytes = promauto.NewGauge(prometheus.GaugeOpts{ Name: "rollapp_pending_submissions_skew_bytes", Help: "The number of bytes (of blocks and commits) which have been accumulated but not yet submitted.", diff --git a/types/pb/dymint/state.pb.go b/types/pb/dymint/state.pb.go index c73e18c79..512664f00 100644 --- a/types/pb/dymint/state.pb.go +++ b/types/pb/dymint/state.pb.go @@ -7,7 +7,6 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" _ "github.com/tendermint/tendermint/abci/types" state "github.com/tendermint/tendermint/proto/tendermint/state" types "github.com/tendermint/tendermint/proto/tendermint/types" @@ -15,14 +14,12 @@ import ( io "io" math "math" math_bits "math/bits" - time "time" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf -var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -36,7 +33,6 @@ type State struct { InitialHeight int64 `protobuf:"varint,3,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"` LastBlockHeight int64 `protobuf:"varint,4,opt,name=last_block_height,json=lastBlockHeight,proto3" json:"last_block_height,omitempty"` LastBlockID types.BlockID `protobuf:"bytes,5,opt,name=last_block_id,json=lastBlockId,proto3" json:"last_block_id"` - LastBlockTime time.Time `protobuf:"bytes,6,opt,name=last_block_time,json=lastBlockTime,proto3,stdtime" json:"last_block_time"` Validators *types.ValidatorSet `protobuf:"bytes,9,opt,name=validators,proto3" json:"validators,omitempty"` // Deprecated: Do not use. LastHeightValidatorsChanged int64 `protobuf:"varint,11,opt,name=last_height_validators_changed,json=lastHeightValidatorsChanged,proto3" json:"last_height_validators_changed,omitempty"` ConsensusParams types.ConsensusParams `protobuf:"bytes,12,opt,name=consensus_params,json=consensusParams,proto3" json:"consensus_params"` @@ -118,13 +114,6 @@ func (m *State) GetLastBlockID() types.BlockID { return types.BlockID{} } -func (m *State) GetLastBlockTime() time.Time { - if m != nil { - return m.LastBlockTime - } - return time.Time{} -} - // Deprecated: Do not use. func (m *State) GetValidators() *types.ValidatorSet { if m != nil { @@ -259,52 +248,50 @@ func init() { func init() { proto.RegisterFile("types/dymint/state.proto", fileDescriptor_4b679420add07272) } var fileDescriptor_4b679420add07272 = []byte{ - // 712 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x94, 0xcf, 0x4e, 0xdb, 0x4a, - 0x14, 0xc6, 0xe3, 0x60, 0x88, 0x33, 0x21, 0x89, 0x99, 0x80, 0x64, 0xb8, 0x92, 0x13, 0xb8, 0xba, - 0x57, 0xd1, 0x95, 0xae, 0x23, 0xc1, 0x03, 0xb4, 0x32, 0x2c, 0x48, 0xc4, 0xa2, 0x72, 0x2a, 0x16, - 0xdd, 0x58, 0x13, 0x7b, 0x6a, 0x8f, 0xea, 0x78, 0xdc, 0x99, 0x09, 0x2a, 0x7d, 0x0a, 0x1e, 0xa1, - 0x8f, 0xc3, 0x92, 0x65, 0x57, 0xb4, 0x0a, 0x2f, 0x52, 0xcd, 0x8c, 0x1d, 0x12, 0x45, 0xac, 0x12, - 0x7f, 0xe7, 0xe7, 0x6f, 0xce, 0x9f, 0x39, 0x06, 0x8e, 0xb8, 0x2f, 0x30, 0x1f, 0xc5, 0xf7, 0x73, - 0x92, 0x8b, 0x11, 0x17, 0x48, 0x60, 0xaf, 0x60, 0x54, 0x50, 0xb8, 0xa7, 0xb5, 0x93, 0xc3, 0x84, - 0x26, 0x54, 0x49, 0x23, 0xf9, 0x4f, 0x47, 0x4f, 0xfa, 0x09, 0xa5, 0x49, 0x86, 0x47, 0xea, 0x69, - 0xb6, 0xf8, 0x3c, 0x12, 0x64, 0x8e, 0xb9, 0x40, 0xf3, 0xa2, 0x04, 0x4e, 0xb5, 0xb1, 0xc0, 0x79, - 0x8c, 0x99, 0x32, 0x47, 0xb3, 0x88, 0x8c, 0x94, 0x5a, 0x22, 0x67, 0x5b, 0x48, 0x29, 0xac, 0x31, - 0xff, 0xbe, 0xc1, 0xdc, 0xa1, 0x8c, 0xc4, 0x48, 0x50, 0x56, 0x72, 0x7f, 0xbf, 0xc1, 0x15, 0x88, - 0xa1, 0xf9, 0xdb, 0x07, 0xaa, 0x82, 0x37, 0x0e, 0x3c, 0xde, 0x68, 0x88, 0xfe, 0xd1, 0xa1, 0xb3, - 0x1f, 0x0d, 0xb0, 0x3b, 0x95, 0x2f, 0xc0, 0x0b, 0xd0, 0xb8, 0xc3, 0x8c, 0x13, 0x9a, 0x3b, 0xc6, - 0xc0, 0x18, 0xb6, 0xce, 0x8f, 0xbd, 0x57, 0x53, 0x4f, 0x77, 0xf1, 0x56, 0x03, 0x41, 0x45, 0xc2, - 0x63, 0x60, 0x45, 0x29, 0x22, 0x79, 0x48, 0x62, 0xa7, 0x3e, 0x30, 0x86, 0xcd, 0xa0, 0xa1, 0x9e, - 0xc7, 0x31, 0xfc, 0x07, 0x74, 0x48, 0x4e, 0x04, 0x41, 0x59, 0x98, 0x62, 0x92, 0xa4, 0xc2, 0xd9, - 0x19, 0x18, 0xc3, 0x9d, 0xa0, 0x5d, 0xaa, 0xd7, 0x4a, 0x84, 0xff, 0x81, 0x83, 0x0c, 0x71, 0x11, - 0xce, 0x32, 0x1a, 0x7d, 0xa9, 0x48, 0x53, 0x91, 0x5d, 0x19, 0xf0, 0xa5, 0x5e, 0xb2, 0x01, 0x68, - 0xaf, 0xb1, 0x24, 0x76, 0x76, 0xb7, 0x13, 0xd5, 0x75, 0xab, 0xb7, 0xc6, 0x57, 0x7e, 0xef, 0xf1, - 0xb9, 0x5f, 0x5b, 0x3e, 0xf7, 0x5b, 0x37, 0x95, 0xd5, 0xf8, 0x2a, 0x68, 0xad, 0x7c, 0xc7, 0x31, - 0xbc, 0x01, 0xdd, 0x35, 0x4f, 0x39, 0x71, 0x67, 0x4f, 0xb9, 0x9e, 0x78, 0xfa, 0x3a, 0x78, 0xd5, - 0x75, 0xf0, 0x3e, 0x56, 0xd7, 0xc1, 0xb7, 0xa4, 0xed, 0xc3, 0xaf, 0xbe, 0x11, 0xb4, 0x57, 0x5e, - 0x32, 0x0a, 0x7d, 0x00, 0x56, 0x53, 0xe4, 0x4e, 0x53, 0x19, 0xb9, 0xdb, 0xe9, 0xdd, 0x56, 0xcc, - 0x14, 0x0b, 0xbf, 0xee, 0x18, 0xc1, 0xda, 0x5b, 0xf0, 0x12, 0xb8, 0x2a, 0x23, 0xdd, 0x8b, 0xf0, - 0x35, 0x12, 0x46, 0x29, 0xca, 0x13, 0x1c, 0x3b, 0x2d, 0xd5, 0x9e, 0xbf, 0x24, 0xa5, 0x3b, 0xb3, - 0xf2, 0xe3, 0x97, 0x1a, 0x81, 0x01, 0xb0, 0x23, 0x9a, 0x73, 0x9c, 0xf3, 0x05, 0x0f, 0xf5, 0x85, - 0x71, 0xf6, 0x55, 0x3a, 0xa7, 0xdb, 0xe9, 0x5c, 0x56, 0xe4, 0x07, 0x05, 0xfa, 0xa6, 0x2c, 0x2f, - 0xe8, 0x46, 0x9b, 0xf2, 0x6a, 0x54, 0x0c, 0xf3, 0x45, 0x26, 0x78, 0x98, 0x22, 0x9e, 0x3a, 0x9d, - 0x81, 0x31, 0xdc, 0xd7, 0xa3, 0x0a, 0xb4, 0x7e, 0x8d, 0x78, 0x2a, 0x2f, 0x06, 0x2a, 0x0a, 0x8d, - 0x74, 0x15, 0xd2, 0x40, 0x45, 0xa1, 0x42, 0xef, 0x4a, 0x1b, 0x2e, 0x28, 0xc3, 0xd5, 0xc4, 0xed, - 0x81, 0x31, 0x34, 0xfd, 0xde, 0xf2, 0xb9, 0xdf, 0x95, 0xa3, 0x9a, 0xca, 0x98, 0xae, 0x4d, 0x7b, - 0xaf, 0x09, 0xd0, 0x07, 0x1d, 0x46, 0xb3, 0x4c, 0xfa, 0x97, 0x95, 0x41, 0x55, 0xd9, 0x91, 0x57, - 0x5e, 0xed, 0x40, 0x47, 0x37, 0xaa, 0x69, 0xb3, 0x75, 0x11, 0x0e, 0x81, 0x5d, 0x36, 0x19, 0xc5, - 0x98, 0xe9, 0x3c, 0x7b, 0x2a, 0xcf, 0x8e, 0x6e, 0xab, 0x94, 0x55, 0xba, 0xff, 0x03, 0xab, 0x60, - 0xb4, 0xa0, 0x1c, 0x33, 0xe7, 0x50, 0x9d, 0x73, 0x50, 0x9d, 0x33, 0xc5, 0x5f, 0x17, 0x38, 0x8f, - 0x30, 0x0b, 0x56, 0x08, 0x3c, 0x07, 0x47, 0x0c, 0xdf, 0x11, 0xb9, 0x1d, 0x21, 0x17, 0x88, 0x55, - 0x73, 0x74, 0x8e, 0xd4, 0xd0, 0x7a, 0x55, 0x70, 0x2a, 0x63, 0xba, 0xa0, 0x89, 0x69, 0x35, 0x6c, - 0x6b, 0x62, 0x5a, 0x96, 0xdd, 0x9c, 0x98, 0x16, 0xb0, 0x5b, 0x13, 0xd3, 0x6a, 0xdb, 0x9d, 0x89, - 0x69, 0x1d, 0xd8, 0xf0, 0xec, 0x3d, 0x68, 0x6f, 0x14, 0x04, 0x3b, 0xa0, 0x1e, 0x23, 0xb5, 0xa4, - 0xcd, 0xa0, 0x1e, 0x23, 0xd8, 0x07, 0xad, 0x98, 0xf1, 0xb0, 0xda, 0x5e, 0xb9, 0x87, 0xed, 0x00, - 0xc4, 0x8c, 0x97, 0xeb, 0xea, 0x5f, 0x3f, 0x2e, 0x5d, 0xe3, 0x69, 0xe9, 0x1a, 0xbf, 0x97, 0xae, - 0xf1, 0xf0, 0xe2, 0xd6, 0x9e, 0x5e, 0xdc, 0xda, 0xcf, 0x17, 0xb7, 0xf6, 0xc9, 0x4b, 0x88, 0x48, - 0x17, 0x33, 0x2f, 0xa2, 0x73, 0xf9, 0x5d, 0xc0, 0xb9, 0xe4, 0xbf, 0xdd, 0x7f, 0xaf, 0xbe, 0x15, - 0xe5, 0x07, 0x67, 0x56, 0x3e, 0xcf, 0xf6, 0xd4, 0x32, 0x5c, 0xfc, 0x09, 0x00, 0x00, 0xff, 0xff, - 0x62, 0x29, 0x77, 0x07, 0x63, 0x05, 0x00, 0x00, + // 678 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x94, 0xcf, 0x6e, 0xda, 0x4c, + 0x14, 0xc5, 0x31, 0x71, 0xc0, 0x0c, 0x01, 0x9c, 0x21, 0x91, 0x9c, 0x7c, 0x92, 0x21, 0xf9, 0xd4, + 0x0a, 0x55, 0x2a, 0x48, 0xc9, 0x03, 0xb4, 0x72, 0xb2, 0x08, 0xa8, 0x8b, 0xca, 0x48, 0x59, 0x74, + 0x63, 0x0d, 0xf6, 0x14, 0x8f, 0x6a, 0x3c, 0xee, 0xcc, 0x10, 0x35, 0x7d, 0x8a, 0x3e, 0x56, 0x96, + 0x59, 0x66, 0x15, 0x55, 0xe4, 0x45, 0xaa, 0xf9, 0x63, 0x02, 0x42, 0x59, 0x25, 0x3e, 0xf7, 0xe7, + 0x33, 0xf7, 0xdc, 0xf1, 0x05, 0x78, 0xe2, 0xbe, 0xc0, 0x7c, 0x94, 0xdc, 0x2f, 0x48, 0x2e, 0x46, + 0x5c, 0x20, 0x81, 0x87, 0x05, 0xa3, 0x82, 0xc2, 0x9a, 0xd6, 0x4e, 0x8f, 0xe6, 0x74, 0x4e, 0x95, + 0x34, 0x92, 0xff, 0xe9, 0xea, 0x69, 0x6f, 0x4e, 0xe9, 0x3c, 0xc3, 0x23, 0xf5, 0x34, 0x5b, 0x7e, + 0x1f, 0x09, 0xb2, 0xc0, 0x5c, 0xa0, 0x45, 0x61, 0x80, 0x33, 0x6d, 0x2c, 0x70, 0x9e, 0x60, 0xa6, + 0xcc, 0xd1, 0x2c, 0x26, 0x23, 0xa5, 0x1a, 0xe4, 0x7c, 0x07, 0x31, 0xc2, 0x06, 0xf3, 0xfe, 0x0d, + 0xe6, 0x0e, 0x65, 0x24, 0x41, 0x82, 0x32, 0xc3, 0xfd, 0xff, 0x06, 0x57, 0x20, 0x86, 0x16, 0x6f, + 0x1f, 0xa8, 0x02, 0x6f, 0x1d, 0x78, 0xb2, 0x35, 0x10, 0xfd, 0x47, 0x97, 0xce, 0x9f, 0x6a, 0x60, + 0x7f, 0x2a, 0x5f, 0x80, 0x97, 0xa0, 0x7e, 0x87, 0x19, 0x27, 0x34, 0xf7, 0xac, 0xbe, 0x35, 0x68, + 0x5e, 0x9c, 0x0c, 0x5f, 0x4d, 0x87, 0x7a, 0x8a, 0xb7, 0x1a, 0x08, 0x4b, 0x12, 0x9e, 0x00, 0x27, + 0x4e, 0x11, 0xc9, 0x23, 0x92, 0x78, 0xd5, 0xbe, 0x35, 0x68, 0x84, 0x75, 0xf5, 0x3c, 0x4e, 0xe0, + 0x3b, 0xd0, 0x26, 0x39, 0x11, 0x04, 0x65, 0x51, 0x8a, 0xc9, 0x3c, 0x15, 0xde, 0x5e, 0xdf, 0x1a, + 0xec, 0x85, 0x2d, 0xa3, 0xde, 0x28, 0x11, 0x7e, 0x00, 0x87, 0x19, 0xe2, 0x22, 0x9a, 0x65, 0x34, + 0xfe, 0x51, 0x92, 0xb6, 0x22, 0x3b, 0xb2, 0x10, 0x48, 0xdd, 0xb0, 0x21, 0x68, 0x6d, 0xb0, 0x24, + 0xf1, 0xf6, 0x77, 0x1b, 0xd5, 0xb9, 0xd5, 0x5b, 0xe3, 0xeb, 0xa0, 0xfb, 0xf0, 0xdc, 0xab, 0xac, + 0x9e, 0x7b, 0xcd, 0x2f, 0xa5, 0xd5, 0xf8, 0x3a, 0x6c, 0xae, 0x7d, 0xc7, 0x09, 0x0c, 0x00, 0x58, + 0xcf, 0x9d, 0x7b, 0x0d, 0x65, 0xe8, 0xef, 0x1a, 0xde, 0x96, 0xcc, 0x14, 0x8b, 0xa0, 0xea, 0x59, + 0xe1, 0xc6, 0x5b, 0xf0, 0x0a, 0xf8, 0xaa, 0x2f, 0xdd, 0x7d, 0xf4, 0x5a, 0x89, 0xe2, 0x14, 0xe5, + 0x73, 0x9c, 0x78, 0x4d, 0x15, 0xe8, 0x3f, 0x49, 0xe9, 0x2c, 0x6b, 0x3f, 0x7e, 0xa5, 0x11, 0x18, + 0x02, 0x37, 0xa6, 0x39, 0xc7, 0x39, 0x5f, 0xf2, 0x48, 0x5f, 0xb1, 0x77, 0xa0, 0xda, 0x39, 0xdb, + 0x6d, 0xe7, 0xaa, 0x24, 0xbf, 0x2a, 0x30, 0xb0, 0x65, 0xce, 0xb0, 0x13, 0x6f, 0xcb, 0xeb, 0xe1, + 0x32, 0xcc, 0x97, 0x99, 0xe0, 0x51, 0x8a, 0x78, 0xea, 0xb5, 0xfb, 0xd6, 0xe0, 0x40, 0x0f, 0x37, + 0xd4, 0xfa, 0x0d, 0xe2, 0xa9, 0xbc, 0x4a, 0x54, 0x14, 0x1a, 0xe9, 0x28, 0xa4, 0x8e, 0x8a, 0x42, + 0x95, 0x3e, 0x19, 0x1b, 0x2e, 0x28, 0xc3, 0xe5, 0x1d, 0xb9, 0x7d, 0x6b, 0x60, 0x07, 0xdd, 0xd5, + 0x73, 0xaf, 0x23, 0x87, 0x3b, 0x95, 0x35, 0x9d, 0x4d, 0x7b, 0x6f, 0x08, 0x30, 0x00, 0x6d, 0x46, + 0xb3, 0x4c, 0xfa, 0x9b, 0x64, 0x50, 0x25, 0x3b, 0x1e, 0x9a, 0x8f, 0x31, 0xd4, 0xd5, 0xad, 0x34, + 0x2d, 0xb6, 0x29, 0xc2, 0x01, 0x70, 0xcd, 0x90, 0x51, 0x82, 0x99, 0xee, 0xb3, 0xab, 0xfa, 0x6c, + 0xeb, 0xb1, 0x4a, 0x59, 0xb5, 0xfb, 0x11, 0x38, 0x05, 0xa3, 0x05, 0xe5, 0x98, 0x79, 0x47, 0xea, + 0x9c, 0xc3, 0xf2, 0x9c, 0x29, 0xfe, 0xb9, 0xc4, 0x79, 0x8c, 0x59, 0xb8, 0x46, 0xe0, 0x05, 0x38, + 0x66, 0xf8, 0x8e, 0xc8, 0xef, 0x39, 0xe2, 0x02, 0xb1, 0xf2, 0x1e, 0xbd, 0x63, 0x75, 0x69, 0xdd, + 0xb2, 0x38, 0x95, 0x35, 0x1d, 0x68, 0x62, 0x3b, 0x35, 0xb7, 0x3e, 0xb1, 0x9d, 0xba, 0xeb, 0x4c, + 0x6c, 0xc7, 0x71, 0x1b, 0x13, 0xdb, 0x01, 0x6e, 0x73, 0x62, 0x3b, 0x2d, 0xb7, 0x3d, 0xb1, 0x9d, + 0x43, 0x17, 0x9e, 0x7f, 0x06, 0xad, 0xad, 0x58, 0xb0, 0x0d, 0xaa, 0x09, 0x52, 0xcb, 0xd5, 0x08, + 0xab, 0x09, 0x82, 0x3d, 0xd0, 0x4c, 0x18, 0x8f, 0xca, 0xad, 0x93, 0xfb, 0xd3, 0x0a, 0x41, 0xc2, + 0xb8, 0x59, 0xb3, 0xe0, 0xe6, 0x61, 0xe5, 0x5b, 0x8f, 0x2b, 0xdf, 0xfa, 0xbb, 0xf2, 0xad, 0x3f, + 0x2f, 0x7e, 0xe5, 0xf1, 0xc5, 0xaf, 0x3c, 0xbd, 0xf8, 0x95, 0x6f, 0xc3, 0x39, 0x11, 0xe9, 0x72, + 0x36, 0x8c, 0xe9, 0x42, 0xee, 0x33, 0xce, 0x25, 0xff, 0xeb, 0xfe, 0x77, 0xb9, 0xe3, 0xe6, 0x87, + 0x62, 0x66, 0x9e, 0x67, 0x35, 0xb5, 0xed, 0x97, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x19, 0x4c, + 0x51, 0xe0, 0x1b, 0x05, 0x00, 0x00, } func (m *State) Marshal() (dAtA []byte, err error) { @@ -417,14 +404,6 @@ func (m *State) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x4a } - n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastBlockTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastBlockTime):]) - if err5 != nil { - return 0, err5 - } - i -= n5 - i = encodeVarintState(dAtA, i, uint64(n5)) - i-- - dAtA[i] = 0x32 { size, err := m.LastBlockID.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -535,8 +514,6 @@ func (m *State) Size() (n int) { } l = m.LastBlockID.Size() n += 1 + l + sovState(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.LastBlockTime) - n += 1 + l + sovState(uint64(l)) if m.Validators != nil { l = m.Validators.Size() n += 1 + l + sovState(uint64(l)) @@ -763,39 +740,6 @@ func (m *State) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastBlockTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthState - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.LastBlockTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 9: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Validators", wireType)