github.com/annchain/OG@v0.0.9/node/config.go (about) 1 // Copyright © 2019 Annchain Authors <EMAIL ADDRESS> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package node 15 16 import ( 17 "bytes" 18 "crypto/ecdsa" 19 "encoding/hex" 20 "encoding/json" 21 "fmt" 22 "github.com/annchain/OG/arefactor/common/io" 23 "github.com/annchain/OG/common/crypto" 24 ogcrypto2 "github.com/annchain/OG/deprecated/ogcrypto" 25 "github.com/annchain/OG/p2p" 26 "github.com/annchain/OG/p2p/discv5" 27 "github.com/annchain/OG/p2p/nat" 28 "github.com/annchain/OG/p2p/onode" 29 log "github.com/sirupsen/logrus" 30 "github.com/spf13/viper" 31 "io/ioutil" 32 "net" 33 "net/http" 34 "os" 35 "strconv" 36 "strings" 37 "time" 38 ) 39 40 const ( 41 datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key 42 defaultMaxPeers = 50 43 defaultNetworkId = 1 44 ) 45 46 type BootstrapInfoRequest struct { 47 NetworkId int64 `json:"networkid"` 48 PublicKey string `json:"publickey"` 49 ONode string `json:"onode"` 50 } 51 52 type BootstrapInfoResponse struct { 53 Status string `json:"status"` 54 BootstrapNode bool `json:"bootstrap_node"` 55 BootstrapNodes string `json:"bootstrap_nodes"` 56 GenesisPk string `json:"genesis_pk"` 57 Message string `json:"message"` 58 Partners int `json:"partners"` 59 } 60 61 func getNodePrivKey() *ecdsa.PrivateKey { 62 nodeKey := viper.GetString("p2p.node_key") 63 if nodeKey != "" { 64 keyByte, err := hex.DecodeString(nodeKey) 65 if err != nil { 66 panic(fmt.Sprintf("get nodekey error %v ", err)) 67 } 68 key, err := ogcrypto2.ToECDSA(keyByte) 69 if err != nil { 70 panic(fmt.Sprintf("get nodekey error %v ", err)) 71 } 72 return key 73 } 74 dataDir := viper.GetString("datadir") 75 // Use any specifically configured key. 76 77 keyFile := io.FixPrefixPath(dataDir, datadirPrivateKey) 78 if key, err := ogcrypto2.LoadECDSA(keyFile); err == nil { 79 return key 80 } 81 // No persistent key found, generate and store a new one. 82 key, err := ogcrypto2.GenerateKey() 83 if err != nil { 84 panic(fmt.Sprintf("failed to generate node key: %v", err)) 85 } 86 if err := os.MkdirAll(dataDir, 0700); err != nil { 87 log.Error(fmt.Sprintf("failed to persist node key: %v", err)) 88 return key 89 } 90 if err := ogcrypto2.SaveECDSA(keyFile, key); err != nil { 91 log.Error(fmt.Sprintf("failed to persist node key: %v", err)) 92 } 93 data := ogcrypto2.FromECDSA(key) 94 viper.SetDefault("p2p.node_key", hex.EncodeToString(data)) 95 return key 96 } 97 98 func getOnodeURL(privKey *ecdsa.PrivateKey) string { 99 port := viper.GetString("p2p.port") 100 tcpPort, _ := strconv.Atoi(port) 101 ogNode := onode.NewV4(&privKey.PublicKey, net.ParseIP("127.0.0.1"), tcpPort, tcpPort) 102 // if I got the hostname from env (given by kubernetes), use it as my URL 103 // Make sure the hostname is mapped to this pod by kubernetes's Service 104 // Or the IP will be refreshed after restarting the pod 105 s := ogNode.String() 106 if v, ok := os.LookupEnv("HOSTNAME"); ok { 107 s = strings.Replace(s, "127.0.0.1", v, 1) 108 } 109 return s 110 } 111 112 func NewP2PServer(privKey *ecdsa.PrivateKey, isBootNode bool) *p2p.Server { 113 var p2pConfig p2p.Config 114 p2pConfig.PrivateKey = privKey 115 port := viper.GetString("p2p.port") 116 p2pConfig.ListenAddr = ":" + port 117 maxPeers := viper.GetInt("p2p.max_peers") 118 if maxPeers <= 0 { 119 maxPeers = defaultMaxPeers 120 } 121 p2pConfig.MaxPeers = maxPeers 122 staticNodes := viper.GetString("p2p.static_nodes") 123 p2pConfig.StaticNodes = parserNodes(staticNodes) 124 trustNode := viper.GetString("p2p.trust_nodes") 125 p2pConfig.TrustedNodes = parserNodes(trustNode) 126 nodeName := viper.GetString("p2p.node_name") 127 if nodeName == "" { 128 nodeName = "og" 129 } 130 p2pConfig.NodeName = nodeName 131 p2pConfig.NodeDatabase = viper.GetString("p2p.node_db") 132 bootNodes := viper.GetString("p2p.bootstrap_nodes") 133 bootNodesV5 := viper.GetString("p2p.bootstrap_nodes_v5") 134 p2pConfig.BootstrapNodes = parserNodes(bootNodes) 135 p2pConfig.BootstrapNodesV5 = parserV5Nodes(bootNodesV5) 136 //p2pConfig.NoDiscovery = true 137 //p2pConfig.DiscoveryV5 = true 138 //p2pConfig.BootstrapNodesV5: config.BootstrapNodes.nodes, 139 p2pConfig.NAT = nat.Any() 140 p2pConfig.NoEncryption = viper.GetBool("p2p.no_encryption") 141 142 if isBootNode { 143 tcpPort, err := strconv.Atoi(port) 144 if err != nil { 145 panic(err) 146 } 147 ogNode := onode.NewV4(&privKey.PublicKey, net.ParseIP("127.0.0.1"), tcpPort, tcpPort) 148 viper.SetDefault("p2p.bootstrap_nodes", ogNode.String()) 149 } 150 151 return &p2p.Server{Config: p2pConfig} 152 } 153 154 func parserNodes(nodeString string) []*onode.Node { 155 nodeList := strings.Split(nodeString, ";") 156 var nodes []*onode.Node 157 for _, url := range nodeList { 158 if url == "" { 159 continue 160 } 161 node, err := onode.ParseV4(url) 162 if err != nil { 163 log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) 164 continue 165 } 166 nodes = append(nodes, node) 167 } 168 return nodes 169 } 170 171 func parserV5Nodes(nodeString string) []*discv5.Node { 172 nodeList := strings.Split(nodeString, ";") 173 var nodes []*discv5.Node 174 for _, url := range nodeList { 175 if url == "" { 176 continue 177 } 178 node, err := discv5.ParseNode(url) 179 if err != nil { 180 log.Error(fmt.Sprintf("node URL %s: %v\n", url, err)) 181 continue 182 } 183 nodes = append(nodes, node) 184 } 185 return nodes 186 } 187 188 func parserGenesisAccounts(pubkeys string) []crypto.PublicKey { 189 pubkeyList := strings.Split(pubkeys, ";") 190 var account []crypto.PublicKey 191 for _, pubKeyStr := range pubkeyList { 192 pubKey, err := crypto.PublicKeyFromString(pubKeyStr) 193 if err != nil { 194 panic(err) 195 } 196 account = append(account, pubKey) 197 } 198 return account 199 } 200 201 // buildBootstrap keeps sending info of itself to quering server and wait for other bootstrap server to be ready 202 func buildBootstrap(networkId int64, nodeURL string, key *crypto.PublicKey) { 203 204 pubkey := key.String() 205 206 breq := BootstrapInfoRequest{ 207 NetworkId: networkId, 208 ONode: nodeURL, 209 PublicKey: pubkey, 210 } 211 for { 212 bresp, err := doRequest(breq) 213 if err != nil { 214 log.Warn("failed to get bootstrap config. wait for another 5 seconds") 215 time.Sleep(time.Second * 5) 216 continue 217 } 218 if bresp.Status != "ok" { 219 log.WithField("message", bresp.Message).Info("Consensus group is not ready. waiting for more nodes.") 220 time.Sleep(time.Second * 5) 221 continue 222 } 223 // ready. 224 injectedPath := io.FixPrefixPath(viper.GetString("datadir"), "injected.toml") 225 injectedViper := viper.New() 226 injectedViper.SetConfigType("toml") 227 228 injectedViper.Set("p2p.bootstrap_node", bresp.BootstrapNode) 229 injectedViper.Set("p2p.bootstrap_nodes", bresp.BootstrapNodes) 230 injectedViper.Set("annsensus.genesis_pk", bresp.GenesisPk) 231 injectedViper.Set("annsensus.partner_number", bresp.Partners) 232 injectedViper.Set("annsensus.threshold", 2*bresp.Partners/3+1) 233 234 err = injectedViper.WriteConfigAs(injectedPath) 235 if err != nil { 236 log.WithError(err).Fatal("cannot dump injected config") 237 } 238 err = viper.MergeConfigMap(injectedViper.AllSettings()) 239 if err != nil { 240 log.WithError(err).Fatal("cannot merge injected config") 241 } 242 243 log.WithField("resp", bresp).Info("bootstrap info is updated.") 244 break 245 } 246 247 } 248 249 func doRequest(breq BootstrapInfoRequest) (bresp BootstrapInfoResponse, err error) { 250 url := viper.GetString("p2p.bootstrap_config_server") 251 if url == "" { 252 panic("You must either provide a bootstrap server or provide a bootstrap config server to start building network.") 253 } 254 255 jsonStr, err := json.Marshal(breq) 256 if err != nil { 257 panic("failed to marshal bootstrap request data") 258 } 259 req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) 260 req.Header.Set("Content-Type", "application/json") 261 262 client := &http.Client{ 263 Timeout: time.Second * 10, 264 } 265 defer client.CloseIdleConnections() 266 267 resp, err := client.Do(req) 268 if err != nil { 269 log.WithError(err).Warn("failed to request bootstrap centralized server") 270 return 271 } 272 body, err := ioutil.ReadAll(resp.Body) 273 if err != nil { 274 log.WithError(err).Warn("failed to read response") 275 return 276 } 277 err = json.Unmarshal(body, &bresp) 278 if err != nil { 279 log.WithError(err).Warn("response cannot be unmarshalled") 280 return 281 } 282 return 283 }