types.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package adapters
  17. import (
  18. "crypto/ecdsa"
  19. "encoding/hex"
  20. "encoding/json"
  21. "fmt"
  22. "net"
  23. "os"
  24. "strconv"
  25. "github.com/docker/docker/pkg/reexec"
  26. "github.com/ethereum/go-ethereum/crypto"
  27. "github.com/ethereum/go-ethereum/log"
  28. "github.com/ethereum/go-ethereum/node"
  29. "github.com/ethereum/go-ethereum/p2p"
  30. "github.com/ethereum/go-ethereum/p2p/enode"
  31. "github.com/ethereum/go-ethereum/p2p/enr"
  32. "github.com/ethereum/go-ethereum/rpc"
  33. "github.com/gorilla/websocket"
  34. )
  35. // Node represents a node in a simulation network which is created by a
  36. // NodeAdapter, for example:
  37. //
  38. // * SimNode - An in-memory node
  39. // * ExecNode - A child process node
  40. // * DockerNode - A Docker container node
  41. //
  42. type Node interface {
  43. // Addr returns the node's address (e.g. an Enode URL)
  44. Addr() []byte
  45. // Client returns the RPC client which is created once the node is
  46. // up and running
  47. Client() (*rpc.Client, error)
  48. // ServeRPC serves RPC requests over the given connection
  49. ServeRPC(*websocket.Conn) error
  50. // Start starts the node with the given snapshots
  51. Start(snapshots map[string][]byte) error
  52. // Stop stops the node
  53. Stop() error
  54. // NodeInfo returns information about the node
  55. NodeInfo() *p2p.NodeInfo
  56. // Snapshots creates snapshots of the running services
  57. Snapshots() (map[string][]byte, error)
  58. }
  59. // NodeAdapter is used to create Nodes in a simulation network
  60. type NodeAdapter interface {
  61. // Name returns the name of the adapter for logging purposes
  62. Name() string
  63. // NewNode creates a new node with the given configuration
  64. NewNode(config *NodeConfig) (Node, error)
  65. }
  66. // NodeConfig is the configuration used to start a node in a simulation
  67. // network
  68. type NodeConfig struct {
  69. // ID is the node's ID which is used to identify the node in the
  70. // simulation network
  71. ID enode.ID
  72. // PrivateKey is the node's private key which is used by the devp2p
  73. // stack to encrypt communications
  74. PrivateKey *ecdsa.PrivateKey
  75. // Enable peer events for Msgs
  76. EnableMsgEvents bool
  77. // Name is a human friendly name for the node like "node01"
  78. Name string
  79. // Use an existing database instead of a temporary one if non-empty
  80. DataDir string
  81. // Lifecycles are the names of the service lifecycles which should be run when
  82. // starting the node (for SimNodes it should be the names of service lifecycles
  83. // contained in SimAdapter.lifecycles, for other nodes it should be
  84. // service lifecycles registered by calling the RegisterLifecycle function)
  85. Lifecycles []string
  86. // Properties are the names of the properties this node should hold
  87. // within running services (e.g. "bootnode", "lightnode" or any custom values)
  88. // These values need to be checked and acted upon by node Services
  89. Properties []string
  90. // ExternalSigner specifies an external URI for a clef-type signer
  91. ExternalSigner string
  92. // Enode
  93. node *enode.Node
  94. // ENR Record with entries to overwrite
  95. Record enr.Record
  96. // function to sanction or prevent suggesting a peer
  97. Reachable func(id enode.ID) bool
  98. Port uint16
  99. // LogFile is the log file name of the p2p node at runtime.
  100. //
  101. // The default value is empty so that the default log writer
  102. // is the system standard output.
  103. LogFile string
  104. // LogVerbosity is the log verbosity of the p2p node at runtime.
  105. //
  106. // The default verbosity is INFO.
  107. LogVerbosity log.Lvl
  108. }
  109. // nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding
  110. // all fields as strings
  111. type nodeConfigJSON struct {
  112. ID string `json:"id"`
  113. PrivateKey string `json:"private_key"`
  114. Name string `json:"name"`
  115. Lifecycles []string `json:"lifecycles"`
  116. Properties []string `json:"properties"`
  117. EnableMsgEvents bool `json:"enable_msg_events"`
  118. Port uint16 `json:"port"`
  119. LogFile string `json:"logfile"`
  120. LogVerbosity int `json:"log_verbosity"`
  121. }
  122. // MarshalJSON implements the json.Marshaler interface by encoding the config
  123. // fields as strings
  124. func (n *NodeConfig) MarshalJSON() ([]byte, error) {
  125. confJSON := nodeConfigJSON{
  126. ID: n.ID.String(),
  127. Name: n.Name,
  128. Lifecycles: n.Lifecycles,
  129. Properties: n.Properties,
  130. Port: n.Port,
  131. EnableMsgEvents: n.EnableMsgEvents,
  132. LogFile: n.LogFile,
  133. LogVerbosity: int(n.LogVerbosity),
  134. }
  135. if n.PrivateKey != nil {
  136. confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey))
  137. }
  138. return json.Marshal(confJSON)
  139. }
  140. // UnmarshalJSON implements the json.Unmarshaler interface by decoding the json
  141. // string values into the config fields
  142. func (n *NodeConfig) UnmarshalJSON(data []byte) error {
  143. var confJSON nodeConfigJSON
  144. if err := json.Unmarshal(data, &confJSON); err != nil {
  145. return err
  146. }
  147. if confJSON.ID != "" {
  148. if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil {
  149. return err
  150. }
  151. }
  152. if confJSON.PrivateKey != "" {
  153. key, err := hex.DecodeString(confJSON.PrivateKey)
  154. if err != nil {
  155. return err
  156. }
  157. privKey, err := crypto.ToECDSA(key)
  158. if err != nil {
  159. return err
  160. }
  161. n.PrivateKey = privKey
  162. }
  163. n.Name = confJSON.Name
  164. n.Lifecycles = confJSON.Lifecycles
  165. n.Properties = confJSON.Properties
  166. n.Port = confJSON.Port
  167. n.EnableMsgEvents = confJSON.EnableMsgEvents
  168. n.LogFile = confJSON.LogFile
  169. n.LogVerbosity = log.Lvl(confJSON.LogVerbosity)
  170. return nil
  171. }
  172. // Node returns the node descriptor represented by the config.
  173. func (n *NodeConfig) Node() *enode.Node {
  174. return n.node
  175. }
  176. // RandomNodeConfig returns node configuration with a randomly generated ID and
  177. // PrivateKey
  178. func RandomNodeConfig() *NodeConfig {
  179. prvkey, err := crypto.GenerateKey()
  180. if err != nil {
  181. panic("unable to generate key")
  182. }
  183. port, err := assignTCPPort()
  184. if err != nil {
  185. panic("unable to assign tcp port")
  186. }
  187. enodId := enode.PubkeyToIDV4(&prvkey.PublicKey)
  188. return &NodeConfig{
  189. PrivateKey: prvkey,
  190. ID: enodId,
  191. Name: fmt.Sprintf("node_%s", enodId.String()),
  192. Port: port,
  193. EnableMsgEvents: true,
  194. LogVerbosity: log.LvlInfo,
  195. }
  196. }
  197. func assignTCPPort() (uint16, error) {
  198. l, err := net.Listen("tcp", "127.0.0.1:0")
  199. if err != nil {
  200. return 0, err
  201. }
  202. l.Close()
  203. _, port, err := net.SplitHostPort(l.Addr().String())
  204. if err != nil {
  205. return 0, err
  206. }
  207. p, err := strconv.ParseUint(port, 10, 16)
  208. if err != nil {
  209. return 0, err
  210. }
  211. return uint16(p), nil
  212. }
  213. // ServiceContext is a collection of options and methods which can be utilised
  214. // when starting services
  215. type ServiceContext struct {
  216. RPCDialer
  217. Config *NodeConfig
  218. Snapshot []byte
  219. }
  220. // RPCDialer is used when initialising services which need to connect to
  221. // other nodes in the network (for example a simulated Swarm node which needs
  222. // to connect to a Geth node to resolve ENS names)
  223. type RPCDialer interface {
  224. DialRPC(id enode.ID) (*rpc.Client, error)
  225. }
  226. // LifecycleConstructor allows a Lifecycle to be constructed during node start-up.
  227. // While the service-specific package usually takes care of Lifecycle creation and registration,
  228. // for testing purposes, it is useful to be able to construct a Lifecycle on spot.
  229. type LifecycleConstructor func(ctx *ServiceContext, stack *node.Node) (node.Lifecycle, error)
  230. // LifecycleConstructors stores LifecycleConstructor functions to call during node start-up.
  231. type LifecycleConstructors map[string]LifecycleConstructor
  232. // lifecycleConstructorFuncs is a map of registered services which are used to boot devp2p
  233. // nodes
  234. var lifecycleConstructorFuncs = make(LifecycleConstructors)
  235. // RegisterLifecycles registers the given Services which can then be used to
  236. // start devp2p nodes using either the Exec or Docker adapters.
  237. //
  238. // It should be called in an init function so that it has the opportunity to
  239. // execute the services before main() is called.
  240. func RegisterLifecycles(lifecycles LifecycleConstructors) {
  241. for name, f := range lifecycles {
  242. if _, exists := lifecycleConstructorFuncs[name]; exists {
  243. panic(fmt.Sprintf("node service already exists: %q", name))
  244. }
  245. lifecycleConstructorFuncs[name] = f
  246. }
  247. // now we have registered the services, run reexec.Init() which will
  248. // potentially start one of the services if the current binary has
  249. // been exec'd with argv[0] set to "p2p-node"
  250. if reexec.Init() {
  251. os.Exit(0)
  252. }
  253. }
  254. // adds the host part to the configuration's ENR, signs it
  255. // creates and the corresponding enode object to the configuration
  256. func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error {
  257. enrIp := enr.IP(ip)
  258. n.Record.Set(&enrIp)
  259. enrTcpPort := enr.TCP(tcpport)
  260. n.Record.Set(&enrTcpPort)
  261. enrUdpPort := enr.UDP(udpport)
  262. n.Record.Set(&enrUdpPort)
  263. err := enode.SignV4(&n.Record, n.PrivateKey)
  264. if err != nil {
  265. return fmt.Errorf("unable to generate ENR: %v", err)
  266. }
  267. nod, err := enode.New(enode.V4ID{}, &n.Record)
  268. if err != nil {
  269. return fmt.Errorf("unable to create enode: %v", err)
  270. }
  271. log.Trace("simnode new", "record", n.Record)
  272. n.node = nod
  273. return nil
  274. }
  275. func (n *NodeConfig) initDummyEnode() error {
  276. return n.initEnode(net.IPv4(127, 0, 0, 1), int(n.Port), 0)
  277. }