Skip to content
Closed
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
26 changes: 26 additions & 0 deletions cmd/cometbft/commands/run_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/cometbft/cometbft/crypto/ed25519"
kt "github.com/cometbft/cometbft/internal/keytypes"
cmtos "github.com/cometbft/cometbft/internal/os"
"github.com/cometbft/cometbft/internal/trace"
nm "github.com/cometbft/cometbft/node"
)

Expand Down Expand Up @@ -90,6 +91,31 @@ func AddNodeFlags(cmd *cobra.Command) {
config.DBPath,
"database directory")
cmd.Flags().StringVarP(&keyType, "key-type", "k", ed25519.KeyType, fmt.Sprintf("private key type (one of %s)", kt.SupportedKeyTypesStr()))

// trace flags
cmd.PersistentFlags().String(
trace.FlagTracePushConfig,
config.Instrumentation.TracePushConfig,
trace.FlagTracePushConfigDescription,
)

cmd.PersistentFlags().String(
trace.FlagTracePullAddress,
config.Instrumentation.TracePullAddress,
trace.FlagTracePullAddressDescription,
)

cmd.PersistentFlags().String(
trace.FlagPyroscopeURL,
config.Instrumentation.PyroscopeURL,
trace.FlagPyroscopeURLDescription,
)

cmd.PersistentFlags().Bool(
trace.FlagPyroscopeTrace,
config.Instrumentation.PyroscopeTrace,
trace.FlagPyroscopeTraceDescription,
)
}

// NewRunNodeCmd returns the command that allows the CLI to start a node.
Expand Down
94 changes: 91 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,18 @@ const (

MempoolTypeFlood = "flood"
MempoolTypeNop = "nop"
MempoolTypeCAT = "cat"
)

// NOTE: Most of the structs & relevant comments + the
var (
// DefaultTracingTables is a list of tables that are used for storing traces.
// This global var is filled by an init function in the schema package. This
// allows for the schema package to contain all the relevant logic while
// avoiding import cycles.
DefaultTracingTables = ""
)

// NOTE: Most of the structs & relevant comments the
// default configuration options were used to manually
// generate the config.toml. Please reflect any changes
// made here in the defaultConfigTemplate constant in
Expand Down Expand Up @@ -934,6 +943,7 @@ type MempoolConfig struct {
// (default)
// - "nop" : nop-mempool (short for no operation; the ABCI app is
// responsible for storing, disseminating and proposing txs).
// - "cat" : content addressable transaction pool
// "create_empty_blocks=false" is not supported.
Type string `mapstructure:"type"`
// RootDir is the root directory for all data. This should be configured via
Expand Down Expand Up @@ -1007,6 +1017,12 @@ type MempoolConfig struct {
// redundancy level. The higher the value, the longer it will take the node
// to reduce bandwidth and converge to a stable redundancy level.
DOGAdjustInterval time.Duration `mapstructure:"dog_adjust_interval"`

// MaxGossipDelay is the maximum allotted time that the reactor expects a transaction to
// arrive before issuing a new request to a different peer
// Only applicable to the v2 / CAT mempool
// Default is 200ms
MaxGossipDelay time.Duration `mapstructure:"max-gossip-delay"`
}

// DefaultMempoolConfig returns a default configuration for the CometBFT mempool.
Expand Down Expand Up @@ -1241,8 +1257,13 @@ func (cfg *BlockSyncConfig) ValidateBasic() error {
// including timeouts and details about the WAL and the block structure.
type ConsensusConfig struct {
RootDir string `mapstructure:"home"`
WalPath string `mapstructure:"wal_file"`
walFile string // overrides WalPath if set
// If set to true, only internal messages will be written
// to the WAL. External messages like votes, proposals
// block parts, will not be written
// Default: true
OnlyInternalWal bool `mapstructure:"only_internal_wal"`
WalPath string `mapstructure:"wal_file"`
walFile string // overrides WalPath if set

// How long we wait for a proposal block before prevoting nil
TimeoutPropose time.Duration `mapstructure:"timeout_propose"`
Expand Down Expand Up @@ -1270,6 +1291,7 @@ type ConsensusConfig struct {
// DefaultConsensusConfig returns a default configuration for the consensus service.
func DefaultConsensusConfig() *ConsensusConfig {
return &ConsensusConfig{
OnlyInternalWal: true,
WalPath: filepath.Join(DefaultDataDir, "cs.wal", "wal"),
TimeoutPropose: 3000 * time.Millisecond,
TimeoutProposeDelta: 500 * time.Millisecond,
Expand Down Expand Up @@ -1514,6 +1536,38 @@ type InstrumentationConfig struct {

// Instrumentation namespace.
Namespace string `mapstructure:"namespace"`

// TracePushConfig is the relative path of the push config. This second
// config contains credentials for where and how often to.
TracePushConfig string `mapstructure:"trace_push_config"`

// TracePullAddress is the address that the trace server will listen on for
// pulling data.
TracePullAddress string `mapstructure:"trace_pull_address"`

// TraceType is the type of tracer used. Options are "local" and "noop".
TraceType string `mapstructure:"trace_type"`

// TraceBufferSize is the number of traces to write in a single batch.
TraceBufferSize int `mapstructure:"trace_push_batch_size"`

// TracingTables is the list of tables that will be traced. See the
// pkg/trace/schema for a complete list of tables. It is represented as a
// comma separate string. For example: "consensus_round_state,mempool_tx".
TracingTables string `mapstructure:"tracing_tables"`

// PyroscopeURL is the pyroscope url used to establish a connection with a
// pyroscope continuous profiling server.
PyroscopeURL string `mapstructure:"pyroscope_url"`

// PyroscopeProfile is a flag that enables tracing with pyroscope.
PyroscopeTrace bool `mapstructure:"pyroscope_trace"`

// PyroscopeProfileTypes is a list of profile types to be traced with
// pyroscope. Available profile types are: cpu, alloc_objects, alloc_space,
// inuse_objects, inuse_space, goroutines, mutex_count, mutex_duration,
// block_count, block_duration.
PyroscopeProfileTypes []string `mapstructure:"pyroscope_profile_types"`
}

// DefaultInstrumentationConfig returns a default configuration for metrics
Expand All @@ -1524,6 +1578,23 @@ func DefaultInstrumentationConfig() *InstrumentationConfig {
PrometheusListenAddr: ":26660",
MaxOpenConnections: 3,
Namespace: "cometbft",
TracePushConfig: "",
TracePullAddress: "",
TraceType: "noop",
TraceBufferSize: 1000,
TracingTables: DefaultTracingTables,
PyroscopeURL: "",
PyroscopeTrace: false,
PyroscopeProfileTypes: []string{
"cpu",
"alloc_objects",
"inuse_objects",
"goroutines",
"mutex_count",
"mutex_duration",
"block_count",
"block_duration",
},
}
}

Expand All @@ -1539,6 +1610,23 @@ func (cfg *InstrumentationConfig) ValidateBasic() error {
if cfg.MaxOpenConnections < 0 {
return cmterrors.ErrNegativeField{Field: "max_open_connections"}
}
if cfg.PyroscopeTrace && cfg.PyroscopeURL == "" {
return errors.New("pyroscope_trace can't be enabled if profiling is disabled")
}
// if there is not TracePushConfig configured, then we do not need to validate the rest
// of the config because we are not connecting.
if cfg.TracePushConfig == "" {
return nil
}
if cfg.TracePullAddress == "" {
return fmt.Errorf("token is required")
}
if cfg.TraceType == "" {
return fmt.Errorf("org is required")
}
if cfg.TraceBufferSize <= 0 {
return fmt.Errorf("batch size must be greater than 0")
}
return nil
}

Expand Down
36 changes: 36 additions & 0 deletions config/config.toml.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,39 @@ max_open_connections = {{ .Instrumentation.MaxOpenConnections }}

# Instrumentation namespace
namespace = "{{ .Instrumentation.Namespace }}"

# TracePushConfig is the relative path of the push config.
# This second config contains credentials for where and how often to
# push trace data to. For example, if the config is next to this config,
# it would be "push_config.json".
trace_push_config = "{{ .Instrumentation.TracePushConfig }}"

# The tracer pull address specifies which address will be used for pull based
# event collection. If empty, the pull based server will not be started.
trace_pull_address = "{{ .Instrumentation.TracePullAddress }}"

# The tracer to use for collecting trace data.
trace_type = "{{ .Instrumentation.TraceType }}"

# The size of the batches that are sent to the database.
trace_push_batch_size = {{ .Instrumentation.TraceBufferSize }}

# The list of tables that are updated when tracing. All available tables and
# their schema can be found in the pkg/trace/schema package. It is represented as a
# comma separate string. For example: "consensus_round_state,mempool_tx".
tracing_tables = "{{ .Instrumentation.TracingTables }}"

# The URL of the pyroscope instance to use for continuous profiling.
# If empty, continuous profiling is disabled.
pyroscope_url = "{{ .Instrumentation.PyroscopeURL }}"

# When true, tracing data is added to the continuous profiling
# performed by pyroscope.
pyroscope_trace = {{ .Instrumentation.PyroscopeTrace }}

# pyroscope_profile_types is a list of profile types to be traced with
# pyroscope. Available profile types are: cpu, alloc_objects, alloc_space,
# inuse_objects, inuse_space, goroutines, mutex_count, mutex_duration,
# block_count, block_duration.
pyroscope_profile_types = [{{ range .Instrumentation.PyroscopeProfileTypes }}{{ printf "%q, " . }}{{end}}]

45 changes: 45 additions & 0 deletions crypto/merkle/proof_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,36 @@ func (poz ProofOperators) Verify(root []byte, keypath string, args [][]byte) err
return nil
}

// VerifyFromKeys performs the same verification logic as the normal Verify
// method, except it does not perform any processing on the keypath. This is
// useful when using keys that have split or escape points as a part of the key.
func (poz ProofOperators) VerifyFromKeys(root []byte, keys [][]byte, args [][]byte) (err error) {
for i, op := range poz {
key := op.GetKey()
if len(key) != 0 {
if len(keys) == 0 {
return fmt.Errorf("key path has insufficient # of parts: expected no more keys but got %v", string(key))
}
lastKey := keys[len(keys)-1]
if !bytes.Equal(lastKey, key) {
return fmt.Errorf("key mismatch on operation #%d: expected %v but got %v", i, string(lastKey), string(key))
}
keys = keys[:len(keys)-1]
}
args, err = op.Run(args)
if err != nil {
return
}
}
if !bytes.Equal(root, args[0]) {
return fmt.Errorf("calculated root hash is invalid: expected %X but got %X", root, args[0])
}
if len(keys) != 0 {
return fmt.Errorf("keypath not consumed all: %s", string(bytes.Join(keys, []byte("/"))))
}
return nil
}

// ----------------------------------------
// ProofRuntime - main entrypoint

Expand Down Expand Up @@ -131,6 +161,10 @@ func (prt *ProofRuntime) VerifyValue(proof *cmtcrypto.ProofOps, root []byte, key
return prt.Verify(proof, root, keypath, [][]byte{value})
}

func (prt *ProofRuntime) VerifyValueFromKeys(proof *cmtcrypto.ProofOps, root []byte, keys [][]byte, value []byte) (err error) {
return prt.VerifyFromKeys(proof, root, keys, [][]byte{value})
}

// TODO In the long run we'll need a method of classification of ops,
// whether existence or absence or perhaps a third?
func (prt *ProofRuntime) VerifyAbsence(proof *cmtcrypto.ProofOps, root []byte, keypath string) (err error) {
Expand All @@ -148,6 +182,17 @@ func (prt *ProofRuntime) Verify(proof *cmtcrypto.ProofOps, root []byte, keypath
return poz.Verify(root, keypath, args)
}

// VerifyFromKeys performs the same verification logic as the normal Verify
// method, except it does not perform any processing on the keypath. This is
// useful when using keys that have split or escape points as a part of the key.
func (prt *ProofRuntime) VerifyFromKeys(proof *cmtcrypto.ProofOps, root []byte, keys [][]byte, args [][]byte) (err error) {
poz, err := prt.DecodeProof(proof)
if err != nil {
return fmt.Errorf("decoding proof: %w", err)
}
return poz.VerifyFromKeys(root, keys, args)
}

// DefaultProofRuntime only knows about value proofs.
// To use e.g. IAVL proofs, register op-decoders as
// defined in the IAVL package.
Expand Down
68 changes: 68 additions & 0 deletions crypto/merkle/proof_op_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,71 @@ func TestProofOperators_Verify(t *testing.T) {

require.NoError(t, err, "Verify Failed")
}

func TestProofOperatorsFromKeys(t *testing.T) {
var err error

// ProofRuntime setup
// TODO test this somehow.

// ProofOperators setup
op1 := merkle.NewDominoOp("KEY1", "INPUT1", "INPUT2")
op2 := merkle.NewDominoOp("KEY%2", "INPUT2", "INPUT3")
op3 := merkle.NewDominoOp("", "INPUT3", "INPUT4")
op4 := merkle.NewDominoOp("KEY/4", "INPUT4", "OUTPUT4")

// add characters to the keys that would otherwise result in bad keypath if
// processed
keys1 := [][]byte{bz("KEY/4"), bz("KEY%2"), bz("KEY1")}
badkeys1 := [][]byte{bz("WrongKey"), bz("KEY%2"), bz("KEY1")}
keys2 := [][]byte{bz("KEY3"), bz("KEY%2"), bz("KEY1")}
keys3 := [][]byte{bz("KEY2"), bz("KEY1")}

// Good
popz := merkle.ProofOperators([]merkle.ProofOperator{op1, op2, op3, op4})
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys1, [][]byte{bz("INPUT1")})
require.NoError(t, err)

// BAD INPUT
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys1, [][]byte{bz("INPUT1_WRONG")})
require.Error(t, err)

// BAD KEY 1
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys2, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD KEY 2
err = popz.VerifyFromKeys(bz("OUTPUT4"), badkeys1, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD KEY 5
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys3, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD OUTPUT 1
err = popz.VerifyFromKeys(bz("OUTPUT4_WRONG"), keys1, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD OUTPUT 2
err = popz.VerifyFromKeys(bz(""), keys1, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD POPZ 1
popz = merkle.ProofOperators([]merkle.ProofOperator{op1, op2, op4})
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys1, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD POPZ 2
popz = merkle.ProofOperators([]merkle.ProofOperator{op4, op3, op2, op1})
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys1, [][]byte{bz("INPUT1")})
require.Error(t, err)

// BAD POPZ 3
popz = merkle.ProofOperators([]merkle.ProofOperator{})
err = popz.VerifyFromKeys(bz("OUTPUT4"), keys1, [][]byte{bz("INPUT1")})
require.Error(t, err)
}

func bz(s string) []byte {
return []byte(s)
}
3 changes: 2 additions & 1 deletion internal/blocksync/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

bcproto "github.com/cometbft/cometbft/api/cometbft/blocksync/v2"
"github.com/cometbft/cometbft/internal/blocksync"
"github.com/cometbft/cometbft/internal/test"
"github.com/cometbft/cometbft/types"
)

Expand Down Expand Up @@ -78,7 +79,7 @@ func TestBcStatusResponseMessageValidateBasic(t *testing.T) {

//nolint:lll // ignore line length in tests
func TestBlocksyncMessageVectors(t *testing.T) {
block := types.MakeBlock(int64(3), []types.Tx{types.Tx("Hello World")}, nil, nil)
block := types.MakeBlock(int64(3), test.MakeData([]types.Tx{types.Tx("Hello World")}), nil, nil)
block.Version.Block = 11 // overwrite updated protocol version

bpb, err := block.ToProto()
Expand Down
Loading
Loading