github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/consensus/tendermint/config.go (about)

     1  package tendermint
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"net"
     7  	"net/url"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/hyperledger/burrow/consensus/abci"
    12  	tmConfig "github.com/tendermint/tendermint/config"
    13  )
    14  
    15  const (
    16  	NeverCreateEmptyBlocks  = "never"
    17  	AlwaysCreateEmptyBlocks = "always"
    18  )
    19  
    20  // Burrow's view on Tendermint's config. Since we operate as a Tendermint harness not all configuration values
    21  // are applicable, we may not allow some values to specified, or we may not allow some to be set independently.
    22  // So this serves as a layer of indirection over Tendermint's real config that we derive from ours.
    23  type BurrowTendermintConfig struct {
    24  	Enabled bool
    25  	// Initial peers we connect to for peer exchange
    26  	Seeds string
    27  	// Whether this node should crawl the network looking for new peers - disconnecting to peers after it has shared addresses
    28  	SeedMode bool
    29  	// Peers to which we automatically connect
    30  	PersistentPeers string
    31  	ListenHost      string
    32  	ListenPort      string
    33  	// Optional external that nodes may provide with their NodeInfo
    34  	ExternalAddress string
    35  	// Set true for strict address routability rules
    36  	// Set false for private or local networks
    37  	AddrBookStrict bool
    38  	Moniker        string
    39  	// Only accept connections from registered peers
    40  	IdentifyPeers bool
    41  	// Peers ID or address this node is authorize to sync with
    42  	AuthorizedPeers string
    43  	// EmptyBlocks mode and possible interval between empty blocks in seconds, one of:
    44  	// "", "never" (to never create unnecessary blocks)
    45  	// "always" (to create empty blocks each consensus round)
    46  	CreateEmptyBlocks string
    47  }
    48  
    49  func DefaultBurrowTendermintConfig() *BurrowTendermintConfig {
    50  	tmDefaultConfig := tmConfig.DefaultConfig()
    51  	url, err := url.ParseRequestURI(tmDefaultConfig.P2P.ListenAddress)
    52  	if err != nil {
    53  		return nil
    54  	}
    55  	return &BurrowTendermintConfig{
    56  		Enabled:           true,
    57  		ListenHost:        url.Hostname(),
    58  		ListenPort:        url.Port(),
    59  		ExternalAddress:   tmDefaultConfig.P2P.ExternalAddress,
    60  		CreateEmptyBlocks: "5m",
    61  	}
    62  }
    63  
    64  func (btc *BurrowTendermintConfig) Config(rootDir string, timeoutFactor float64) (*tmConfig.Config, error) {
    65  	conf := tmConfig.DefaultConfig()
    66  	// We expose Tendermint config as required, but try to give fewer levers to pull where possible
    67  	if btc != nil {
    68  		conf.RootDir = rootDir
    69  		conf.Mempool.RootDir = rootDir
    70  		conf.Consensus.RootDir = rootDir
    71  
    72  		// Transactions
    73  		// This creates load on leveldb for no purpose. The default indexer is "kv" and allows retrieval the TxResult
    74  		// for which we use use TxReceipt (returned from ABCI DeliverTx) - we have our own much richer index
    75  		conf.TxIndex.Indexer = "null"
    76  		conf.Mempool.MaxTxBytes = 1024 * 1024 * 4 // 4MB
    77  
    78  		// Consensus
    79  		switch strings.ToLower(btc.CreateEmptyBlocks) {
    80  		case NeverCreateEmptyBlocks, "":
    81  			conf.Consensus.CreateEmptyBlocks = false
    82  		case AlwaysCreateEmptyBlocks:
    83  			conf.Consensus.CreateEmptyBlocks = true
    84  		default:
    85  			conf.Consensus.CreateEmptyBlocks = true
    86  			createEmptyBlocksInterval, err := time.ParseDuration(btc.CreateEmptyBlocks)
    87  			if err != nil {
    88  				return nil, fmt.Errorf("could not parse CreateEmptyBlock '%s' "+
    89  					"as '%s', '%s', or duration (e.g. 1s, 2m, 4h): %v",
    90  					btc.CreateEmptyBlocks, NeverCreateEmptyBlocks, AlwaysCreateEmptyBlocks, err)
    91  			}
    92  			conf.Consensus.CreateEmptyBlocksInterval = createEmptyBlocksInterval
    93  		}
    94  		// Assume Tendermint has some mutually consistent values, assume scaling them linearly makes sense
    95  		conf.Consensus.TimeoutPropose = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutPropose)
    96  		conf.Consensus.TimeoutProposeDelta = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutProposeDelta)
    97  		conf.Consensus.TimeoutPrevote = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutPrevote)
    98  		conf.Consensus.TimeoutPrevoteDelta = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutPrevoteDelta)
    99  		conf.Consensus.TimeoutPrecommit = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutPrecommit)
   100  		conf.Consensus.TimeoutPrecommitDelta = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutPrecommitDelta)
   101  		conf.Consensus.TimeoutCommit = scaleTimeout(timeoutFactor, conf.Consensus.TimeoutCommit)
   102  
   103  		// P2P
   104  		conf.Moniker = btc.Moniker
   105  		conf.P2P.RootDir = rootDir
   106  		conf.P2P.Seeds = btc.Seeds
   107  		conf.P2P.SeedMode = btc.SeedMode
   108  		conf.P2P.PersistentPeers = btc.PersistentPeers
   109  		conf.P2P.ListenAddress = btc.ListenAddress()
   110  		conf.P2P.ExternalAddress = btc.ExternalAddress
   111  		conf.P2P.AddrBookStrict = btc.AddrBookStrict
   112  		// We use this in tests and I am not aware of a strong reason to reject nodes on the same IP with different ports
   113  		conf.P2P.AllowDuplicateIP = true
   114  
   115  		// Unfortunately this stops metrics from being used at all
   116  		conf.Instrumentation.Prometheus = false
   117  
   118  		conf.FilterPeers = btc.IdentifyPeers || btc.AuthorizedPeers != ""
   119  	}
   120  	// Disable Tendermint RPC
   121  	conf.RPC.ListenAddress = ""
   122  	return conf, nil
   123  }
   124  
   125  func (btc *BurrowTendermintConfig) DefaultAuthorizedPeersProvider() abci.AuthorizedPeers {
   126  	authorizedPeers := abci.NewPeerLists()
   127  
   128  	authorizedPeersAddrOrID := strings.Split(btc.AuthorizedPeers, ",")
   129  	for _, authorizedPeerAddrOrID := range authorizedPeersAddrOrID {
   130  		_, err := url.Parse(authorizedPeerAddrOrID)
   131  		isNodeAddress := err != nil
   132  		if isNodeAddress {
   133  			authorizedPeers.Addresses[authorizedPeerAddrOrID] = struct{}{}
   134  		} else {
   135  			authorizedPeers.IDs[authorizedPeerAddrOrID] = struct{}{}
   136  		}
   137  	}
   138  
   139  	return authorizedPeers
   140  }
   141  
   142  func scaleTimeout(factor float64, timeout time.Duration) time.Duration {
   143  	if factor == 0 {
   144  		return timeout
   145  	}
   146  	return time.Duration(math.Round(factor * float64(timeout)))
   147  }
   148  
   149  func (btc *BurrowTendermintConfig) ListenAddress() string {
   150  	return net.JoinHostPort(btc.ListenHost, btc.ListenPort)
   151  }