Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions config/tendermintbase/tendermintbase.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ const (
RPCSectionName = "rpc"
ConsensusSectionName = "consensus"
MempoolSectionName = "mempool"

StateSyncSectionName = "statesync"
TxIndexSectionName = "tx-index"
InstrumentationSectionName = "instrumentation"
PrivValidatorSectionName = "priv-validator"
SelfRemediationSectionName = "self-remediation"
)

// removedSettings are the consensus paths this section does not declare.
Expand Down Expand Up @@ -60,6 +66,15 @@ func init() {
append([]string{filledFromTheCommandLine}, removedSettings...)...)
registry.RegisterSectionExcluding(MempoolSectionName, &tmcfg.MempoolConfig{}, mempoolDefaults,
filledFromTheCommandLine)
registry.RegisterSectionExcluding(StateSyncSectionName, &tmcfg.StateSyncConfig{}, stateSyncDefaults,
"rpc-servers")
registry.RegisterSection(TxIndexSectionName, &tmcfg.TxIndexConfig{}, txIndexDefaults)
registry.RegisterSection(InstrumentationSectionName, &tmcfg.InstrumentationConfig{},
instrumentationDefaults)
registry.RegisterSectionExcluding(PrivValidatorSectionName, &tmcfg.PrivValidatorConfig{},
privValidatorDefaults, filledFromTheCommandLine)
registry.RegisterSection(SelfRemediationSectionName, &tmcfg.SelfRemediationConfig{},
selfRemediationDefaults)
}

// forMode is the configuration the seid init command writes for a kind of node.
Expand Down Expand Up @@ -117,3 +132,40 @@ func consensusDefaults(mode registry.Mode) any { return *forMode(mode).Consensus
// The same values for every mode. What a node holds before a transaction is decided is a limit on its own
// memory and bandwidth, and nothing in the binary makes one follow from what kind of node is asking.
func mempoolDefaults(mode registry.Mode) any { return *forMode(mode).Mempool }

// The one path the state sync section does not declare.
//
// The list of servers to fetch a snapshot from has no default and cannot have one: the addresses are the
// operator's own peers. An empty list is not a value they can inherit, and any address written here would
// name a host this binary does not know exists.

// stateSyncDefaults is what a generated file carries for the state sync section.
//
// The same values for every mode. Whether a node starts from a snapshot is a decision about how it is being
// brought up rather than about what it will be, and every kind of node can be brought up either way.
func stateSyncDefaults(mode registry.Mode) any { return *forMode(mode).StateSync }

// txIndexDefaults is what a generated file carries for the transaction index section.
//
// Answered per mode, for the indexer alone. A node that serves queries indexes transactions so it can
// answer them, and a validator and a seed serve none, so they index nothing and keep the write.
func txIndexDefaults(mode registry.Mode) any { return *forMode(mode).TxIndex }

// instrumentationDefaults is what a generated file carries for the instrumentation section.
//
// The same values for every mode. What a node measures about itself is a decision about how it is operated,
// and an operator who collects metrics collects them from every kind of node they run.
func instrumentationDefaults(mode registry.Mode) any { return *forMode(mode).Instrumentation }

// privValidatorDefaults is what a generated file carries for the signing key section.
//
// The same values for every mode. These are paths and an address for reaching a signer, and a node that
// does not sign simply does not use them, so varying them by kind would state a difference the binary does
// not make.
func privValidatorDefaults(mode registry.Mode) any { return *forMode(mode).PrivValidator }

// selfRemediationDefaults is what a generated file carries for the self remediation section.
//
// The same values for every mode. These are the thresholds at which a node restarts itself, and each one
// describes a node that has stopped making progress, which is the same condition whatever the node is for.
func selfRemediationDefaults(mode registry.Mode) any { return *forMode(mode).SelfRemediation }
73 changes: 72 additions & 1 deletion config/tendermintbase/tendermintbase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,32 @@ var whatVariesByNodeKind = map[string]map[registry.Mode]string{
registry.ModeFull: "false",
registry.ModeArchive: "false",
},
"tx-index.indexer": {
registry.ModeValidator: "[null]",
registry.ModeSeed: "[null]",
registry.ModeFull: "[kv]",
registry.ModeArchive: "[kv]",
},
}

// declaredSections are the sections this package registers, so a test walks the set rather than a list that
// has to be extended alongside it.
func declaredSections() []string {
return []string{
P2PSectionName, RPCSectionName, ConsensusSectionName, MempoolSectionName,
StateSyncSectionName, TxIndexSectionName, InstrumentationSectionName,
PrivValidatorSectionName, SelfRemediationSectionName,
}
}

// ours reports whether a key belongs to a section this package registers.
func ours(key string) bool {
for _, name := range declaredSections() {
if strings.HasPrefix(key, name+".") {
return true
}
}
return false
}

// TestWhatVariesByNodeKindIsTheRecordedSet measures the mode rules through the declared values.
Expand All @@ -62,7 +88,7 @@ func TestWhatVariesByNodeKindIsTheRecordedSet(t *testing.T) {

var measured []string
for key := range byMode[registry.ModeValidator] {
if !strings.HasPrefix(key, P2PSectionName+".") && !strings.HasPrefix(key, RPCSectionName+".") {
if !ours(key) {
continue
}
seen := map[string]bool{}
Expand Down Expand Up @@ -111,6 +137,11 @@ func TestTheDeclaredKeysAreTheOnesTheReaderDecodes(t *testing.T) {
{RPCSectionName, &tmcfg.RPCConfig{}, 1},
{ConsensusSectionName, &tmcfg.ConsensusConfig{}, len(removedSettings) + 1},
{MempoolSectionName, &tmcfg.MempoolConfig{}, 1},
{StateSyncSectionName, &tmcfg.StateSyncConfig{}, 1},
{TxIndexSectionName, &tmcfg.TxIndexConfig{}, 0},
{InstrumentationSectionName, &tmcfg.InstrumentationConfig{}, 0},
{PrivValidatorSectionName, &tmcfg.PrivValidatorConfig{}, 1},
{SelfRemediationSectionName, &tmcfg.SelfRemediationConfig{}, 0},
} {
registered, ok := registry.Lookup(tc.section)
if !ok {
Expand Down Expand Up @@ -321,6 +352,46 @@ func probeValueFor(rel string) string {
}
}

// TestTheStateSyncExclusionIsThePathWithNoDefault names why that section leaves one path out.
//
// The servers to fetch a snapshot from are the operator's own peers, so there is no value to inherit. An
// empty list is not a default an operator can start from, and an address written here would name a host
// this binary cannot know about. If the node ever ships one, this fails and the key should be declared.
func TestTheStateSyncExclusionIsThePathWithNoDefault(t *testing.T) {
registered, ok := registry.Lookup(StateSyncSectionName)
if !ok {
t.Fatalf("%s is not registered; Defects: %v", StateSyncSectionName, registry.Defects())
}
if want := []string{StateSyncSectionName + ".rpc-servers"}; !reflect.DeepEqual(registered.Excluded, want) {
t.Fatalf("excluded is %v, want %v", registered.Excluded, want)
}
if got := tmcfg.DefaultStateSyncConfig().RPCServers; len(got) != 0 {
t.Errorf("the node now defaults the snapshot servers to %v, so it states a value and the key "+
"belongs declared rather than excluded", got)
}
}

// TestEverySectionThisPackageRegistersIsUsable is the check no single section here can make.
//
// A registration the registry cannot use is recorded rather than panicked, so a section that failed to
// register is absent rather than loud, and two of the refusals depend on what else has registered. Nothing
// is enumerated beyond the section names this package owns, so adding one is covered by adding it there.
func TestEverySectionThisPackageRegistersIsUsable(t *testing.T) {
for _, name := range declaredSections() {
registered, ok := registry.Lookup(name)
if !ok {
t.Errorf("%s is not registered; Defects: %v", name, registry.Defects())
continue
}
if len(registered.Keys) == 0 {
t.Errorf("%s registered and declares no key", name)
}
}
for _, d := range registry.Defects() {
t.Errorf("the registry refused %s: %v", d.Section, d.Err)
}
}

// TestNoSectionDeclaresTheRootDirectory covers a field five of these sections carry.
//
// Each holds a root directory tagged the same as the key at the top of the file, and the node fills every
Expand Down
Loading