From 5df277cacaf27088863f69ab656ae968f1a53089 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 8 Apr 2022 13:19:28 +0000
Subject: [PATCH 01/13] build(deps): Bump github.com/lib/pq from 1.10.4 to
1.10.5 (#8283)
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.4 to 1.10.5.
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
---
go.mod | 4 ++--
go.sum | 3 ++-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index 49db1ba5e..b25b8ef39 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
github.com/gorilla/websocket v1.5.0
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
- github.com/lib/pq v1.10.4
+ github.com/lib/pq v1.10.5
github.com/libp2p/go-buffer-pool v0.0.2
github.com/mroth/weightedrand v0.4.1
github.com/oasisprotocol/curve25519-voi v0.0.0-20210609091139-0a56a4bca00b
@@ -39,6 +39,7 @@ require (
require (
github.com/creachadair/atomicfile v0.2.4
+ github.com/creachadair/taskgroup v0.3.2
github.com/golangci/golangci-lint v1.45.2
github.com/google/go-cmp v0.5.7
github.com/vektra/mockery/v2 v2.10.4
@@ -72,7 +73,6 @@ require (
github.com/charithe/durationcheck v0.0.9 // indirect
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect
github.com/containerd/continuity v0.2.1 // indirect
- github.com/creachadair/taskgroup v0.3.2 // indirect
github.com/daixiang0/gci v0.3.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.4.3 // indirect
diff --git a/go.sum b/go.sum
index c0388b7af..4fc7fab1e 100644
--- a/go.sum
+++ b/go.sum
@@ -658,8 +658,9 @@ github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJ
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
From 90b951af7210a0275f79b3075e420c9a3f465a75 Mon Sep 17 00:00:00 2001
From: Sam Kleinman
Date: Fri, 8 Apr 2022 11:00:58 -0400
Subject: [PATCH 02/13] node+statesync: normalize initialization (#8275)
---
internal/statesync/reactor.go | 54 ++++++++++++------
internal/statesync/reactor_test.go | 5 +-
node/node.go | 88 +++++++++++-------------------
3 files changed, 74 insertions(+), 73 deletions(-)
diff --git a/internal/statesync/reactor.go b/internal/statesync/reactor.go
index 5ca1d0798..ea2cac4f4 100644
--- a/internal/statesync/reactor.go
+++ b/internal/statesync/reactor.go
@@ -143,6 +143,12 @@ type Reactor struct {
peerEvents p2p.PeerEventSubscriber
chCreator p2p.ChannelCreator
sendBlockError func(context.Context, p2p.PeerError) error
+ postSyncHook func(context.Context, sm.State) error
+
+ // when true, the reactor will, during startup perform a
+ // statesync for this node, and otherwise just provide
+ // snapshots to other nodes.
+ needsStateSync bool
// Dispatcher is used to multiplex light block requests and responses over multiple
// peers used by the p2p state provider and in reverse sync.
@@ -171,7 +177,6 @@ type Reactor struct {
// and querying, references to p2p Channels and a channel to listen for peer
// updates on. Note, the reactor will close all p2p Channels when stopping.
func NewReactor(
- ctx context.Context,
chainID string,
initialHeight int64,
cfg config.StateSyncConfig,
@@ -184,23 +189,26 @@ func NewReactor(
tempDir string,
ssMetrics *Metrics,
eventBus *eventbus.EventBus,
+ postSyncHook func(context.Context, sm.State) error,
+ needsStateSync bool,
) *Reactor {
-
r := &Reactor{
- logger: logger,
- chainID: chainID,
- initialHeight: initialHeight,
- cfg: cfg,
- conn: conn,
- chCreator: channelCreator,
- peerEvents: peerEvents,
- tempDir: tempDir,
- stateStore: stateStore,
- blockStore: blockStore,
- peers: newPeerList(),
- providers: make(map[types.NodeID]*BlockProvider),
- metrics: ssMetrics,
- eventBus: eventBus,
+ logger: logger,
+ chainID: chainID,
+ initialHeight: initialHeight,
+ cfg: cfg,
+ conn: conn,
+ chCreator: channelCreator,
+ peerEvents: peerEvents,
+ tempDir: tempDir,
+ stateStore: stateStore,
+ blockStore: blockStore,
+ peers: newPeerList(),
+ providers: make(map[types.NodeID]*BlockProvider),
+ metrics: ssMetrics,
+ eventBus: eventBus,
+ postSyncHook: postSyncHook,
+ needsStateSync: needsStateSync,
}
r.BaseService = *service.NewBaseService(logger, "StateSync", r)
@@ -300,6 +308,14 @@ func (r *Reactor) OnStart(ctx context.Context) error {
go r.processChannels(ctx, snapshotCh, chunkCh, blockCh, paramsCh)
go r.processPeerUpdates(ctx, r.peerEvents(ctx))
+ if r.needsStateSync {
+ r.logger.Info("starting state sync")
+ if _, err := r.Sync(ctx); err != nil {
+ r.logger.Error("state sync failed; shutting down this node", "err", err)
+ return err
+ }
+ }
+
return nil
}
@@ -379,6 +395,12 @@ func (r *Reactor) Sync(ctx context.Context) (sm.State, error) {
}
}
+ if r.postSyncHook != nil {
+ if err := r.postSyncHook(ctx, state); err != nil {
+ return sm.State{}, err
+ }
+ }
+
return state, nil
}
diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go
index cef0735f2..86c84a9ed 100644
--- a/internal/statesync/reactor_test.go
+++ b/internal/statesync/reactor_test.go
@@ -155,7 +155,6 @@ func setup(
logger := log.NewNopLogger()
rts.reactor = NewReactor(
- ctx,
factory.DefaultTestChainID,
1,
*cfg,
@@ -167,7 +166,9 @@ func setup(
rts.blockStore,
"",
m,
- nil, // eventbus can be nil
+ nil, // eventbus can be nil
+ nil, // post-sync-hook
+ false, // run Sync during Start()
)
rts.syncer = &syncer{
diff --git a/node/node.go b/node/node.go
index 37b66c697..8a4da29f2 100644
--- a/node/node.go
+++ b/node/node.go
@@ -60,19 +60,17 @@ type nodeImpl struct {
nodeKey types.NodeKey // our node privkey
// services
- eventSinks []indexer.EventSink
- initialState sm.State
- stateStore sm.Store
- blockStore *store.BlockStore // store the blockchain to disk
- evPool *evidence.Pool
- stateSync bool // whether the node should state sync on startup
- stateSyncReactor *statesync.Reactor // for hosting and restoring state sync snapshots
- indexerService *indexer.Service
- services []service.Service
- rpcListeners []net.Listener // rpc servers
- shutdownOps closer
- rpcEnv *rpccore.Environment
- prometheusSrv *http.Server
+ eventSinks []indexer.EventSink
+ initialState sm.State
+ stateStore sm.Store
+ blockStore *store.BlockStore // store the blockchain to disk
+ evPool *evidence.Pool
+ indexerService *indexer.Service
+ services []service.Service
+ rpcListeners []net.Listener // rpc servers
+ shutdownOps closer
+ rpcEnv *rpccore.Environment
+ prometheusSrv *http.Server
}
// newDefaultNode returns a Tendermint node with default settings for the
@@ -331,13 +329,15 @@ func makeNode(
nodeMetrics.consensus.BlockSyncing.Set(1)
}
+ if cfg.P2P.PexReactor {
+ node.services = append(node.services, pex.NewReactor(logger, peerManager, node.router.OpenChannel, peerManager.Subscribe))
+ }
+
// Set up state sync reactor, and schedule a sync if requested.
// FIXME The way we do phased startups (e.g. replay -> block sync -> consensus) is very messy,
// we should clean this whole thing up. See:
// https://github.com/tendermint/tendermint/issues/4644
- node.stateSync = stateSync
- node.stateSyncReactor = statesync.NewReactor(
- ctx,
+ node.services = append(node.services, statesync.NewReactor(
genDoc.ChainID,
genDoc.InitialHeight,
*cfg.StateSync,
@@ -350,11 +350,24 @@ func makeNode(
cfg.StateSync.TempDir,
nodeMetrics.statesync,
eventBus,
- )
+ // the post-sync operation
+ func(ctx context.Context, state sm.State) error {
+ csReactor.SetStateSyncingMetrics(0)
- if cfg.P2P.PexReactor {
- node.services = append(node.services, pex.NewReactor(logger, peerManager, node.router.OpenChannel, peerManager.Subscribe))
- }
+ // TODO: Some form of orchestrator is needed here between the state
+ // advancing reactors to be able to control which one of the three
+ // is running
+ // FIXME Very ugly to have these metrics bleed through here.
+ csReactor.SetBlockSyncingMetrics(1)
+ if err := bcReactor.SwitchToBlockSync(ctx, state); err != nil {
+ logger.Error("failed to switch to block sync", "err", err)
+ return err
+ }
+
+ return nil
+ },
+ stateSync,
+ ))
if cfg.Mode == config.ModeValidator {
node.rpcEnv.PubKey = pubKey
@@ -481,40 +494,6 @@ func (n *nodeImpl) OnStart(ctx context.Context) error {
}
}
- if err := n.stateSyncReactor.Start(ctx); err != nil {
- return err
- }
-
- // Run state sync
- // TODO: We shouldn't run state sync if we already have state that has a
- // LastBlockHeight that is not InitialHeight
- if n.stateSync {
- // RUN STATE SYNC NOW:
- //
- // TODO: Eventually this should run as part of some
- // separate orchestrator
- n.logger.Info("starting state sync")
- ssState, err := n.stateSyncReactor.Sync(ctx)
- if err != nil {
- n.logger.Error("state sync failed; shutting down this node", "err", err)
- // stop the node
- n.Stop()
- return err
- }
-
- n.rpcEnv.ConsensusReactor.SetStateSyncingMetrics(0)
-
- // TODO: Some form of orchestrator is needed here between the state
- // advancing reactors to be able to control which one of the three
- // is running
- // FIXME Very ugly to have these metrics bleed through here.
- n.rpcEnv.ConsensusReactor.SetBlockSyncingMetrics(1)
- if err := n.rpcEnv.BlockSyncReactor.SwitchToBlockSync(ctx, ssState); err != nil {
- n.logger.Error("failed to switch to block sync", "err", err)
- return err
- }
- }
-
return nil
}
@@ -531,7 +510,6 @@ func (n *nodeImpl) OnStop() {
reactor.Wait()
}
- n.stateSyncReactor.Wait()
n.router.Wait()
n.rpcEnv.IsListening = false
From 3e3a9348180b9e3a8a48d887e3e5864624ed347b Mon Sep 17 00:00:00 2001
From: Sam Kleinman
Date: Fri, 8 Apr 2022 14:04:43 -0400
Subject: [PATCH 03/13] rpc: add more nil checks in the status end point
(#8287)
---
internal/rpc/core/status.go | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/internal/rpc/core/status.go b/internal/rpc/core/status.go
index 46b8a6fcd..870c13424 100644
--- a/internal/rpc/core/status.go
+++ b/internal/rpc/core/status.go
@@ -77,14 +77,25 @@ func (env *Environment) Status(ctx context.Context) (*coretypes.ResultStatus, er
EarliestAppHash: earliestAppHash,
EarliestBlockHeight: earliestBlockHeight,
EarliestBlockTime: time.Unix(0, earliestBlockTimeNano),
- MaxPeerBlockHeight: env.BlockSyncReactor.GetMaxPeerBlockHeight(),
- CatchingUp: env.ConsensusReactor.WaitSync(),
- TotalSyncedTime: env.BlockSyncReactor.GetTotalSyncedTime(),
- RemainingTime: env.BlockSyncReactor.GetRemainingSyncTime(),
+ // this should start as true, if consensus
+ // hasn't started yet, and then flip to false
+ // (or true,) depending on what's actually
+ // happening.
+ CatchingUp: true,
},
ValidatorInfo: validatorInfo,
}
+ if env.ConsensusReactor != nil {
+ result.SyncInfo.CatchingUp = env.ConsensusReactor.WaitSync()
+ }
+
+ if env.BlockSyncReactor != nil {
+ result.SyncInfo.MaxPeerBlockHeight = env.BlockSyncReactor.GetMaxPeerBlockHeight()
+ result.SyncInfo.TotalSyncedTime = env.BlockSyncReactor.GetTotalSyncedTime()
+ result.SyncInfo.RemainingTime = env.BlockSyncReactor.GetRemainingSyncTime()
+ }
+
if env.StateSyncMetricer != nil {
result.SyncInfo.TotalSnapshots = env.StateSyncMetricer.TotalSnapshots()
result.SyncInfo.ChunkProcessAvgTime = env.StateSyncMetricer.ChunkProcessAvgTime()
@@ -103,6 +114,9 @@ func (env *Environment) validatorAtHeight(h int64) *types.Validator {
if err != nil {
return nil
}
+ if env.ConsensusState == nil {
+ return nil
+ }
if env.PubKey == nil {
return nil
}
From 631ef7aae00bafedd64f41f0c24c71a3d0dcb0cc Mon Sep 17 00:00:00 2001
From: Sam Kleinman
Date: Fri, 8 Apr 2022 17:13:10 -0400
Subject: [PATCH 04/13] consensus: add nil check to gossip routine (#8288)
---
internal/consensus/reactor.go | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go
index c73f998d8..3020e6e16 100644
--- a/internal/consensus/reactor.go
+++ b/internal/consensus/reactor.go
@@ -836,10 +836,20 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState, stateCh
return
}
- rs := r.getRoundState()
- prs := ps.GetRoundState()
- // TODO create more reliable coppies of these
+ // TODO create more reliable copies of these
// structures so the following go routines don't race
+ rs := r.getRoundState()
+ if rs.Votes == nil {
+ // if we have gotten here, we've connected to
+ // a peer before the state of the reactor has
+ // updated to the current round, so we should
+ // sleep for a while before we attempt to
+ // start gossiping the data that doesn't exist
+ // yet. This prevents a panic.
+ timer.Reset(r.state.config.PeerQueryMaj23SleepDuration)
+ continue
+ }
+ prs := ps.GetRoundState()
wg := &sync.WaitGroup{}
From 6ff07a163327e6c4d7269e3a541fcabbbb94ed2b Mon Sep 17 00:00:00 2001
From: William Banfield <4561443+williambanfield@users.noreply.github.com>
Date: Fri, 8 Apr 2022 18:11:20 -0400
Subject: [PATCH 05/13] switch to consensus change startup ordering (#8290)
---
internal/consensus/reactor.go | 49 +++++++++++++++--------------------
1 file changed, 21 insertions(+), 28 deletions(-)
diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go
index 3020e6e16..18589c93a 100644
--- a/internal/consensus/reactor.go
+++ b/internal/consensus/reactor.go
@@ -211,7 +211,6 @@ func (r *Reactor) OnStart(ctx context.Context) error {
go r.peerStatsRoutine(ctx, peerUpdates)
r.subscribeToBroadcastEvents(chBundle.state)
- go r.updateRoundStateRoutine()
if !r.WaitSync() {
if err := r.state.Start(ctx); err != nil {
@@ -219,6 +218,8 @@ func (r *Reactor) OnStart(ctx context.Context) error {
}
}
+ go r.updateRoundStateRoutine(ctx)
+
go r.processStateCh(ctx, chBundle)
go r.processDataCh(ctx, chBundle)
go r.processVoteCh(ctx, chBundle)
@@ -260,6 +261,15 @@ func (r *Reactor) SwitchToConsensus(ctx context.Context, state sm.State, skipWAL
// NOTE: The line below causes broadcastNewRoundStepRoutine() to broadcast a
// NewRoundStepMessage.
r.state.updateToState(ctx, state)
+ if err := r.state.Start(ctx); err != nil {
+ panic(fmt.Sprintf(`failed to start consensus state: %v
+
+conS:
+%+v
+
+conR:
+%+v`, err, r.state, r))
+ }
r.mtx.Lock()
r.waitSync = false
@@ -273,16 +283,6 @@ func (r *Reactor) SwitchToConsensus(ctx context.Context, state sm.State, skipWAL
r.state.doWALCatchup = false
}
- if err := r.state.Start(ctx); err != nil {
- panic(fmt.Sprintf(`failed to start consensus state: %v
-
-conS:
-%+v
-
-conR:
-%+v`, err, r.state, r))
- }
-
d := types.EventDataBlockSyncStatus{Complete: true, Height: state.LastBlockHeight}
if err := r.eventBus.PublishEventBlockSyncStatus(ctx, d); err != nil {
r.logger.Error("failed to emit the blocksync complete event", "err", err)
@@ -408,17 +408,20 @@ func (r *Reactor) sendNewRoundStepMessage(ctx context.Context, peerID types.Node
})
}
-func (r *Reactor) updateRoundStateRoutine() {
+func (r *Reactor) updateRoundStateRoutine(ctx context.Context) {
t := time.NewTicker(100 * time.Microsecond)
defer t.Stop()
- for range t.C {
- if !r.IsRunning() {
+
+ for {
+ select {
+ case <-ctx.Done():
return
+ case <-t.C:
+ rs := r.state.GetRoundState()
+ r.mtx.Lock()
+ r.rs = rs
+ r.mtx.Unlock()
}
- rs := r.state.GetRoundState()
- r.mtx.Lock()
- r.rs = rs
- r.mtx.Unlock()
}
}
@@ -839,16 +842,6 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState, stateCh
// TODO create more reliable copies of these
// structures so the following go routines don't race
rs := r.getRoundState()
- if rs.Votes == nil {
- // if we have gotten here, we've connected to
- // a peer before the state of the reactor has
- // updated to the current round, so we should
- // sleep for a while before we attempt to
- // start gossiping the data that doesn't exist
- // yet. This prevents a panic.
- timer.Reset(r.state.config.PeerQueryMaj23SleepDuration)
- continue
- }
prs := ps.GetRoundState()
wg := &sync.WaitGroup{}
From e565a4a1f58da80fa7b241e73b05fac91c01300d Mon Sep 17 00:00:00 2001
From: "M. J. Fromberger"
Date: Fri, 8 Apr 2022 17:21:24 -0700
Subject: [PATCH 06/13] Forward-port v0.35.3 changelog to master. (#8291)
---
CHANGELOG.md | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07d049cf2..73fee3289 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,22 @@
Friendly reminder: We have a [bug bounty program](https://hackerone.com/cosmos).
+## v0.35.3
+
+April 8, 2022
+
+### FEATURES
+
+- [cli] [\#8081](https://github.com/tendermint/tendermint/pull/8081) add a safer-to-use `reset-state` command. (@marbar3778)
+
+### IMPROVEMENTS
+
+- [consensus] [\#8138](https://github.com/tendermint/tendermint/pull/8138) change lock handling in reactor and handleMsg for RoundState. (@williambanfield)
+
+### BUG FIXES
+
+- [cli] [\#8276](https://github.com/tendermint/tendermint/pull/8276) scmigrate: ensure target key is correctly renamed. (@creachadair)
+
## v0.35.2
February 28, 2022
From e6550f868605dc4795b4b9fd48ab154b5c04eb16 Mon Sep 17 00:00:00 2001
From: "M. J. Fromberger"
Date: Fri, 8 Apr 2022 18:02:49 -0700
Subject: [PATCH 07/13] Fix release notes to match the prevailing style.
(#8292)
---
.github/workflows/release.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d3a6a8a71..862ef598a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -27,11 +27,13 @@ jobs:
version: latest
args: build --skip-validate # skip validate skips initial sanity checks in order to be able to fully run
+ - run: echo https://github.com/tendermint/tendermint/blob/${GITHUB_REF#refs/tags/}/CHANGELOG.md#${GITHUB_REF#refs/tags/} > ../release_notes.md
+
- name: Release
uses: goreleaser/goreleaser-action@v2
if: startsWith(github.ref, 'refs/tags/')
with:
version: latest
- args: release --rm-dist
+ args: release --rm-dist --release-notes=../release_notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From 26b5672a54222218be4083cdcc65595b1920600d Mon Sep 17 00:00:00 2001
From: "M. J. Fromberger"
Date: Fri, 8 Apr 2022 19:40:03 -0700
Subject: [PATCH 08/13] Add a tool to update old config files to the latest
version (#8281)
---
CHANGELOG_PENDING.md | 1 +
UPGRADING.md | 26 +-
go.mod | 2 +
go.sum | 2 +
scripts/confix/confix.go | 249 +++++++++++
scripts/confix/confix_test.go | 98 +++++
scripts/confix/testdata/non-config.toml | 6 +
scripts/confix/testdata/v31-config.toml | 292 +++++++++++++
scripts/confix/testdata/v32-config.toml | 319 ++++++++++++++
scripts/confix/testdata/v33-config.toml | 335 +++++++++++++++
scripts/confix/testdata/v34-config.toml | 428 +++++++++++++++++++
scripts/confix/testdata/v35-config.toml | 527 ++++++++++++++++++++++++
scripts/confix/testdata/v36-config.toml | 479 +++++++++++++++++++++
13 files changed, 2760 insertions(+), 4 deletions(-)
create mode 100644 scripts/confix/confix.go
create mode 100644 scripts/confix/confix_test.go
create mode 100644 scripts/confix/testdata/non-config.toml
create mode 100644 scripts/confix/testdata/v31-config.toml
create mode 100644 scripts/confix/testdata/v32-config.toml
create mode 100644 scripts/confix/testdata/v33-config.toml
create mode 100644 scripts/confix/testdata/v34-config.toml
create mode 100644 scripts/confix/testdata/v35-config.toml
create mode 100644 scripts/confix/testdata/v36-config.toml
diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md
index f0409a545..0d070d304 100644
--- a/CHANGELOG_PENDING.md
+++ b/CHANGELOG_PENDING.md
@@ -62,6 +62,7 @@ Special thanks to external contributors on this release:
- [consensus] \#7415 Update proposal validation logic to Prevote nil if a proposal does not meet the conditions for Timelyness per the proposer-based timestamp specification. (@anca)
- [consensus] \#7382 Update block validation to no longer require the block timestamp to be the median of the timestamps of the previous commit. (@anca)
- [consensus] \#7711 Use the proposer timestamp for the first height instead of the genesis time. Chains will still start consensus at the genesis time. (@anca)
+- [cli] \#8281 Add a tool to update old config files to the latest version. (@creachadair)
### IMPROVEMENTS
diff --git a/UPGRADING.md b/UPGRADING.md
index 931272cce..199a5f83c 100644
--- a/UPGRADING.md
+++ b/UPGRADING.md
@@ -28,10 +28,28 @@ applications remains correct.
### Config Changes
-The default configuration for a newly-created node now disables indexing for
-ABCI event metadata. Existing node configurations that already have indexing
-turned on are not affected. Operators who wish to enable indexing for a new
-node, however, must now edit the `config.toml` explicitly.
+- We have added a new, experimental tool to help operators migrate
+ configuration files created by previous versions of Tendermint.
+ To try this tool, run:
+
+ ```shell
+ # Install the tool.
+ go install github.com/tendermint/tendermint/scripts/confix@latest
+
+ # Run the tool with the old configuration file as input.
+ # Replace the -config argument with your path.
+ confix -config ~/.tendermint/config/config.toml -out updated.toml
+ ```
+
+ This tool should be able to update configurations from v0.34 and v0.35. We
+ plan to extend it to handle older configuration files in the future. For now,
+ it will report an error (without making any changes) if it does not recognize
+ the version that created the file.
+
+- The default configuration for a newly-created node now disables indexing for
+ ABCI event metadata. Existing node configurations that already have indexing
+ turned on are not affected. Operators who wish to enable indexing for a new
+ node, however, must now edit the `config.toml` explicitly.
### RPC Changes
diff --git a/go.mod b/go.mod
index b25b8ef39..91895c36e 100644
--- a/go.mod
+++ b/go.mod
@@ -73,6 +73,8 @@ require (
github.com/charithe/durationcheck v0.0.9 // indirect
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect
github.com/containerd/continuity v0.2.1 // indirect
+ github.com/creachadair/taskgroup v0.3.2
+ github.com/creachadair/tomledit v0.0.5
github.com/daixiang0/gci v0.3.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.4.3 // indirect
diff --git a/go.sum b/go.sum
index 4fc7fab1e..2351806cf 100644
--- a/go.sum
+++ b/go.sum
@@ -225,6 +225,8 @@ github.com/creachadair/atomicfile v0.2.4 h1:GRjpQLmz/78I4+nBQpGMFrRa9yrL157AUTrA
github.com/creachadair/atomicfile v0.2.4/go.mod h1:BRq8Une6ckFneYXZQ+kO7p1ZZP3I2fzVzf28JxrIkBc=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk=
+github.com/creachadair/tomledit v0.0.5 h1:ILJt2EO93fr8w2UAUA5FPNThk1Pq5m4KX2qUZ1Xz4Xs=
+github.com/creachadair/tomledit v0.0.5/go.mod h1:gvtfnSZLa+YNQD28vaPq0Nk12bRxEhmUdBzAWn+EGF4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
diff --git a/scripts/confix/confix.go b/scripts/confix/confix.go
new file mode 100644
index 000000000..aa73897a5
--- /dev/null
+++ b/scripts/confix/confix.go
@@ -0,0 +1,249 @@
+// Program confix applies fixes to a Tendermint TOML configuration file to
+// update a file created with an older version of Tendermint to a compatible
+// format for a newer version.
+package main
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/creachadair/atomicfile"
+ "github.com/creachadair/tomledit"
+ "github.com/creachadair/tomledit/parser"
+ "github.com/creachadair/tomledit/transform"
+ "github.com/spf13/viper"
+ "github.com/tendermint/tendermint/config"
+)
+
+func init() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, `Usage: %[1]s -config [-out ]
+
+Modify the contents of the specified -config TOML file to update the names,
+locations, and values of configuration settings to the current configuration
+layout. The output is written to -out, or to stdout.
+
+It is valid to set -config and -out to the same path. In that case, the file will
+be modified in-place. In case of any error in updating the file, no output is
+written.
+
+Options:
+`, filepath.Base(os.Args[0]))
+ flag.PrintDefaults()
+ }
+}
+
+var (
+ configPath = flag.String("config", "", "Config file path (required)")
+ outPath = flag.String("out", "", "Output file path (default stdout)")
+)
+
+func main() {
+ flag.Parse()
+ if *configPath == "" {
+ log.Fatal("You must specify a non-empty -config path")
+ }
+
+ doc, err := LoadConfig(*configPath)
+ if err != nil {
+ log.Fatalf("Loading config: %v", err)
+ }
+
+ ctx := transform.WithLogWriter(context.Background(), os.Stderr)
+ if err := ApplyFixes(ctx, doc); err != nil {
+ log.Fatalf("Updating %q: %v", *configPath, err)
+ }
+
+ var buf bytes.Buffer
+ if err := tomledit.Format(&buf, doc); err != nil {
+ log.Fatalf("Formatting config: %v", err)
+ }
+
+ // Verify that Tendermint can parse the results after our edits.
+ if err := CheckValid(buf.Bytes()); err != nil {
+ log.Fatalf("Updated config is invalid: %v", err)
+ }
+
+ if *outPath == "" {
+ os.Stdout.Write(buf.Bytes())
+ } else if err := atomicfile.WriteData(*outPath, buf.Bytes(), 0600); err != nil {
+ log.Fatalf("Writing output: %v", err)
+ }
+}
+
+var plan = transform.Plan{
+ {
+ Desc: "Rename everything from snake_case to kebab-case",
+ T: transform.SnakeToKebab(),
+ },
+ {
+ Desc: "Rename [fastsync] to [blocksync]",
+ T: transform.Rename(parser.Key{"fastsync"}, parser.Key{"blocksync"}),
+ ErrorOK: true,
+ },
+ {
+ Desc: "Move top-level fast_sync key under [blocksync]",
+ T: transform.MoveKey(
+ parser.Key{"fast-sync"},
+ parser.Key{"blocksync"},
+ parser.Key{"fast-sync"},
+ ),
+ ErrorOK: true,
+ },
+ {
+ Desc: "Move priv-validator settings under [priv-validator]",
+ T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
+ const pvPrefix = "priv-validator-"
+
+ var found []*tomledit.Entry
+ doc.Scan(func(key parser.Key, e *tomledit.Entry) bool {
+ if e.IsSection() && !e.IsGlobal() {
+ return false // no more candidates
+ } else if len(key) == 1 && strings.HasPrefix(key[0], pvPrefix) {
+ found = append(found, e)
+ }
+ return true
+ })
+ if len(found) == 0 {
+ return nil // nothing to do
+ }
+
+ // Now that we know we have work to do, find the target table.
+ var sec *tomledit.Section
+ if dst := transform.FindTable(doc, "priv-validator"); dst == nil {
+ // If the table doesn't exist, create it. Old config files
+ // probably will not have it, so plug in the comment too.
+ sec = &tomledit.Section{
+ Heading: &parser.Heading{
+ Block: parser.Comments{
+ "#######################################################",
+ "### Priv Validator Configuration ###",
+ "#######################################################",
+ },
+ Name: parser.Key{"priv-validator"},
+ },
+ }
+ doc.Sections = append(doc.Sections, sec)
+ } else {
+ sec = dst.Section
+ }
+
+ for _, e := range found {
+ e.Remove()
+ e.Name = parser.Key{strings.TrimPrefix(e.Name[0], pvPrefix)}
+ sec.Items = append(sec.Items, e.KeyValue)
+ }
+ return nil
+ }),
+ },
+ {
+ Desc: `Set blocksync.version to "v0"`,
+ T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
+ v := doc.First("blocksync", "version")
+ if v == nil {
+ return nil // nothing to do
+ } else if !v.IsMapping() {
+ // This shouldn't happen, but is easier to debug than a panic.
+ return fmt.Errorf("blocksync.version is weird: %v", v)
+ }
+ v.Value.X = parser.MustValue(`"v0"`).X
+ return nil
+ }),
+ },
+}
+
+// ApplyFixes transforms doc and reports whether it succeeded.
+func ApplyFixes(ctx context.Context, doc *tomledit.Document) error {
+ // Check what version of Tendermint might have created this config file, as
+ // a safety check for the updates we are about to make.
+ tmVersion := GuessConfigVersion(doc)
+ if tmVersion == vUnknown {
+ return errors.New("cannot tell what Tendermint version created this config")
+ } else if tmVersion < v34 {
+ // TODO(creachadair): Add in rewrites for older versions. This will
+ // require some digging to discover what the changes were. The upgrade
+ // instructions do not give specifics.
+ return fmt.Errorf("unable to update version %s config", tmVersion)
+ }
+ return plan.Apply(ctx, doc)
+}
+
+// LoadConfig loads and parses the TOML document from path.
+func LoadConfig(path string) (*tomledit.Document, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return tomledit.Parse(f)
+}
+
+const (
+ vUnknown = ""
+ v32 = "v0.32"
+ v33 = "v0.33"
+ v34 = "v0.34"
+ v35 = "v0.35"
+ v36 = "v0.36"
+)
+
+// GuessConfigVersion attempts to figure out which version of Tendermint
+// created the specified config document. It returns "" if the creating version
+// cannot be determined, otherwise a string of the form "vX.YY".
+func GuessConfigVersion(doc *tomledit.Document) string {
+ hasDisableWS := doc.First("rpc", "experimental-disable-websocket") != nil
+ hasUseLegacy := doc.First("p2p", "use-legacy") != nil // v0.35 only
+ if hasDisableWS && !hasUseLegacy {
+ return v36
+ }
+
+ hasBlockSync := transform.FindTable(doc, "blocksync") != nil // add: v0.35
+ hasStateSync := transform.FindTable(doc, "statesync") != nil // add: v0.34
+ if hasBlockSync && hasStateSync {
+ return v35
+ } else if hasStateSync {
+ return v34
+ }
+
+ hasIndexKeys := doc.First("tx_index", "index_keys") != nil // add: v0.33
+ hasIndexTags := doc.First("tx_index", "index_tags") != nil // rem: v0.33
+ if hasIndexKeys && !hasIndexTags {
+ return v33
+ }
+
+ hasFastSync := transform.FindTable(doc, "fastsync") != nil // add: v0.32
+ if hasIndexTags && hasFastSync {
+ return v32
+ }
+
+ // Something older, probably.
+ return vUnknown
+}
+
+// CheckValid checks whether the specified config appears to be a valid
+// Tendermint config file. This emulates how the node loads the config.
+func CheckValid(data []byte) error {
+ v := viper.New()
+ v.SetConfigType("toml")
+
+ if err := v.ReadConfig(bytes.NewReader(data)); err != nil {
+ return fmt.Errorf("reading config: %w", err)
+ }
+
+ var cfg config.Config
+ if err := v.Unmarshal(&cfg); err != nil {
+ return fmt.Errorf("decoding config: %w", err)
+ }
+
+ // Stub in required value not stored in the config file, so that validation
+ // will not fail spuriously.
+ cfg.Mode = config.ModeValidator
+ return cfg.ValidateBasic()
+}
diff --git a/scripts/confix/confix_test.go b/scripts/confix/confix_test.go
new file mode 100644
index 000000000..b7be1247d
--- /dev/null
+++ b/scripts/confix/confix_test.go
@@ -0,0 +1,98 @@
+package main_test
+
+import (
+ "bytes"
+ "context"
+ "strings"
+ "testing"
+
+ "github.com/creachadair/tomledit"
+ "github.com/google/go-cmp/cmp"
+
+ confix "github.com/tendermint/tendermint/scripts/confix"
+)
+
+func mustParseConfig(t *testing.T, path string) *tomledit.Document {
+ doc, err := confix.LoadConfig(path)
+ if err != nil {
+ t.Fatalf("Loading config: %v", err)
+ }
+ return doc
+}
+
+func TestGuessConfigVersion(t *testing.T) {
+ tests := []struct {
+ path, want string
+ }{
+ {"testdata/non-config.toml", ""},
+ {"testdata/v31-config.toml", ""},
+ {"testdata/v32-config.toml", "v0.32"},
+ {"testdata/v33-config.toml", "v0.33"},
+ {"testdata/v34-config.toml", "v0.34"},
+ {"testdata/v35-config.toml", "v0.35"},
+ {"testdata/v36-config.toml", "v0.36"},
+ }
+ for _, test := range tests {
+ t.Run(test.path, func(t *testing.T) {
+ got := confix.GuessConfigVersion(mustParseConfig(t, test.path))
+ if got != test.want {
+ t.Errorf("Wrong version: got %q, want %q", got, test.want)
+ }
+ })
+ }
+}
+
+func TestApplyFixes(t *testing.T) {
+ ctx := context.Background()
+
+ t.Run("Unknown", func(t *testing.T) {
+ err := confix.ApplyFixes(ctx, mustParseConfig(t, "testdata/v31-config.toml"))
+ if err == nil || !strings.Contains(err.Error(), "cannot tell what Tendermint version") {
+ t.Error("ApplyFixes succeeded, but should have failed for an unknown version")
+ }
+ })
+ t.Run("TooOld", func(t *testing.T) {
+ err := confix.ApplyFixes(ctx, mustParseConfig(t, "testdata/v33-config.toml"))
+ if err == nil || !strings.Contains(err.Error(), "unable to update version v0.33 config") {
+ t.Errorf("ApplyFixes: got %v, want version error", err)
+ }
+ })
+ t.Run("OK", func(t *testing.T) {
+ doc := mustParseConfig(t, "testdata/v34-config.toml")
+ if err := confix.ApplyFixes(ctx, doc); err != nil {
+ t.Fatalf("ApplyFixes: unexpected error: %v", err)
+ }
+
+ t.Run("Fixpoint", func(t *testing.T) {
+ // Verify that reapplying fixes to the same config succeeds, and does not
+ // make any additional changes.
+ var before bytes.Buffer
+ if err := tomledit.Format(&before, doc); err != nil {
+ t.Fatalf("Formatting document: %v", err)
+ }
+ if err := confix.CheckValid(before.Bytes()); err != nil {
+ t.Fatalf("Validating output: %v", err)
+ }
+ want := before.String()
+
+ // Re-parse the output from the first round of transformations.
+ doc2, err := tomledit.Parse(&before)
+ if err != nil {
+ t.Fatalf("Parsing fixed output: %v", err)
+ }
+ if err := confix.ApplyFixes(ctx, doc2); err != nil {
+ t.Fatalf("ApplyFixes: unexpected error: %v", err)
+ }
+
+ var after bytes.Buffer
+ if err := tomledit.Format(&after, doc2); err != nil {
+ t.Fatalf("Formatting document: %v", err)
+ }
+ got := after.String()
+
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Errorf("Reapplied fixes changed something: (-want, +got)\n%s", diff)
+ }
+ })
+ })
+}
diff --git a/scripts/confix/testdata/non-config.toml b/scripts/confix/testdata/non-config.toml
new file mode 100644
index 000000000..abfd48667
--- /dev/null
+++ b/scripts/confix/testdata/non-config.toml
@@ -0,0 +1,6 @@
+# This is not a Tendermint config file.
+
+[ test ]
+key = 'value'
+
+# Nothing to see here, move along.
diff --git a/scripts/confix/testdata/v31-config.toml b/scripts/confix/testdata/v31-config.toml
new file mode 100644
index 000000000..247d2da2e
--- /dev/null
+++ b/scripts/confix/testdata/v31-config.toml
@@ -0,0 +1,292 @@
+# This is a TOML config file.
+# For more information, see https://github.com/toml-lang/toml
+
+##### main base config options #####
+
+# TCP or UNIX socket address of the ABCI application,
+# or the name of an ABCI application compiled in with the Tendermint binary
+proxy_app = "tcp://127.0.0.1:26658"
+
+# A custom human readable name for this node
+moniker = "localhost"
+
+# If this node is many blocks behind the tip of the chain, FastSync
+# allows them to catchup quickly by downloading blocks in parallel
+# and verifying their commits
+fast_sync = true
+
+# Database backend: goleveldb | cleveldb | boltdb
+# * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
+# - pure go
+# - stable
+# * cleveldb (uses levigo wrapper)
+# - fast
+# - requires gcc
+# - use cleveldb build tag (go build -tags cleveldb)
+# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt)
+# - EXPERIMENTAL
+# - may be faster is some use-cases (random reads - indexer)
+# - use boltdb build tag (go build -tags boltdb)
+db_backend = "goleveldb"
+
+# Database directory
+db_dir = "data"
+
+# Output level for logging, including package level options
+log_level = "main:info,state:info,*:error"
+
+# Output format: 'plain' (colored text) or 'json'
+log_format = "plain"
+
+##### additional base config options #####
+
+# Path to the JSON file containing the initial validator set and other meta data
+genesis_file = "config/genesis.json"
+
+# Path to the JSON file containing the private key to use as a validator in the consensus protocol
+priv_validator_key_file = "config/priv_validator_key.json"
+
+# Path to the JSON file containing the last sign state of a validator
+priv_validator_state_file = "data/priv_validator_state.json"
+
+# TCP or UNIX socket address for Tendermint to listen on for
+# connections from an external PrivValidator process
+priv_validator_laddr = ""
+
+# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
+node_key_file = "config/node_key.json"
+
+# Mechanism to connect to the ABCI application: socket | grpc
+abci = "socket"
+
+# TCP or UNIX socket address for the profiling server to listen on
+prof_laddr = ""
+
+# If true, query the ABCI app on connecting to a new peer
+# so the app can decide if we should keep the connection or not
+filter_peers = false
+
+##### advanced configuration options #####
+
+##### rpc server configuration options #####
+[rpc]
+
+# TCP or UNIX socket address for the RPC server to listen on
+laddr = "tcp://0.0.0.0:26657"
+
+# A list of origins a cross-domain request can be executed from
+# Default value '[]' disables cors support
+# Use '["*"]' to allow any origin
+cors_allowed_origins = []
+
+# A list of methods the client is allowed to use with cross-domain requests
+cors_allowed_methods = ["HEAD", "GET", "POST", ]
+
+# A list of non simple headers the client is allowed to use with cross-domain requests
+cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ]
+
+# TCP or UNIX socket address for the gRPC server to listen on
+# NOTE: This server only supports /broadcast_tx_commit
+grpc_laddr = ""
+
+# Maximum number of simultaneous connections.
+# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+grpc_max_open_connections = 900
+
+# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
+unsafe = false
+
+# Maximum number of simultaneous connections (including WebSocket).
+# Does not include gRPC connections. See grpc_max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+max_open_connections = 900
+
+# Maximum number of unique clientIDs that can /subscribe
+# If you're using /broadcast_tx_commit, set to the estimated maximum number
+# of broadcast_tx_commit calls per block.
+max_subscription_clients = 100
+
+# Maximum number of unique queries a given client can /subscribe to
+# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to
+# the estimated # maximum number of broadcast_tx_commit calls per block.
+max_subscriptions_per_client = 5
+
+# How long to wait for a tx to be committed during /broadcast_tx_commit.
+# WARNING: Using a value larger than 10s will result in increasing the
+# global HTTP write timeout, which applies to all connections and endpoints.
+# See https://github.com/tendermint/tendermint/issues/3435
+timeout_broadcast_tx_commit = "10s"
+
+# The name of a file containing certificate that is used to create the HTTPS server.
+# If the certificate is signed by a certificate authority,
+# the certFile should be the concatenation of the server's certificate, any intermediates,
+# and the CA's certificate.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
+tls_cert_file = ""
+
+# The name of a file containing matching private key that is used to create the HTTPS server.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. Otherwise, HTTP server is run.
+tls_key_file = ""
+
+##### peer to peer configuration options #####
+[p2p]
+
+# Address to listen for incoming connections
+laddr = "tcp://0.0.0.0:26656"
+
+# Address to advertise to peers for them to dial
+# If empty, will use the same port as the laddr,
+# and will introspect on the listener or use UPnP
+# to figure out the address.
+external_address = ""
+
+# Comma separated list of seed nodes to connect to
+seeds = ""
+
+# Comma separated list of nodes to keep persistent connections to
+persistent_peers = ""
+
+# UPNP port forwarding
+upnp = false
+
+# Path to address book
+addr_book_file = "config/addrbook.json"
+
+# Set true for strict address routability rules
+# Set false for private or local networks
+addr_book_strict = true
+
+# Maximum number of inbound peers
+max_num_inbound_peers = 40
+
+# Maximum number of outbound peers to connect to, excluding persistent peers
+max_num_outbound_peers = 10
+
+# Time to wait before flushing messages out on the connection
+flush_throttle_timeout = "100ms"
+
+# Maximum size of a message packet payload, in bytes
+max_packet_msg_payload_size = 1024
+
+# Rate at which packets can be sent, in bytes/second
+send_rate = 5120000
+
+# Rate at which packets can be received, in bytes/second
+recv_rate = 5120000
+
+# Set true to enable the peer-exchange reactor
+pex = true
+
+# Seed mode, in which node constantly crawls the network and looks for
+# peers. If another node asks it for addresses, it responds and disconnects.
+#
+# Does not work if the peer-exchange reactor is disabled.
+seed_mode = false
+
+# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
+private_peer_ids = ""
+
+# Toggle to disable guard against peers connecting from the same ip.
+allow_duplicate_ip = false
+
+# Peer connection configuration.
+handshake_timeout = "20s"
+dial_timeout = "3s"
+
+##### mempool configuration options #####
+[mempool]
+
+recheck = true
+broadcast = true
+wal_dir = ""
+
+# Maximum number of transactions in the mempool
+size = 5000
+
+# Limit the total size of all txs in the mempool.
+# This only accounts for raw transactions (e.g. given 1MB transactions and
+# max_txs_bytes=5MB, mempool will only accept 5 transactions).
+max_txs_bytes = 1073741824
+
+# Size of the cache (used to filter transactions we saw earlier) in transactions
+cache_size = 10000
+
+##### consensus configuration options #####
+[consensus]
+
+wal_file = "data/cs.wal/wal"
+
+timeout_propose = "3s"
+timeout_propose_delta = "500ms"
+timeout_prevote = "1s"
+timeout_prevote_delta = "500ms"
+timeout_precommit = "1s"
+timeout_precommit_delta = "500ms"
+timeout_commit = "1s"
+
+# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
+skip_timeout_commit = false
+
+# EmptyBlocks mode and possible interval between empty blocks
+create_empty_blocks = true
+create_empty_blocks_interval = "0s"
+
+# Reactor sleep duration parameters
+peer_gossip_sleep_duration = "100ms"
+peer_query_maj23_sleep_duration = "2s"
+
+##### transactions indexer configuration options #####
+[tx_index]
+
+# What indexer to use for transactions
+#
+# Options:
+# 1) "null"
+# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
+indexer = "kv"
+
+# Comma-separated list of tags to index (by default the only tag is "tx.hash")
+#
+# You can also index transactions by height by adding "tx.height" tag here.
+#
+# It's recommended to index only a subset of tags due to possible memory
+# bloat. This is, of course, depends on the indexer's DB and the volume of
+# transactions.
+index_tags = ""
+
+# When set to true, tells indexer to index all tags (predefined tags:
+# "tx.hash", "tx.height" and all tags from DeliverTx responses).
+#
+# Note this may be not desirable (see the comment above). IndexTags has a
+# precedence over IndexAllTags (i.e. when given both, IndexTags will be
+# indexed).
+index_all_tags = false
+
+##### instrumentation configuration options #####
+[instrumentation]
+
+# When true, Prometheus metrics are served under /metrics on
+# PrometheusListenAddr.
+# Check out the documentation for the list of available metrics.
+prometheus = false
+
+# Address to listen for Prometheus collector(s) connections
+prometheus_listen_addr = ":26660"
+
+# Maximum number of simultaneous connections.
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+max_open_connections = 3
+
+# Instrumentation namespace
+namespace = "tendermint"
diff --git a/scripts/confix/testdata/v32-config.toml b/scripts/confix/testdata/v32-config.toml
new file mode 100644
index 000000000..e0b897525
--- /dev/null
+++ b/scripts/confix/testdata/v32-config.toml
@@ -0,0 +1,319 @@
+# This is a TOML config file.
+# For more information, see https://github.com/toml-lang/toml
+
+# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or
+# relative to the home directory (e.g. "data"). The home directory is
+# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
+# or --home cmd flag.
+
+##### main base config options #####
+
+# TCP or UNIX socket address of the ABCI application,
+# or the name of an ABCI application compiled in with the Tendermint binary
+proxy_app = "tcp://127.0.0.1:26658"
+
+# A custom human readable name for this node
+moniker = "localhost"
+
+# If this node is many blocks behind the tip of the chain, FastSync
+# allows them to catchup quickly by downloading blocks in parallel
+# and verifying their commits
+fast_sync = true
+
+# Database backend: goleveldb | cleveldb | boltdb
+# * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
+# - pure go
+# - stable
+# * cleveldb (uses levigo wrapper)
+# - fast
+# - requires gcc
+# - use cleveldb build tag (go build -tags cleveldb)
+# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt)
+# - EXPERIMENTAL
+# - may be faster is some use-cases (random reads - indexer)
+# - use boltdb build tag (go build -tags boltdb)
+db_backend = "goleveldb"
+
+# Database directory
+db_dir = "data"
+
+# Output level for logging, including package level options
+log_level = "main:info,state:info,*:error"
+
+# Output format: 'plain' (colored text) or 'json'
+log_format = "plain"
+
+##### additional base config options #####
+
+# Path to the JSON file containing the initial validator set and other meta data
+genesis_file = "config/genesis.json"
+
+# Path to the JSON file containing the private key to use as a validator in the consensus protocol
+priv_validator_key_file = "config/priv_validator_key.json"
+
+# Path to the JSON file containing the last sign state of a validator
+priv_validator_state_file = "data/priv_validator_state.json"
+
+# TCP or UNIX socket address for Tendermint to listen on for
+# connections from an external PrivValidator process
+priv_validator_laddr = ""
+
+# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
+node_key_file = "config/node_key.json"
+
+# Mechanism to connect to the ABCI application: socket | grpc
+abci = "socket"
+
+# TCP or UNIX socket address for the profiling server to listen on
+prof_laddr = ""
+
+# If true, query the ABCI app on connecting to a new peer
+# so the app can decide if we should keep the connection or not
+filter_peers = false
+
+##### advanced configuration options #####
+
+##### rpc server configuration options #####
+[rpc]
+
+# TCP or UNIX socket address for the RPC server to listen on
+laddr = "tcp://127.0.0.1:26657"
+
+# A list of origins a cross-domain request can be executed from
+# Default value '[]' disables cors support
+# Use '["*"]' to allow any origin
+cors_allowed_origins = []
+
+# A list of methods the client is allowed to use with cross-domain requests
+cors_allowed_methods = ["HEAD", "GET", "POST", ]
+
+# A list of non simple headers the client is allowed to use with cross-domain requests
+cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ]
+
+# TCP or UNIX socket address for the gRPC server to listen on
+# NOTE: This server only supports /broadcast_tx_commit
+grpc_laddr = ""
+
+# Maximum number of simultaneous connections.
+# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+grpc_max_open_connections = 900
+
+# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
+unsafe = false
+
+# Maximum number of simultaneous connections (including WebSocket).
+# Does not include gRPC connections. See grpc_max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+max_open_connections = 900
+
+# Maximum number of unique clientIDs that can /subscribe
+# If you're using /broadcast_tx_commit, set to the estimated maximum number
+# of broadcast_tx_commit calls per block.
+max_subscription_clients = 100
+
+# Maximum number of unique queries a given client can /subscribe to
+# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to
+# the estimated # maximum number of broadcast_tx_commit calls per block.
+max_subscriptions_per_client = 5
+
+# How long to wait for a tx to be committed during /broadcast_tx_commit.
+# WARNING: Using a value larger than 10s will result in increasing the
+# global HTTP write timeout, which applies to all connections and endpoints.
+# See https://github.com/tendermint/tendermint/issues/3435
+timeout_broadcast_tx_commit = "10s"
+
+# Maximum size of request body, in bytes
+max_body_bytes = 1000000
+
+# Maximum size of request header, in bytes
+max_header_bytes = 1048576
+
+# The path to a file containing certificate that is used to create the HTTPS server.
+# Migth be either absolute path or path related to tendermint's config directory.
+# If the certificate is signed by a certificate authority,
+# the certFile should be the concatenation of the server's certificate, any intermediates,
+# and the CA's certificate.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls_cert_file = ""
+
+# The path to a file containing matching private key that is used to create the HTTPS server.
+# Migth be either absolute path or path related to tendermint's config directory.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls_key_file = ""
+
+##### peer to peer configuration options #####
+[p2p]
+
+# Address to listen for incoming connections
+laddr = "tcp://0.0.0.0:26656"
+
+# Address to advertise to peers for them to dial
+# If empty, will use the same port as the laddr,
+# and will introspect on the listener or use UPnP
+# to figure out the address.
+external_address = ""
+
+# Comma separated list of seed nodes to connect to
+seeds = ""
+
+# Comma separated list of nodes to keep persistent connections to
+persistent_peers = ""
+
+# UPNP port forwarding
+upnp = false
+
+# Path to address book
+addr_book_file = "config/addrbook.json"
+
+# Set true for strict address routability rules
+# Set false for private or local networks
+addr_book_strict = true
+
+# Maximum number of inbound peers
+max_num_inbound_peers = 40
+
+# Maximum number of outbound peers to connect to, excluding persistent peers
+max_num_outbound_peers = 10
+
+# Time to wait before flushing messages out on the connection
+flush_throttle_timeout = "100ms"
+
+# Maximum size of a message packet payload, in bytes
+max_packet_msg_payload_size = 1024
+
+# Rate at which packets can be sent, in bytes/second
+send_rate = 5120000
+
+# Rate at which packets can be received, in bytes/second
+recv_rate = 5120000
+
+# Set true to enable the peer-exchange reactor
+pex = true
+
+# Seed mode, in which node constantly crawls the network and looks for
+# peers. If another node asks it for addresses, it responds and disconnects.
+#
+# Does not work if the peer-exchange reactor is disabled.
+seed_mode = false
+
+# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
+private_peer_ids = ""
+
+# Toggle to disable guard against peers connecting from the same ip.
+allow_duplicate_ip = false
+
+# Peer connection configuration.
+handshake_timeout = "20s"
+dial_timeout = "3s"
+
+##### mempool configuration options #####
+[mempool]
+
+recheck = true
+broadcast = true
+wal_dir = ""
+
+# Maximum number of transactions in the mempool
+size = 5000
+
+# Limit the total size of all txs in the mempool.
+# This only accounts for raw transactions (e.g. given 1MB transactions and
+# max_txs_bytes=5MB, mempool will only accept 5 transactions).
+max_txs_bytes = 1073741824
+
+# Size of the cache (used to filter transactions we saw earlier) in transactions
+cache_size = 10000
+
+# Maximum size of a single transaction.
+# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes} + {amino overhead}.
+max_tx_bytes = 1048576
+
+##### fast sync configuration options #####
+[fastsync]
+
+# Fast Sync version to use:
+# 1) "v0" (default) - the legacy fast sync implementation
+# 2) "v1" - refactor of v0 version for better testability
+version = "v0"
+
+##### consensus configuration options #####
+[consensus]
+
+wal_file = "data/cs.wal/wal"
+
+timeout_propose = "3s"
+timeout_propose_delta = "500ms"
+timeout_prevote = "1s"
+timeout_prevote_delta = "500ms"
+timeout_precommit = "1s"
+timeout_precommit_delta = "500ms"
+timeout_commit = "1s"
+
+# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
+skip_timeout_commit = false
+
+# EmptyBlocks mode and possible interval between empty blocks
+create_empty_blocks = true
+create_empty_blocks_interval = "0s"
+
+# Reactor sleep duration parameters
+peer_gossip_sleep_duration = "100ms"
+peer_query_maj23_sleep_duration = "2s"
+
+##### transactions indexer configuration options #####
+[tx_index]
+
+# What indexer to use for transactions
+#
+# Options:
+# 1) "null"
+# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
+indexer = "kv"
+
+# Comma-separated list of tags to index (by default the only tag is "tx.hash")
+#
+# You can also index transactions by height by adding "tx.height" tag here.
+#
+# It's recommended to index only a subset of tags due to possible memory
+# bloat. This is, of course, depends on the indexer's DB and the volume of
+# transactions.
+index_tags = ""
+
+# When set to true, tells indexer to index all tags (predefined tags:
+# "tx.hash", "tx.height" and all tags from DeliverTx responses).
+#
+# Note this may be not desirable (see the comment above). IndexTags has a
+# precedence over IndexAllTags (i.e. when given both, IndexTags will be
+# indexed).
+index_all_tags = false
+
+##### instrumentation configuration options #####
+[instrumentation]
+
+# When true, Prometheus metrics are served under /metrics on
+# PrometheusListenAddr.
+# Check out the documentation for the list of available metrics.
+prometheus = false
+
+# Address to listen for Prometheus collector(s) connections
+prometheus_listen_addr = ":26660"
+
+# Maximum number of simultaneous connections.
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+max_open_connections = 3
+
+# Instrumentation namespace
+namespace = "tendermint"
diff --git a/scripts/confix/testdata/v33-config.toml b/scripts/confix/testdata/v33-config.toml
new file mode 100644
index 000000000..b728f08a1
--- /dev/null
+++ b/scripts/confix/testdata/v33-config.toml
@@ -0,0 +1,335 @@
+# This is a TOML config file.
+# For more information, see https://github.com/toml-lang/toml
+
+# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or
+# relative to the home directory (e.g. "data"). The home directory is
+# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
+# or --home cmd flag.
+
+##### main base config options #####
+
+# TCP or UNIX socket address of the ABCI application,
+# or the name of an ABCI application compiled in with the Tendermint binary
+proxy_app = "tcp://127.0.0.1:26658"
+
+# A custom human readable name for this node
+moniker = "localhost"
+
+# If this node is many blocks behind the tip of the chain, FastSync
+# allows them to catchup quickly by downloading blocks in parallel
+# and verifying their commits
+fast_sync = true
+
+# Database backend: goleveldb | cleveldb | boltdb | rocksdb
+# * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
+# - pure go
+# - stable
+# * cleveldb (uses levigo wrapper)
+# - fast
+# - requires gcc
+# - use cleveldb build tag (go build -tags cleveldb)
+# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt)
+# - EXPERIMENTAL
+# - may be faster is some use-cases (random reads - indexer)
+# - use boltdb build tag (go build -tags boltdb)
+# * rocksdb (uses github.com/tecbot/gorocksdb)
+# - EXPERIMENTAL
+# - requires gcc
+# - use rocksdb build tag (go build -tags rocksdb)
+db_backend = "goleveldb"
+
+# Database directory
+db_dir = "data"
+
+# Output level for logging, including package level options
+log_level = "main:info,state:info,*:error"
+
+# Output format: 'plain' (colored text) or 'json'
+log_format = "plain"
+
+##### additional base config options #####
+
+# Path to the JSON file containing the initial validator set and other meta data
+genesis_file = "config/genesis.json"
+
+# Path to the JSON file containing the private key to use as a validator in the consensus protocol
+priv_validator_key_file = "config/priv_validator_key.json"
+
+# Path to the JSON file containing the last sign state of a validator
+priv_validator_state_file = "data/priv_validator_state.json"
+
+# TCP or UNIX socket address for Tendermint to listen on for
+# connections from an external PrivValidator process
+priv_validator_laddr = ""
+
+# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
+node_key_file = "config/node_key.json"
+
+# Mechanism to connect to the ABCI application: socket | grpc
+abci = "socket"
+
+# TCP or UNIX socket address for the profiling server to listen on
+prof_laddr = ""
+
+# If true, query the ABCI app on connecting to a new peer
+# so the app can decide if we should keep the connection or not
+filter_peers = false
+
+##### advanced configuration options #####
+
+##### rpc server configuration options #####
+[rpc]
+
+# TCP or UNIX socket address for the RPC server to listen on
+laddr = "tcp://127.0.0.1:26657"
+
+# A list of origins a cross-domain request can be executed from
+# Default value '[]' disables cors support
+# Use '["*"]' to allow any origin
+cors_allowed_origins = []
+
+# A list of methods the client is allowed to use with cross-domain requests
+cors_allowed_methods = ["HEAD", "GET", "POST", ]
+
+# A list of non simple headers the client is allowed to use with cross-domain requests
+cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ]
+
+# TCP or UNIX socket address for the gRPC server to listen on
+# NOTE: This server only supports /broadcast_tx_commit
+grpc_laddr = ""
+
+# Maximum number of simultaneous connections.
+# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+grpc_max_open_connections = 900
+
+# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
+unsafe = false
+
+# Maximum number of simultaneous connections (including WebSocket).
+# Does not include gRPC connections. See grpc_max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+max_open_connections = 900
+
+# Maximum number of unique clientIDs that can /subscribe
+# If you're using /broadcast_tx_commit, set to the estimated maximum number
+# of broadcast_tx_commit calls per block.
+max_subscription_clients = 100
+
+# Maximum number of unique queries a given client can /subscribe to
+# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to
+# the estimated # maximum number of broadcast_tx_commit calls per block.
+max_subscriptions_per_client = 5
+
+# How long to wait for a tx to be committed during /broadcast_tx_commit.
+# WARNING: Using a value larger than 10s will result in increasing the
+# global HTTP write timeout, which applies to all connections and endpoints.
+# See https://github.com/tendermint/tendermint/issues/3435
+timeout_broadcast_tx_commit = "10s"
+
+# Maximum size of request body, in bytes
+max_body_bytes = 1000000
+
+# Maximum size of request header, in bytes
+max_header_bytes = 1048576
+
+# The path to a file containing certificate that is used to create the HTTPS server.
+# Migth be either absolute path or path related to tendermint's config directory.
+# If the certificate is signed by a certificate authority,
+# the certFile should be the concatenation of the server's certificate, any intermediates,
+# and the CA's certificate.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls_cert_file = ""
+
+# The path to a file containing matching private key that is used to create the HTTPS server.
+# Migth be either absolute path or path related to tendermint's config directory.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls_key_file = ""
+
+##### peer to peer configuration options #####
+[p2p]
+
+# Address to listen for incoming connections
+laddr = "tcp://0.0.0.0:26656"
+
+# Address to advertise to peers for them to dial
+# If empty, will use the same port as the laddr,
+# and will introspect on the listener or use UPnP
+# to figure out the address.
+external_address = ""
+
+# Comma separated list of seed nodes to connect to
+seeds = ""
+
+# Comma separated list of nodes to keep persistent connections to
+persistent_peers = ""
+
+# UPNP port forwarding
+upnp = false
+
+# Path to address book
+addr_book_file = "config/addrbook.json"
+
+# Set true for strict address routability rules
+# Set false for private or local networks
+addr_book_strict = true
+
+# Maximum number of inbound peers
+max_num_inbound_peers = 40
+
+# Maximum number of outbound peers to connect to, excluding persistent peers
+max_num_outbound_peers = 10
+
+# List of node IDs, to which a connection will be (re)established ignoring any existing limits
+unconditional_peer_ids = ""
+
+# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used)
+persistent_peers_max_dial_period = "0s"
+
+# Time to wait before flushing messages out on the connection
+flush_throttle_timeout = "100ms"
+
+# Maximum size of a message packet payload, in bytes
+max_packet_msg_payload_size = 1024
+
+# Rate at which packets can be sent, in bytes/second
+send_rate = 5120000
+
+# Rate at which packets can be received, in bytes/second
+recv_rate = 5120000
+
+# Set true to enable the peer-exchange reactor
+pex = true
+
+# Seed mode, in which node constantly crawls the network and looks for
+# peers. If another node asks it for addresses, it responds and disconnects.
+#
+# Does not work if the peer-exchange reactor is disabled.
+seed_mode = false
+
+# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
+private_peer_ids = ""
+
+# Toggle to disable guard against peers connecting from the same ip.
+allow_duplicate_ip = false
+
+# Peer connection configuration.
+handshake_timeout = "20s"
+dial_timeout = "3s"
+
+##### mempool configuration options #####
+[mempool]
+
+recheck = true
+broadcast = true
+wal_dir = ""
+
+# Maximum number of transactions in the mempool
+size = 5000
+
+# Limit the total size of all txs in the mempool.
+# This only accounts for raw transactions (e.g. given 1MB transactions and
+# max_txs_bytes=5MB, mempool will only accept 5 transactions).
+max_txs_bytes = 1073741824
+
+# Size of the cache (used to filter transactions we saw earlier) in transactions
+cache_size = 10000
+
+# Maximum size of a single transaction.
+# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes} + {amino overhead}.
+max_tx_bytes = 1048576
+
+##### fast sync configuration options #####
+[fastsync]
+
+# Fast Sync version to use:
+# 1) "v0" (default) - the legacy fast sync implementation
+# 2) "v1" - refactor of v0 version for better testability
+# 3) "v2" - refactor of v1 version for better usability
+version = "v0"
+
+##### consensus configuration options #####
+[consensus]
+
+wal_file = "data/cs.wal/wal"
+
+timeout_propose = "3s"
+timeout_propose_delta = "500ms"
+timeout_prevote = "1s"
+timeout_prevote_delta = "500ms"
+timeout_precommit = "1s"
+timeout_precommit_delta = "500ms"
+timeout_commit = "1s"
+
+# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
+skip_timeout_commit = false
+
+# EmptyBlocks mode and possible interval between empty blocks
+create_empty_blocks = true
+create_empty_blocks_interval = "0s"
+
+# Reactor sleep duration parameters
+peer_gossip_sleep_duration = "100ms"
+peer_query_maj23_sleep_duration = "2s"
+
+##### transactions indexer configuration options #####
+[tx_index]
+
+# What indexer to use for transactions
+#
+# Options:
+# 1) "null"
+# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
+indexer = "kv"
+
+# Comma-separated list of compositeKeys to index (by default the only key is "tx.hash")
+# Remember that Event has the following structure: type.key
+# type: [
+# key: value,
+# ...
+# ]
+#
+# You can also index transactions by height by adding "tx.height" key here.
+#
+# It's recommended to index only a subset of keys due to possible memory
+# bloat. This is, of course, depends on the indexer's DB and the volume of
+# transactions.
+index_keys = ""
+
+# When set to true, tells indexer to index all compositeKeys (predefined keys:
+# "tx.hash", "tx.height" and all keys from DeliverTx responses).
+#
+# Note this may be not desirable (see the comment above). IndexKeys has a
+# precedence over IndexAllKeys (i.e. when given both, IndexKeys will be
+# indexed).
+index_all_keys = false
+
+##### instrumentation configuration options #####
+[instrumentation]
+
+# When true, Prometheus metrics are served under /metrics on
+# PrometheusListenAddr.
+# Check out the documentation for the list of available metrics.
+prometheus = false
+
+# Address to listen for Prometheus collector(s) connections
+prometheus_listen_addr = ":26660"
+
+# Maximum number of simultaneous connections.
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+max_open_connections = 3
+
+# Instrumentation namespace
+namespace = "tendermint"
diff --git a/scripts/confix/testdata/v34-config.toml b/scripts/confix/testdata/v34-config.toml
new file mode 100644
index 000000000..0ef8b25eb
--- /dev/null
+++ b/scripts/confix/testdata/v34-config.toml
@@ -0,0 +1,428 @@
+# This is a TOML config file.
+# For more information, see https://github.com/toml-lang/toml
+
+# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or
+# relative to the home directory (e.g. "data"). The home directory is
+# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
+# or --home cmd flag.
+
+#######################################################################
+### Main Base Config Options ###
+#######################################################################
+
+# TCP or UNIX socket address of the ABCI application,
+# or the name of an ABCI application compiled in with the Tendermint binary
+proxy_app = "tcp://127.0.0.1:26658"
+
+# A custom human readable name for this node
+moniker = "localhost"
+
+# If this node is many blocks behind the tip of the chain, FastSync
+# allows them to catchup quickly by downloading blocks in parallel
+# and verifying their commits
+fast_sync = true
+
+# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb
+# * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
+# - pure go
+# - stable
+# * cleveldb (uses levigo wrapper)
+# - fast
+# - requires gcc
+# - use cleveldb build tag (go build -tags cleveldb)
+# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt)
+# - EXPERIMENTAL
+# - may be faster is some use-cases (random reads - indexer)
+# - use boltdb build tag (go build -tags boltdb)
+# * rocksdb (uses github.com/tecbot/gorocksdb)
+# - EXPERIMENTAL
+# - requires gcc
+# - use rocksdb build tag (go build -tags rocksdb)
+# * badgerdb (uses github.com/dgraph-io/badger)
+# - EXPERIMENTAL
+# - use badgerdb build tag (go build -tags badgerdb)
+db_backend = "goleveldb"
+
+# Database directory
+db_dir = "data"
+
+# Output level for logging, including package level options
+log_level = "info"
+
+# Output format: 'plain' (colored text) or 'json'
+log_format = "plain"
+
+##### additional base config options #####
+
+# Path to the JSON file containing the initial validator set and other meta data
+genesis_file = "config/genesis.json"
+
+# Path to the JSON file containing the private key to use as a validator in the consensus protocol
+priv_validator_key_file = "config/priv_validator_key.json"
+
+# Path to the JSON file containing the last sign state of a validator
+priv_validator_state_file = "data/priv_validator_state.json"
+
+# TCP or UNIX socket address for Tendermint to listen on for
+# connections from an external PrivValidator process
+priv_validator_laddr = ""
+
+# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
+node_key_file = "config/node_key.json"
+
+# Mechanism to connect to the ABCI application: socket | grpc
+abci = "socket"
+
+# If true, query the ABCI app on connecting to a new peer
+# so the app can decide if we should keep the connection or not
+filter_peers = false
+
+
+#######################################################################
+### Advanced Configuration Options ###
+#######################################################################
+
+#######################################################
+### RPC Server Configuration Options ###
+#######################################################
+[rpc]
+
+# TCP or UNIX socket address for the RPC server to listen on
+laddr = "tcp://127.0.0.1:26657"
+
+# A list of origins a cross-domain request can be executed from
+# Default value '[]' disables cors support
+# Use '["*"]' to allow any origin
+cors_allowed_origins = []
+
+# A list of methods the client is allowed to use with cross-domain requests
+cors_allowed_methods = ["HEAD", "GET", "POST", ]
+
+# A list of non simple headers the client is allowed to use with cross-domain requests
+cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ]
+
+# TCP or UNIX socket address for the gRPC server to listen on
+# NOTE: This server only supports /broadcast_tx_commit
+grpc_laddr = ""
+
+# Maximum number of simultaneous connections.
+# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+grpc_max_open_connections = 900
+
+# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
+unsafe = false
+
+# Maximum number of simultaneous connections (including WebSocket).
+# Does not include gRPC connections. See grpc_max_open_connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+max_open_connections = 900
+
+# Maximum number of unique clientIDs that can /subscribe
+# If you're using /broadcast_tx_commit, set to the estimated maximum number
+# of broadcast_tx_commit calls per block.
+max_subscription_clients = 100
+
+# Maximum number of unique queries a given client can /subscribe to
+# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to
+# the estimated # maximum number of broadcast_tx_commit calls per block.
+max_subscriptions_per_client = 5
+
+# Experimental parameter to specify the maximum number of events a node will
+# buffer, per subscription, before returning an error and closing the
+# subscription. Must be set to at least 100, but higher values will accommodate
+# higher event throughput rates (and will use more memory).
+experimental_subscription_buffer_size = 200
+
+# Experimental parameter to specify the maximum number of RPC responses that
+# can be buffered per WebSocket client. If clients cannot read from the
+# WebSocket endpoint fast enough, they will be disconnected, so increasing this
+# parameter may reduce the chances of them being disconnected (but will cause
+# the node to use more memory).
+#
+# Must be at least the same as "experimental_subscription_buffer_size",
+# otherwise connections could be dropped unnecessarily. This value should
+# ideally be somewhat higher than "experimental_subscription_buffer_size" to
+# accommodate non-subscription-related RPC responses.
+experimental_websocket_write_buffer_size = 200
+
+# If a WebSocket client cannot read fast enough, at present we may
+# silently drop events instead of generating an error or disconnecting the
+# client.
+#
+# Enabling this experimental parameter will cause the WebSocket connection to
+# be closed instead if it cannot read fast enough, allowing for greater
+# predictability in subscription behaviour.
+experimental_close_on_slow_client = false
+
+# How long to wait for a tx to be committed during /broadcast_tx_commit.
+# WARNING: Using a value larger than 10s will result in increasing the
+# global HTTP write timeout, which applies to all connections and endpoints.
+# See https://github.com/tendermint/tendermint/issues/3435
+timeout_broadcast_tx_commit = "10s"
+
+# Maximum size of request body, in bytes
+max_body_bytes = 1000000
+
+# Maximum size of request header, in bytes
+max_header_bytes = 1048576
+
+# The path to a file containing certificate that is used to create the HTTPS server.
+# Might be either absolute path or path related to Tendermint's config directory.
+# If the certificate is signed by a certificate authority,
+# the certFile should be the concatenation of the server's certificate, any intermediates,
+# and the CA's certificate.
+# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls_cert_file = ""
+
+# The path to a file containing matching private key that is used to create the HTTPS server.
+# Might be either absolute path or path related to Tendermint's config directory.
+# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls_key_file = ""
+
+# pprof listen address (https://golang.org/pkg/net/http/pprof)
+pprof_laddr = ""
+
+#######################################################
+### P2P Configuration Options ###
+#######################################################
+[p2p]
+
+# Address to listen for incoming connections
+laddr = "tcp://0.0.0.0:26656"
+
+# Address to advertise to peers for them to dial
+# If empty, will use the same port as the laddr,
+# and will introspect on the listener or use UPnP
+# to figure out the address. ip and port are required
+# example: 159.89.10.97:26656
+external_address = ""
+
+# Comma separated list of seed nodes to connect to
+seeds = ""
+
+# Comma separated list of nodes to keep persistent connections to
+persistent_peers = ""
+
+# UPNP port forwarding
+upnp = false
+
+# Path to address book
+addr_book_file = "config/addrbook.json"
+
+# Set true for strict address routability rules
+# Set false for private or local networks
+addr_book_strict = true
+
+# Maximum number of inbound peers
+max_num_inbound_peers = 40
+
+# Maximum number of outbound peers to connect to, excluding persistent peers
+max_num_outbound_peers = 10
+
+# List of node IDs, to which a connection will be (re)established ignoring any existing limits
+unconditional_peer_ids = ""
+
+# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used)
+persistent_peers_max_dial_period = "0s"
+
+# Time to wait before flushing messages out on the connection
+flush_throttle_timeout = "100ms"
+
+# Maximum size of a message packet payload, in bytes
+max_packet_msg_payload_size = 1024
+
+# Rate at which packets can be sent, in bytes/second
+send_rate = 5120000
+
+# Rate at which packets can be received, in bytes/second
+recv_rate = 5120000
+
+# Set true to enable the peer-exchange reactor
+pex = true
+
+# Seed mode, in which node constantly crawls the network and looks for
+# peers. If another node asks it for addresses, it responds and disconnects.
+#
+# Does not work if the peer-exchange reactor is disabled.
+seed_mode = false
+
+# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
+private_peer_ids = ""
+
+# Toggle to disable guard against peers connecting from the same ip.
+allow_duplicate_ip = false
+
+# Peer connection configuration.
+handshake_timeout = "20s"
+dial_timeout = "3s"
+
+#######################################################
+### Mempool Configuration Option ###
+#######################################################
+[mempool]
+
+recheck = true
+broadcast = true
+wal_dir = ""
+
+# Maximum number of transactions in the mempool
+size = 5000
+
+# Limit the total size of all txs in the mempool.
+# This only accounts for raw transactions (e.g. given 1MB transactions and
+# max_txs_bytes=5MB, mempool will only accept 5 transactions).
+max_txs_bytes = 1073741824
+
+# Size of the cache (used to filter transactions we saw earlier) in transactions
+cache_size = 10000
+
+# Do not remove invalid transactions from the cache (default: false)
+# Set to true if it's not possible for any invalid transaction to become valid
+# again in the future.
+keep-invalid-txs-in-cache = false
+
+# Maximum size of a single transaction.
+# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}.
+max_tx_bytes = 1048576
+
+# Maximum size of a batch of transactions to send to a peer
+# Including space needed by encoding (one varint per transaction).
+# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796
+max_batch_bytes = 0
+
+#######################################################
+### State Sync Configuration Options ###
+#######################################################
+[statesync]
+# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine
+# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in
+# the network to take and serve state machine snapshots. State sync is not attempted if the node
+# has any local state (LastBlockHeight > 0). The node will have a truncated block history,
+# starting from the height of the snapshot.
+enable = false
+
+# RPC servers (comma-separated) for light client verification of the synced state machine and
+# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding
+# header hash obtained from a trusted source, and a period during which validators can be trusted.
+#
+# For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2
+# weeks) during which they can be financially punished (slashed) for misbehavior.
+rpc_servers = ""
+trust_height = 0
+trust_hash = ""
+trust_period = "168h0m0s"
+
+# Time to spend discovering snapshots before initiating a restore.
+discovery_time = "15s"
+
+# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp).
+# Will create a new, randomly named directory within, and remove it when done.
+temp_dir = ""
+
+# The timeout duration before re-requesting a chunk, possibly from a different
+# peer (default: 1 minute).
+chunk_request_timeout = "10s"
+
+# The number of concurrent chunk fetchers to run (default: 1).
+chunk_fetchers = "4"
+
+#######################################################
+### Fast Sync Configuration Connections ###
+#######################################################
+[fastsync]
+
+# Fast Sync version to use:
+# 1) "v0" (default) - the legacy fast sync implementation
+# 2) "v1" - refactor of v0 version for better testability
+# 2) "v2" - complete redesign of v0, optimized for testability & readability
+version = "v0"
+
+#######################################################
+### Consensus Configuration Options ###
+#######################################################
+[consensus]
+
+wal_file = "data/cs.wal/wal"
+
+# How long we wait for a proposal block before prevoting nil
+timeout_propose = "3s"
+# How much timeout_propose increases with each round
+timeout_propose_delta = "500ms"
+# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil)
+timeout_prevote = "1s"
+# How much the timeout_prevote increases with each round
+timeout_prevote_delta = "500ms"
+# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil)
+timeout_precommit = "1s"
+# How much the timeout_precommit increases with each round
+timeout_precommit_delta = "500ms"
+# How long we wait after committing a block, before starting on the new
+# height (this gives us a chance to receive some more precommits, even
+# though we already have +2/3).
+timeout_commit = "1s"
+
+# How many blocks to look back to check existence of the node's consensus votes before joining consensus
+# When non-zero, the node will panic upon restart
+# if the same consensus key was used to sign {double_sign_check_height} last blocks.
+# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic.
+double_sign_check_height = 0
+
+# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
+skip_timeout_commit = false
+
+# EmptyBlocks mode and possible interval between empty blocks
+create_empty_blocks = true
+create_empty_blocks_interval = "0s"
+
+# Reactor sleep duration parameters
+peer_gossip_sleep_duration = "100ms"
+peer_query_maj23_sleep_duration = "2s"
+
+#######################################################
+### Transaction Indexer Configuration Options ###
+#######################################################
+[tx_index]
+
+# What indexer to use for transactions
+#
+# The application will set which txs to index. In some cases a node operator will be able
+# to decide which txs to index based on configuration set in the application.
+#
+# Options:
+# 1) "null"
+# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
+# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed.
+indexer = "kv"
+
+#######################################################
+### Instrumentation Configuration Options ###
+#######################################################
+[instrumentation]
+
+# When true, Prometheus metrics are served under /metrics on
+# PrometheusListenAddr.
+# Check out the documentation for the list of available metrics.
+prometheus = false
+
+# Address to listen for Prometheus collector(s) connections
+prometheus_listen_addr = ":26660"
+
+# Maximum number of simultaneous connections.
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+max_open_connections = 3
+
+# Instrumentation namespace
+namespace = "tendermint"
diff --git a/scripts/confix/testdata/v35-config.toml b/scripts/confix/testdata/v35-config.toml
new file mode 100644
index 000000000..79616d6cd
--- /dev/null
+++ b/scripts/confix/testdata/v35-config.toml
@@ -0,0 +1,527 @@
+# This is a TOML config file.
+# For more information, see https://github.com/toml-lang/toml
+
+# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or
+# relative to the home directory (e.g. "data"). The home directory is
+# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
+# or --home cmd flag.
+
+#######################################################################
+### Main Base Config Options ###
+#######################################################################
+
+# TCP or UNIX socket address of the ABCI application,
+# or the name of an ABCI application compiled in with the Tendermint binary
+proxy-app = "tcp://127.0.0.1:26658"
+
+# A custom human readable name for this node
+moniker = "localhost"
+
+# Mode of Node: full | validator | seed
+# * validator node
+# - all reactors
+# - with priv_validator_key.json, priv_validator_state.json
+# * full node
+# - all reactors
+# - No priv_validator_key.json, priv_validator_state.json
+# * seed node
+# - only P2P, PEX Reactor
+# - No priv_validator_key.json, priv_validator_state.json
+mode = "validator"
+
+# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb
+# * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
+# - pure go
+# - stable
+# * cleveldb (uses levigo wrapper)
+# - fast
+# - requires gcc
+# - use cleveldb build tag (go build -tags cleveldb)
+# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt)
+# - EXPERIMENTAL
+# - may be faster is some use-cases (random reads - indexer)
+# - use boltdb build tag (go build -tags boltdb)
+# * rocksdb (uses github.com/tecbot/gorocksdb)
+# - EXPERIMENTAL
+# - requires gcc
+# - use rocksdb build tag (go build -tags rocksdb)
+# * badgerdb (uses github.com/dgraph-io/badger)
+# - EXPERIMENTAL
+# - use badgerdb build tag (go build -tags badgerdb)
+db-backend = "goleveldb"
+
+# Database directory
+db-dir = "data"
+
+# Output level for logging, including package level options
+log-level = "info"
+
+# Output format: 'plain' (colored text) or 'json'
+log-format = "plain"
+
+##### additional base config options #####
+
+# Path to the JSON file containing the initial validator set and other meta data
+genesis-file = "config/genesis.json"
+
+# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
+node-key-file = "config/node_key.json"
+
+# Mechanism to connect to the ABCI application: socket | grpc
+abci = "socket"
+
+# If true, query the ABCI app on connecting to a new peer
+# so the app can decide if we should keep the connection or not
+filter-peers = false
+
+
+#######################################################
+### Priv Validator Configuration ###
+#######################################################
+[priv-validator]
+
+# Path to the JSON file containing the private key to use as a validator in the consensus protocol
+key-file = "config/priv_validator_key.json"
+
+# Path to the JSON file containing the last sign state of a validator
+state-file = "data/priv_validator_state.json"
+
+# TCP or UNIX socket address for Tendermint to listen on for
+# connections from an external PrivValidator process
+# when the listenAddr is prefixed with grpc instead of tcp it will use the gRPC Client
+laddr = ""
+
+# Path to the client certificate generated while creating needed files for secure connection.
+# If a remote validator address is provided but no certificate, the connection will be insecure
+client-certificate-file = ""
+
+# Client key generated while creating certificates for secure connection
+client-key-file = ""
+
+# Path to the Root Certificate Authority used to sign both client and server certificates
+root-ca-file = ""
+
+
+#######################################################################
+### Advanced Configuration Options ###
+#######################################################################
+
+#######################################################
+### RPC Server Configuration Options ###
+#######################################################
+[rpc]
+
+# TCP or UNIX socket address for the RPC server to listen on
+laddr = "tcp://127.0.0.1:26657"
+
+# A list of origins a cross-domain request can be executed from
+# Default value '[]' disables cors support
+# Use '["*"]' to allow any origin
+cors-allowed-origins = []
+
+# A list of methods the client is allowed to use with cross-domain requests
+cors-allowed-methods = ["HEAD", "GET", "POST", ]
+
+# A list of non simple headers the client is allowed to use with cross-domain requests
+cors-allowed-headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ]
+
+# TCP or UNIX socket address for the gRPC server to listen on
+# NOTE: This server only supports /broadcast_tx_commit
+# Deprecated gRPC in the RPC layer of Tendermint will be deprecated in 0.36.
+grpc-laddr = ""
+
+# Maximum number of simultaneous connections.
+# Does not include RPC (HTTP&WebSocket) connections. See max-open-connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+# Deprecated gRPC in the RPC layer of Tendermint will be deprecated in 0.36.
+grpc-max-open-connections = 900
+
+# Activate unsafe RPC commands like /dial-seeds and /unsafe-flush-mempool
+unsafe = false
+
+# Maximum number of simultaneous connections (including WebSocket).
+# Does not include gRPC connections. See grpc-max-open-connections
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+max-open-connections = 900
+
+# Maximum number of unique clientIDs that can /subscribe
+# If you're using /broadcast_tx_commit, set to the estimated maximum number
+# of broadcast_tx_commit calls per block.
+max-subscription-clients = 100
+
+# Maximum number of unique queries a given client can /subscribe to
+# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to
+# the estimated # maximum number of broadcast_tx_commit calls per block.
+max-subscriptions-per-client = 5
+
+# Experimental parameter to specify the maximum number of events a node will
+# buffer, per subscription, before returning an error and closing the
+# subscription. Must be set to at least 100, but higher values will accommodate
+# higher event throughput rates (and will use more memory).
+experimental-subscription-buffer-size = 200
+
+# Experimental parameter to specify the maximum number of RPC responses that
+# can be buffered per WebSocket client. If clients cannot read from the
+# WebSocket endpoint fast enough, they will be disconnected, so increasing this
+# parameter may reduce the chances of them being disconnected (but will cause
+# the node to use more memory).
+#
+# Must be at least the same as "experimental-subscription-buffer-size",
+# otherwise connections could be dropped unnecessarily. This value should
+# ideally be somewhat higher than "experimental-subscription-buffer-size" to
+# accommodate non-subscription-related RPC responses.
+experimental-websocket-write-buffer-size = 200
+
+# If a WebSocket client cannot read fast enough, at present we may
+# silently drop events instead of generating an error or disconnecting the
+# client.
+#
+# Enabling this experimental parameter will cause the WebSocket connection to
+# be closed instead if it cannot read fast enough, allowing for greater
+# predictability in subscription behavior.
+experimental-close-on-slow-client = false
+
+# How long to wait for a tx to be committed during /broadcast_tx_commit.
+# WARNING: Using a value larger than 10s will result in increasing the
+# global HTTP write timeout, which applies to all connections and endpoints.
+# See https://github.com/tendermint/tendermint/issues/3435
+timeout-broadcast-tx-commit = "10s"
+
+# Maximum size of request body, in bytes
+max-body-bytes = 1000000
+
+# Maximum size of request header, in bytes
+max-header-bytes = 1048576
+
+# The path to a file containing certificate that is used to create the HTTPS server.
+# Might be either absolute path or path related to Tendermint's config directory.
+# If the certificate is signed by a certificate authority,
+# the certFile should be the concatenation of the server's certificate, any intermediates,
+# and the CA's certificate.
+# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls-cert-file = ""
+
+# The path to a file containing matching private key that is used to create the HTTPS server.
+# Might be either absolute path or path related to Tendermint's config directory.
+# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls-key-file = ""
+
+# pprof listen address (https://golang.org/pkg/net/http/pprof)
+pprof-laddr = ""
+
+#######################################################
+### P2P Configuration Options ###
+#######################################################
+[p2p]
+
+# Enable the legacy p2p layer.
+use-legacy = false
+
+# Select the p2p internal queue
+queue-type = "priority"
+
+# Address to listen for incoming connections
+laddr = "tcp://0.0.0.0:26656"
+
+# Address to advertise to peers for them to dial
+# If empty, will use the same port as the laddr,
+# and will introspect on the listener or use UPnP
+# to figure out the address. ip and port are required
+# example: 159.89.10.97:26656
+external-address = ""
+
+# Comma separated list of seed nodes to connect to
+# We only use these if we can’t connect to peers in the addrbook
+# NOTE: not used by the new PEX reactor. Please use BootstrapPeers instead.
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+seeds = ""
+
+# Comma separated list of peers to be added to the peer store
+# on startup. Either BootstrapPeers or PersistentPeers are
+# needed for peer discovery
+bootstrap-peers = ""
+
+# Comma separated list of nodes to keep persistent connections to
+persistent-peers = ""
+
+# UPNP port forwarding
+upnp = false
+
+# Path to address book
+# TODO: Remove once p2p refactor is complete in favor of peer store.
+addr-book-file = "config/addrbook.json"
+
+# Set true for strict address routability rules
+# Set false for private or local networks
+addr-book-strict = true
+
+# Maximum number of inbound peers
+#
+# TODO: Remove once p2p refactor is complete in favor of MaxConnections.
+# ref: https://github.com/tendermint/tendermint/issues/5670
+max-num-inbound-peers = 40
+
+# Maximum number of outbound peers to connect to, excluding persistent peers
+#
+# TODO: Remove once p2p refactor is complete in favor of MaxConnections.
+# ref: https://github.com/tendermint/tendermint/issues/5670
+max-num-outbound-peers = 10
+
+# Maximum number of connections (inbound and outbound).
+max-connections = 64
+
+# Rate limits the number of incoming connection attempts per IP address.
+max-incoming-connection-attempts = 100
+
+# List of node IDs, to which a connection will be (re)established ignoring any existing limits
+# TODO: Remove once p2p refactor is complete.
+# ref: https://github.com/tendermint/tendermint/issues/5670
+unconditional-peer-ids = ""
+
+# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used)
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+persistent-peers-max-dial-period = "0s"
+
+# Time to wait before flushing messages out on the connection
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+flush-throttle-timeout = "100ms"
+
+# Maximum size of a message packet payload, in bytes
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+max-packet-msg-payload-size = 1400
+
+# Rate at which packets can be sent, in bytes/second
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+send-rate = 5120000
+
+# Rate at which packets can be received, in bytes/second
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+recv-rate = 5120000
+
+# Set true to enable the peer-exchange reactor
+pex = true
+
+# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
+# Warning: IPs will be exposed at /net_info, for more information https://github.com/tendermint/tendermint/issues/3055
+private-peer-ids = ""
+
+# Toggle to disable guard against peers connecting from the same ip.
+allow-duplicate-ip = false
+
+# Peer connection configuration.
+handshake-timeout = "20s"
+dial-timeout = "3s"
+
+#######################################################
+### Mempool Configuration Option ###
+#######################################################
+[mempool]
+
+# Mempool version to use:
+# 1) "v0" - The legacy non-prioritized mempool reactor.
+# 2) "v1" (default) - The prioritized mempool reactor.
+version = "v1"
+
+recheck = true
+broadcast = true
+
+# Maximum number of transactions in the mempool
+size = 5000
+
+# Limit the total size of all txs in the mempool.
+# This only accounts for raw transactions (e.g. given 1MB transactions and
+# max-txs-bytes=5MB, mempool will only accept 5 transactions).
+max-txs-bytes = 1073741824
+
+# Size of the cache (used to filter transactions we saw earlier) in transactions
+cache-size = 10000
+
+# Do not remove invalid transactions from the cache (default: false)
+# Set to true if it's not possible for any invalid transaction to become valid
+# again in the future.
+keep-invalid-txs-in-cache = false
+
+# Maximum size of a single transaction.
+# NOTE: the max size of a tx transmitted over the network is {max-tx-bytes}.
+max-tx-bytes = 1048576
+
+# Maximum size of a batch of transactions to send to a peer
+# Including space needed by encoding (one varint per transaction).
+# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796
+max-batch-bytes = 0
+
+# ttl-duration, if non-zero, defines the maximum amount of time a transaction
+# can exist for in the mempool.
+#
+# Note, if ttl-num-blocks is also defined, a transaction will be removed if it
+# has existed in the mempool at least ttl-num-blocks number of blocks or if it's
+# insertion time into the mempool is beyond ttl-duration.
+ttl-duration = "0s"
+
+# ttl-num-blocks, if non-zero, defines the maximum number of blocks a transaction
+# can exist for in the mempool.
+#
+# Note, if ttl-duration is also defined, a transaction will be removed if it
+# has existed in the mempool at least ttl-num-blocks number of blocks or if
+# it's insertion time into the mempool is beyond ttl-duration.
+ttl-num-blocks = 0
+
+#######################################################
+### State Sync Configuration Options ###
+#######################################################
+[statesync]
+# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine
+# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in
+# the network to take and serve state machine snapshots. State sync is not attempted if the node
+# has any local state (LastBlockHeight > 0). The node will have a truncated block history,
+# starting from the height of the snapshot.
+enable = false
+
+# State sync uses light client verification to verify state. This can be done either through the
+# P2P layer or RPC layer. Set this to true to use the P2P layer. If false (default), RPC layer
+# will be used.
+use-p2p = false
+
+# If using RPC, at least two addresses need to be provided. They should be compatible with net.Dial,
+# for example: "host.example.com:2125"
+rpc-servers = ""
+
+# The hash and height of a trusted block. Must be within the trust-period.
+trust-height = 0
+trust-hash = ""
+
+# The trust period should be set so that Tendermint can detect and gossip misbehavior before
+# it is considered expired. For chains based on the Cosmos SDK, one day less than the unbonding
+# period should suffice.
+trust-period = "168h0m0s"
+
+# Time to spend discovering snapshots before initiating a restore.
+discovery-time = "15s"
+
+# Temporary directory for state sync snapshot chunks, defaults to os.TempDir().
+# The synchronizer will create a new, randomly named directory within this directory
+# and remove it when the sync is complete.
+temp-dir = ""
+
+# The timeout duration before re-requesting a chunk, possibly from a different
+# peer (default: 15 seconds).
+chunk-request-timeout = "15s"
+
+# The number of concurrent chunk and block fetchers to run (default: 4).
+fetchers = "4"
+
+#######################################################
+### Block Sync Configuration Connections ###
+#######################################################
+[blocksync]
+
+# If this node is many blocks behind the tip of the chain, BlockSync
+# allows them to catchup quickly by downloading blocks in parallel
+# and verifying their commits
+enable = true
+
+# Block Sync version to use:
+# 1) "v0" (default) - the standard Block Sync implementation
+# 2) "v2" - DEPRECATED, please use v0
+version = "v0"
+
+#######################################################
+### Consensus Configuration Options ###
+#######################################################
+[consensus]
+
+wal-file = "data/cs.wal/wal"
+
+# How long we wait for a proposal block before prevoting nil
+timeout-propose = "3s"
+# How much timeout-propose increases with each round
+timeout-propose-delta = "500ms"
+# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil)
+timeout-prevote = "1s"
+# How much the timeout-prevote increases with each round
+timeout-prevote-delta = "500ms"
+# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil)
+timeout-precommit = "1s"
+# How much the timeout-precommit increases with each round
+timeout-precommit-delta = "500ms"
+# How long we wait after committing a block, before starting on the new
+# height (this gives us a chance to receive some more precommits, even
+# though we already have +2/3).
+timeout-commit = "1s"
+
+# How many blocks to look back to check existence of the node's consensus votes before joining consensus
+# When non-zero, the node will panic upon restart
+# if the same consensus key was used to sign {double-sign-check-height} last blocks.
+# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic.
+double-sign-check-height = 0
+
+# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
+skip-timeout-commit = false
+
+# EmptyBlocks mode and possible interval between empty blocks
+create-empty-blocks = true
+create-empty-blocks-interval = "0s"
+
+# Reactor sleep duration parameters
+peer-gossip-sleep-duration = "100ms"
+peer-query-maj23-sleep-duration = "2s"
+
+#######################################################
+### Transaction Indexer Configuration Options ###
+#######################################################
+[tx-index]
+
+# The backend database list to back the indexer.
+# If list contains "null" or "", meaning no indexer service will be used.
+#
+# The application will set which txs to index. In some cases a node operator will be able
+# to decide which txs to index based on configuration set in the application.
+#
+# Options:
+# 1) "null"
+# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
+# 3) "psql" - the indexer services backed by PostgreSQL.
+# When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed.
+indexer = ["kv"]
+
+# The PostgreSQL connection configuration, the connection format:
+# postgresql://:@:/?
+psql-conn = ""
+
+#######################################################
+### Instrumentation Configuration Options ###
+#######################################################
+[instrumentation]
+
+# When true, Prometheus metrics are served under /metrics on
+# PrometheusListenAddr.
+# Check out the documentation for the list of available metrics.
+prometheus = false
+
+# Address to listen for Prometheus collector(s) connections
+prometheus-listen-addr = ":26660"
+
+# Maximum number of simultaneous connections.
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+max-open-connections = 3
+
+# Instrumentation namespace
+namespace = "tendermint"
diff --git a/scripts/confix/testdata/v36-config.toml b/scripts/confix/testdata/v36-config.toml
new file mode 100644
index 000000000..e49b97d89
--- /dev/null
+++ b/scripts/confix/testdata/v36-config.toml
@@ -0,0 +1,479 @@
+# This is a TOML config file.
+# For more information, see https://github.com/toml-lang/toml
+
+# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or
+# relative to the home directory (e.g. "data"). The home directory is
+# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
+# or --home cmd flag.
+
+#######################################################################
+### Main Base Config Options ###
+#######################################################################
+
+# TCP or UNIX socket address of the ABCI application,
+# or the name of an ABCI application compiled in with the Tendermint binary
+proxy-app = "tcp://127.0.0.1:26658"
+
+# A custom human readable name for this node
+moniker = "localhost"
+
+# Mode of Node: full | validator | seed
+# * validator node
+# - all reactors
+# - with priv_validator_key.json, priv_validator_state.json
+# * full node
+# - all reactors
+# - No priv_validator_key.json, priv_validator_state.json
+# * seed node
+# - only P2P, PEX Reactor
+# - No priv_validator_key.json, priv_validator_state.json
+mode = "validator"
+
+# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb
+# * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
+# - pure go
+# - stable
+# * cleveldb (uses levigo wrapper)
+# - fast
+# - requires gcc
+# - use cleveldb build tag (go build -tags cleveldb)
+# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt)
+# - EXPERIMENTAL
+# - may be faster is some use-cases (random reads - indexer)
+# - use boltdb build tag (go build -tags boltdb)
+# * rocksdb (uses github.com/tecbot/gorocksdb)
+# - EXPERIMENTAL
+# - requires gcc
+# - use rocksdb build tag (go build -tags rocksdb)
+# * badgerdb (uses github.com/dgraph-io/badger)
+# - EXPERIMENTAL
+# - use badgerdb build tag (go build -tags badgerdb)
+db-backend = "goleveldb"
+
+# Database directory
+db-dir = "data"
+
+# Output level for logging, including package level options
+log-level = "info"
+
+# Output format: 'plain' (colored text) or 'json'
+log-format = "plain"
+
+##### additional base config options #####
+
+# Path to the JSON file containing the initial validator set and other meta data
+genesis-file = "config/genesis.json"
+
+# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
+node-key-file = "config/node_key.json"
+
+# Mechanism to connect to the ABCI application: socket | grpc
+abci = "socket"
+
+# If true, query the ABCI app on connecting to a new peer
+# so the app can decide if we should keep the connection or not
+filter-peers = false
+
+
+#######################################################
+### Priv Validator Configuration ###
+#######################################################
+[priv-validator]
+
+# Path to the JSON file containing the private key to use as a validator in the consensus protocol
+key-file = "config/priv_validator_key.json"
+
+# Path to the JSON file containing the last sign state of a validator
+state-file = "data/priv_validator_state.json"
+
+# TCP or UNIX socket address for Tendermint to listen on for
+# connections from an external PrivValidator process
+# when the listenAddr is prefixed with grpc instead of tcp it will use the gRPC Client
+laddr = ""
+
+# Path to the client certificate generated while creating needed files for secure connection.
+# If a remote validator address is provided but no certificate, the connection will be insecure
+client-certificate-file = ""
+
+# Client key generated while creating certificates for secure connection
+client-key-file = ""
+
+# Path to the Root Certificate Authority used to sign both client and server certificates
+root-ca-file = ""
+
+
+#######################################################################
+### Advanced Configuration Options ###
+#######################################################################
+
+#######################################################
+### RPC Server Configuration Options ###
+#######################################################
+[rpc]
+
+# TCP or UNIX socket address for the RPC server to listen on
+laddr = "tcp://127.0.0.1:26657"
+
+# A list of origins a cross-domain request can be executed from
+# Default value '[]' disables cors support
+# Use '["*"]' to allow any origin
+cors-allowed-origins = []
+
+# A list of methods the client is allowed to use with cross-domain requests
+cors-allowed-methods = ["HEAD", "GET", "POST", ]
+
+# A list of non simple headers the client is allowed to use with cross-domain requests
+cors-allowed-headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ]
+
+# Activate unsafe RPC commands like /dial-seeds and /unsafe-flush-mempool
+unsafe = false
+
+# Maximum number of simultaneous connections (including WebSocket).
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files}
+# 1024 - 40 - 10 - 50 = 924 = ~900
+max-open-connections = 900
+
+# Maximum number of unique clientIDs that can /subscribe
+# If you're using /broadcast_tx_commit, set to the estimated maximum number
+# of broadcast_tx_commit calls per block.
+max-subscription-clients = 100
+
+# Maximum number of unique queries a given client can /subscribe to
+# If you're using a Local RPC client and /broadcast_tx_commit, set this
+# to the estimated maximum number of broadcast_tx_commit calls per block.
+max-subscriptions-per-client = 5
+
+# If true, disable the websocket interface to the RPC service. This has
+# the effect of disabling the /subscribe, /unsubscribe, and /unsubscribe_all
+# methods for event subscription.
+#
+# EXPERIMENTAL: This setting will be removed in Tendermint v0.37.
+experimental-disable-websocket = false
+
+# The time window size for the event log. All events up to this long before
+# the latest (up to EventLogMaxItems) will be available for subscribers to
+# fetch via the /events method. If 0 (the default) the event log and the
+# /events RPC method are disabled.
+event-log-window-size = "0s"
+
+# The maxiumum number of events that may be retained by the event log. If
+# this value is 0, no upper limit is set. Otherwise, items in excess of
+# this number will be discarded from the event log.
+#
+# Warning: This setting is a safety valve. Setting it too low may cause
+# subscribers to miss events. Try to choose a value higher than the
+# maximum worst-case expected event load within the chosen window size in
+# ordinary operation.
+#
+# For example, if the window size is 10 minutes and the node typically
+# averages 1000 events per ten minutes, but with occasional known spikes of
+# up to 2000, choose a value > 2000.
+event-log-max-items = 0
+
+# How long to wait for a tx to be committed during /broadcast_tx_commit.
+# WARNING: Using a value larger than 10s will result in increasing the
+# global HTTP write timeout, which applies to all connections and endpoints.
+# See https://github.com/tendermint/tendermint/issues/3435
+timeout-broadcast-tx-commit = "10s"
+
+# Maximum size of request body, in bytes
+max-body-bytes = 1000000
+
+# Maximum size of request header, in bytes
+max-header-bytes = 1048576
+
+# The path to a file containing certificate that is used to create the HTTPS server.
+# Might be either absolute path or path related to Tendermint's config directory.
+# If the certificate is signed by a certificate authority,
+# the certFile should be the concatenation of the server's certificate, any intermediates,
+# and the CA's certificate.
+# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls-cert-file = ""
+
+# The path to a file containing matching private key that is used to create the HTTPS server.
+# Might be either absolute path or path related to Tendermint's config directory.
+# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server.
+# Otherwise, HTTP server is run.
+tls-key-file = ""
+
+# pprof listen address (https://golang.org/pkg/net/http/pprof)
+pprof-laddr = ""
+
+#######################################################
+### P2P Configuration Options ###
+#######################################################
+[p2p]
+
+# Select the p2p internal queue
+queue-type = "priority"
+
+# Address to listen for incoming connections
+laddr = "tcp://0.0.0.0:26656"
+
+# Address to advertise to peers for them to dial
+# If empty, will use the same port as the laddr,
+# and will introspect on the listener or use UPnP
+# to figure out the address. ip and port are required
+# example: 159.89.10.97:26656
+external-address = ""
+
+# Comma separated list of seed nodes to connect to
+# We only use these if we can’t connect to peers in the addrbook
+# NOTE: not used by the new PEX reactor. Please use BootstrapPeers instead.
+# TODO: Remove once p2p refactor is complete
+# ref: https:#github.com/tendermint/tendermint/issues/5670
+seeds = ""
+
+# Comma separated list of peers to be added to the peer store
+# on startup. Either BootstrapPeers or PersistentPeers are
+# needed for peer discovery
+bootstrap-peers = ""
+
+# Comma separated list of nodes to keep persistent connections to
+persistent-peers = ""
+
+# UPNP port forwarding
+upnp = false
+
+# Maximum number of connections (inbound and outbound).
+max-connections = 64
+
+# Rate limits the number of incoming connection attempts per IP address.
+max-incoming-connection-attempts = 100
+
+# Set true to enable the peer-exchange reactor
+pex = true
+
+# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
+# Warning: IPs will be exposed at /net_info, for more information https://github.com/tendermint/tendermint/issues/3055
+private-peer-ids = ""
+
+# Toggle to disable guard against peers connecting from the same ip.
+allow-duplicate-ip = false
+
+# Peer connection configuration.
+handshake-timeout = "20s"
+dial-timeout = "3s"
+
+# Time to wait before flushing messages out on the connection
+# TODO: Remove once MConnConnection is removed.
+flush-throttle-timeout = "100ms"
+
+# Maximum size of a message packet payload, in bytes
+# TODO: Remove once MConnConnection is removed.
+max-packet-msg-payload-size = 1400
+
+# Rate at which packets can be sent, in bytes/second
+# TODO: Remove once MConnConnection is removed.
+send-rate = 5120000
+
+# Rate at which packets can be received, in bytes/second
+# TODO: Remove once MConnConnection is removed.
+recv-rate = 5120000
+
+
+#######################################################
+### Mempool Configuration Option ###
+#######################################################
+[mempool]
+
+recheck = true
+broadcast = true
+
+# Maximum number of transactions in the mempool
+size = 5000
+
+# Limit the total size of all txs in the mempool.
+# This only accounts for raw transactions (e.g. given 1MB transactions and
+# max-txs-bytes=5MB, mempool will only accept 5 transactions).
+max-txs-bytes = 1073741824
+
+# Size of the cache (used to filter transactions we saw earlier) in transactions
+cache-size = 10000
+
+# Do not remove invalid transactions from the cache (default: false)
+# Set to true if it's not possible for any invalid transaction to become valid
+# again in the future.
+keep-invalid-txs-in-cache = false
+
+# Maximum size of a single transaction.
+# NOTE: the max size of a tx transmitted over the network is {max-tx-bytes}.
+max-tx-bytes = 1048576
+
+# Maximum size of a batch of transactions to send to a peer
+# Including space needed by encoding (one varint per transaction).
+# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796
+max-batch-bytes = 0
+
+# ttl-duration, if non-zero, defines the maximum amount of time a transaction
+# can exist for in the mempool.
+#
+# Note, if ttl-num-blocks is also defined, a transaction will be removed if it
+# has existed in the mempool at least ttl-num-blocks number of blocks or if it's
+# insertion time into the mempool is beyond ttl-duration.
+ttl-duration = "0s"
+
+# ttl-num-blocks, if non-zero, defines the maximum number of blocks a transaction
+# can exist for in the mempool.
+#
+# Note, if ttl-duration is also defined, a transaction will be removed if it
+# has existed in the mempool at least ttl-num-blocks number of blocks or if
+# it's insertion time into the mempool is beyond ttl-duration.
+ttl-num-blocks = 0
+
+#######################################################
+### State Sync Configuration Options ###
+#######################################################
+[statesync]
+# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine
+# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in
+# the network to take and serve state machine snapshots. State sync is not attempted if the node
+# has any local state (LastBlockHeight > 0). The node will have a truncated block history,
+# starting from the height of the snapshot.
+enable = false
+
+# State sync uses light client verification to verify state. This can be done either through the
+# P2P layer or RPC layer. Set this to true to use the P2P layer. If false (default), RPC layer
+# will be used.
+use-p2p = false
+
+# If using RPC, at least two addresses need to be provided. They should be compatible with net.Dial,
+# for example: "host.example.com:2125"
+rpc-servers = ""
+
+# The hash and height of a trusted block. Must be within the trust-period.
+trust-height = 0
+trust-hash = ""
+
+# The trust period should be set so that Tendermint can detect and gossip misbehavior before
+# it is considered expired. For chains based on the Cosmos SDK, one day less than the unbonding
+# period should suffice.
+trust-period = "168h0m0s"
+
+# Time to spend discovering snapshots before initiating a restore.
+discovery-time = "15s"
+
+# Temporary directory for state sync snapshot chunks, defaults to os.TempDir().
+# The synchronizer will create a new, randomly named directory within this directory
+# and remove it when the sync is complete.
+temp-dir = ""
+
+# The timeout duration before re-requesting a chunk, possibly from a different
+# peer (default: 15 seconds).
+chunk-request-timeout = "15s"
+
+# The number of concurrent chunk and block fetchers to run (default: 4).
+fetchers = "4"
+
+#######################################################
+### Consensus Configuration Options ###
+#######################################################
+[consensus]
+
+wal-file = "data/cs.wal/wal"
+
+# How many blocks to look back to check existence of the node's consensus votes before joining consensus
+# When non-zero, the node will panic upon restart
+# if the same consensus key was used to sign {double-sign-check-height} last blocks.
+# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic.
+double-sign-check-height = 0
+
+# EmptyBlocks mode and possible interval between empty blocks
+create-empty-blocks = true
+create-empty-blocks-interval = "0s"
+
+# Reactor sleep duration parameters
+peer-gossip-sleep-duration = "100ms"
+peer-query-maj23-sleep-duration = "2s"
+
+### Unsafe Timeout Overrides ###
+
+# These fields provide temporary overrides for the Timeout consensus parameters.
+# Use of these parameters is strongly discouraged. Using these parameters may have serious
+# liveness implications for the validator and for the chain.
+#
+# These fields will be removed from the configuration file in the v0.37 release of Tendermint.
+# For additional information, see ADR-74:
+# https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-074-timeout-params.md
+
+# This field provides an unsafe override of the Propose timeout consensus parameter.
+# This field configures how long the consensus engine will wait for a proposal block before prevoting nil.
+# If this field is set to a value greater than 0, it will take effect.
+# unsafe-propose-timeout-override = 0s
+
+# This field provides an unsafe override of the ProposeDelta timeout consensus parameter.
+# This field configures how much the propose timeout increases with each round.
+# If this field is set to a value greater than 0, it will take effect.
+# unsafe-propose-timeout-delta-override = 0s
+
+# This field provides an unsafe override of the Vote timeout consensus parameter.
+# This field configures how long the consensus engine will wait after
+# receiving +2/3 votes in a round.
+# If this field is set to a value greater than 0, it will take effect.
+# unsafe-vote-timeout-override = 0s
+
+# This field provides an unsafe override of the VoteDelta timeout consensus parameter.
+# This field configures how much the vote timeout increases with each round.
+# If this field is set to a value greater than 0, it will take effect.
+# unsafe-vote-timeout-delta-override = 0s
+
+# This field provides an unsafe override of the Commit timeout consensus parameter.
+# This field configures how long the consensus engine will wait after receiving
+# +2/3 precommits before beginning the next height.
+# If this field is set to a value greater than 0, it will take effect.
+# unsafe-commit-timeout-override = 0s
+
+# This field provides an unsafe override of the BypassCommitTimeout consensus parameter.
+# This field configures if the consensus engine will wait for the full Commit timeout
+# before proceeding to the next height.
+# If this field is set to true, the consensus engine will proceed to the next height
+# as soon as the node has gathered votes from all of the validators on the network.
+# unsafe-bypass-commit-timeout-override =
+
+#######################################################
+### Transaction Indexer Configuration Options ###
+#######################################################
+[tx-index]
+
+# The backend database list to back the indexer.
+# If list contains "null" or "", meaning no indexer service will be used.
+#
+# The application will set which txs to index. In some cases a node operator will be able
+# to decide which txs to index based on configuration set in the application.
+#
+# Options:
+# 1) "null" (default) - no indexer services.
+# 2) "kv" - a simple indexer backed by key-value storage (see DBBackend)
+# 3) "psql" - the indexer services backed by PostgreSQL.
+# When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed.
+indexer = ["null"]
+
+# The PostgreSQL connection configuration, the connection format:
+# postgresql://:@:/?
+psql-conn = ""
+
+#######################################################
+### Instrumentation Configuration Options ###
+#######################################################
+[instrumentation]
+
+# When true, Prometheus metrics are served under /metrics on
+# PrometheusListenAddr.
+# Check out the documentation for the list of available metrics.
+prometheus = false
+
+# Address to listen for Prometheus collector(s) connections
+prometheus-listen-addr = ":26660"
+
+# Maximum number of simultaneous connections.
+# If you want to accept a larger number than the default, make sure
+# you increase your OS limits.
+# 0 - unlimited.
+max-open-connections = 3
+
+# Instrumentation namespace
+namespace = "tendermint"
From 322bb460dd3fb0469dc33da8ab419a366878e5fd Mon Sep 17 00:00:00 2001
From: "M. J. Fromberger"
Date: Sat, 9 Apr 2022 07:20:08 -0700
Subject: [PATCH 09/13] keymigrate: fix decoding of block-hash row keys (#8294)
---
CHANGELOG_PENDING.md | 1 +
scripts/keymigrate/migrate.go | 8 ++++++--
scripts/keymigrate/migrate_test.go | 2 +-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md
index 0d070d304..4f3ddc142 100644
--- a/CHANGELOG_PENDING.md
+++ b/CHANGELOG_PENDING.md
@@ -83,3 +83,4 @@ Special thanks to external contributors on this release:
- [light] \#7641 Light Client: fix querying against the latest height (@ashcherbakov)
- [cli] [#7837](https://github.com/tendermint/tendermint/pull/7837) fix app hash in state rollback. (@yihuang)
- [cli] \#8276 scmigrate: ensure target key is correctly renamed. (@creachadair)
+- [cli] \#8294 keymigrate: ensure block hash keys are correctly translated. (@creachadair)
diff --git a/scripts/keymigrate/migrate.go b/scripts/keymigrate/migrate.go
index b53c5e98f..738e982a2 100644
--- a/scripts/keymigrate/migrate.go
+++ b/scripts/keymigrate/migrate.go
@@ -138,12 +138,16 @@ func migrateKey(key keyID) (keyID, error) {
return orderedcode.Append(nil, int64(3), int64(val))
case bytes.HasPrefix(key, keyID("BH:")):
- val, err := strconv.Atoi(string(key[3:]))
+ hash := string(key[3:])
+ if len(hash)%2 == 1 {
+ hash = "0" + hash
+ }
+ val, err := hex.DecodeString(hash)
if err != nil {
return nil, err
}
- return orderedcode.Append(nil, int64(4), int64(val))
+ return orderedcode.Append(nil, int64(4), string(val))
case bytes.HasPrefix(key, keyID("validatorsKey:")):
val, err := strconv.Atoi(string(key[14:]))
if err != nil {
diff --git a/scripts/keymigrate/migrate_test.go b/scripts/keymigrate/migrate_test.go
index 8f6f30808..8fb9c282b 100644
--- a/scripts/keymigrate/migrate_test.go
+++ b/scripts/keymigrate/migrate_test.go
@@ -27,7 +27,7 @@ func getLegacyPrefixKeys(val int) map[string][]byte {
"BlockPartTwo": []byte(fmt.Sprintf("P:%d:%d", val+2, val+val)),
"BlockCommit": []byte(fmt.Sprintf("C:%d", val)),
"SeenCommit": []byte(fmt.Sprintf("SC:%d", val)),
- "BlockHeight": []byte(fmt.Sprintf("BH:%d", val)),
+ "BlockHeight": []byte(fmt.Sprintf("BH:%x", val)),
"Validators": []byte(fmt.Sprintf("validatorsKey:%d", val)),
"ConsensusParams": []byte(fmt.Sprintf("consensusParamsKey:%d", val)),
"ABCIResponse": []byte(fmt.Sprintf("abciResponsesKey:%d", val)),
From b91501cecf32057d7d09e468fe21c5468a28ec0b Mon Sep 17 00:00:00 2001
From: elias-orijtech <103319121+elias-orijtech@users.noreply.github.com>
Date: Sat, 9 Apr 2022 17:07:40 +0200
Subject: [PATCH 10/13] test/fuzz: update oss-fuzz build script to match
reality (#8296)
p2p/pex and p2p/addrbook were deleted in 03ad7d6f20d9fd8fe83d31db168f433480552e94,
secret_connection was renamed to secretconnection in dd97ac6e1c8810a115e53a61c9a91dd40275b3fe.
---
test/fuzz/oss-fuzz-build.sh | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/test/fuzz/oss-fuzz-build.sh b/test/fuzz/oss-fuzz-build.sh
index 8eb30f510..ef2052614 100755
--- a/test/fuzz/oss-fuzz-build.sh
+++ b/test/fuzz/oss-fuzz-build.sh
@@ -2,12 +2,8 @@
export FUZZ_ROOT="github.com/tendermint/tendermint"
-(cd test/fuzz/p2p/addrbook; go run ./init-corpus/main.go)
-compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/p2p/addrbook Fuzz fuzz_p2p_addrbook fuzz
-(cd test/fuzz/p2p/pex; go run ./init-corpus/main.go)
-compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/p2p/pex Fuzz fuzz_p2p_pex fuzz
-(cd test/fuzz/p2p/secret_connection; go run ./init-corpus/main.go)
-compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/p2p/secret_connection Fuzz fuzz_p2p_secret_connection fuzz
+(cd test/fuzz/p2p/secretconnection; go run ./init-corpus/main.go)
+compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/p2p/secretconnection Fuzz fuzz_p2p_secretconnection fuzz
compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/mempool Fuzz fuzz_mempool fuzz
From c53b71821c0bd53929736ed5073426353f2dc069 Mon Sep 17 00:00:00 2001
From: Chill Validation <92176880+chillyvee@users.noreply.github.com>
Date: Sun, 10 Apr 2022 03:42:47 +0900
Subject: [PATCH 11/13] Fix a spelling error (#8297)
---
spec/consensus/evidence.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/consensus/evidence.md b/spec/consensus/evidence.md
index 84d51a01b..edf9e53ff 100644
--- a/spec/consensus/evidence.md
+++ b/spec/consensus/evidence.md
@@ -1,7 +1,7 @@
# Evidence
Evidence is an important component of Tendermint's security model. Whilst the core
-consensus protocol provides correctness gaurantees for state machine replication
+consensus protocol provides correctness guarantees for state machine replication
that can tolerate less than 1/3 failures, the evidence system looks to detect and
gossip byzantine faults whose combined power is greater than or equal to 1/3. It is worth noting that
the evidence system is designed purely to detect possible attacks, gossip them,
From f504089273263ca39e20917d0e6f1f44c0d67e32 Mon Sep 17 00:00:00 2001
From: John Adler
Date: Sat, 9 Apr 2022 23:15:07 -0400
Subject: [PATCH 12/13] build: use go install instead of go get. (#8299)
---
.github/workflows/fuzz-nightly.yml | 2 +-
Makefile | 2 +-
docs/nodes/remote-signer.md | 2 +-
docs/tools/terraform-and-ansible.md | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/fuzz-nightly.yml b/.github/workflows/fuzz-nightly.yml
index 569442362..ea998929f 100644
--- a/.github/workflows/fuzz-nightly.yml
+++ b/.github/workflows/fuzz-nightly.yml
@@ -21,7 +21,7 @@ jobs:
- name: Install go-fuzz
working-directory: test/fuzz
- run: go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
+ run: go install github.com/dvyukov/go-fuzz/go-fuzz@latest github.com/dvyukov/go-fuzz/go-fuzz-build@latest
- name: Fuzz mempool
working-directory: test/fuzz
diff --git a/Makefile b/Makefile
index 85cd3202d..ba8850164 100644
--- a/Makefile
+++ b/Makefile
@@ -178,7 +178,7 @@ go.sum: go.mod
draw_deps:
@# requires brew install graphviz or apt-get install graphviz
- go get github.com/RobotsAndPencils/goviz
+ go install github.com/RobotsAndPencils/goviz@latest
@goviz -i github.com/tendermint/tendermint/cmd/tendermint -d 3 | dot -Tpng -o dependency-graph.png
.PHONY: draw_deps
diff --git a/docs/nodes/remote-signer.md b/docs/nodes/remote-signer.md
index e7dfccacd..39a38e1b7 100644
--- a/docs/nodes/remote-signer.md
+++ b/docs/nodes/remote-signer.md
@@ -37,7 +37,7 @@ There are two ways to generate certificates, [openssl](https://www.openssl.org/)
- Install `Certstrap`:
```sh
- go get github.com/square/certstrap@v1.2.0
+ go install github.com/square/certstrap@v1.2.0
```
- Create certificate authority for self signing.
diff --git a/docs/tools/terraform-and-ansible.md b/docs/tools/terraform-and-ansible.md
index 6efbf3751..78e45652c 100644
--- a/docs/tools/terraform-and-ansible.md
+++ b/docs/tools/terraform-and-ansible.md
@@ -164,7 +164,7 @@ page](https://app.logz.io/#/dashboard/data-sources/Filebeat), then:
yum install systemd-devel || echo "This will only work on RHEL-based systems."
apt-get install libsystemd-dev || echo "This will only work on Debian-based systems."
-go get github.com/mheese/journalbeat
+go install github.com/mheese/journalbeat@latest
ansible-playbook -i inventory/digital_ocean.py -l sentrynet logzio.yml -e LOGZIO_TOKEN=ABCDEFGHIJKLMNOPQRSTUVWXYZ012345
```
From 4743a7ad0d62aadb2eeafe4359b398e771620b0e Mon Sep 17 00:00:00 2001
From: "M. J. Fromberger"
Date: Sun, 10 Apr 2022 19:37:54 -0700
Subject: [PATCH 13/13] confix: clean up and document transformations (#8301)
Right now the confix tool works up to v0.35. This change is preparation for
extending the tool to handle additional changes in v0.36.
Mostly this is adding documentation. The one functional change is to fix the
name of the moved "fast-sync" parameter, which was renamed "enable".
- Document the origin of each transformation step.
- Update fast-sync target name.
---
go.mod | 3 +--
go.sum | 4 ++--
scripts/confix/confix.go | 12 +++++++++---
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/go.mod b/go.mod
index 91895c36e..0b05266bd 100644
--- a/go.mod
+++ b/go.mod
@@ -73,8 +73,7 @@ require (
github.com/charithe/durationcheck v0.0.9 // indirect
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect
github.com/containerd/continuity v0.2.1 // indirect
- github.com/creachadair/taskgroup v0.3.2
- github.com/creachadair/tomledit v0.0.5
+ github.com/creachadair/tomledit v0.0.11
github.com/daixiang0/gci v0.3.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.4.3 // indirect
diff --git a/go.sum b/go.sum
index 2351806cf..ea3befa2f 100644
--- a/go.sum
+++ b/go.sum
@@ -225,8 +225,8 @@ github.com/creachadair/atomicfile v0.2.4 h1:GRjpQLmz/78I4+nBQpGMFrRa9yrL157AUTrA
github.com/creachadair/atomicfile v0.2.4/go.mod h1:BRq8Une6ckFneYXZQ+kO7p1ZZP3I2fzVzf28JxrIkBc=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk=
-github.com/creachadair/tomledit v0.0.5 h1:ILJt2EO93fr8w2UAUA5FPNThk1Pq5m4KX2qUZ1Xz4Xs=
-github.com/creachadair/tomledit v0.0.5/go.mod h1:gvtfnSZLa+YNQD28vaPq0Nk12bRxEhmUdBzAWn+EGF4=
+github.com/creachadair/tomledit v0.0.11 h1:6fHNLdCa5pNudF+5Sb+3M+hPHz/q1fMoAm+MI6TWIR4=
+github.com/creachadair/tomledit v0.0.11/go.mod h1:gvtfnSZLa+YNQD28vaPq0Nk12bRxEhmUdBzAWn+EGF4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
diff --git a/scripts/confix/confix.go b/scripts/confix/confix.go
index aa73897a5..b958060fe 100644
--- a/scripts/confix/confix.go
+++ b/scripts/confix/confix.go
@@ -80,24 +80,28 @@ func main() {
var plan = transform.Plan{
{
+ // Since https://github.com/tendermint/tendermint/pull/5777.
Desc: "Rename everything from snake_case to kebab-case",
T: transform.SnakeToKebab(),
},
{
+ // Since https://github.com/tendermint/tendermint/pull/6896.
Desc: "Rename [fastsync] to [blocksync]",
T: transform.Rename(parser.Key{"fastsync"}, parser.Key{"blocksync"}),
ErrorOK: true,
},
{
- Desc: "Move top-level fast_sync key under [blocksync]",
+ // Since https://github.com/tendermint/tendermint/pull/7159.
+ Desc: "Move top-level fast_sync key to blocksync.enable",
T: transform.MoveKey(
parser.Key{"fast-sync"},
parser.Key{"blocksync"},
- parser.Key{"fast-sync"},
+ parser.Key{"enable"},
),
ErrorOK: true,
},
{
+ // Since https://github.com/tendermint/tendermint/pull/6462.
Desc: "Move priv-validator settings under [priv-validator]",
T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
const pvPrefix = "priv-validator-"
@@ -144,6 +148,8 @@ var plan = transform.Plan{
}),
},
{
+ // v1 removed: https://github.com/tendermint/tendermint/pull/5728
+ // v2 deprecated: https://github.com/tendermint/tendermint/pull/6730
Desc: `Set blocksync.version to "v0"`,
T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
v := doc.First("blocksync", "version")
@@ -166,7 +172,7 @@ func ApplyFixes(ctx context.Context, doc *tomledit.Document) error {
tmVersion := GuessConfigVersion(doc)
if tmVersion == vUnknown {
return errors.New("cannot tell what Tendermint version created this config")
- } else if tmVersion < v34 {
+ } else if tmVersion < v34 || tmVersion > v36 {
// TODO(creachadair): Add in rewrites for older versions. This will
// require some digging to discover what the changes were. The upgrade
// instructions do not give specifics.