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 }