You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

472 lines
14 KiB

7 years ago
7 years ago
p2p: introduce peerConn to simplify peer creation (#1226) * expose AuthEnc in the P2P config if AuthEnc is true, dialed peers must have a node ID in the address and it must match the persistent pubkey from the secret handshake. Refs #1157 * fixes after my own review * fix docs * fix build failure ``` p2p/pex/pex_reactor_test.go:288:88: cannot use seed.NodeInfo().NetAddress() (type *p2p.NetAddress) as type string in array or slice literal ``` * p2p: introduce peerConn to simplify peer creation * Introduce `peerConn` containing the known fields of `peer` * `peer` only created in `sw.addPeer` once handshake is complete and NodeInfo is checked * Eliminates some mutable variables and makes the code flow better * Simplifies the `newXxxPeer` funcs * Use ID instead of PubKey where possible. * SetPubKeyFilter -> SetIDFilter * nodeInfo.Validate takes ID * remove peer.PubKey() * persistent node ids * fixes from review * test: use ip_plus_id.sh more * fix invalid memory panic during fast_sync test ``` 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: panic: runtime error: invalid memory address or nil pointer dereference 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x98dd3e] 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: goroutine 3432 [running]: 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.newOutboundPeerConn(0xc423fd1380, 0xc420933e00, 0x1, 0x1239a60, 0 xc420128c40, 0x2, 0x42caf6, 0xc42001f300, 0xc422831d98, 0xc4227951c0, ...) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/peer.go:123 +0x31e 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).addOutboundPeerWithConfig(0xc4200ad040, 0xc423fd1380, 0 xc420933e00, 0xc423f48801, 0x28, 0x2) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:455 +0x12b 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).DialPeerWithAddress(0xc4200ad040, 0xc423fd1380, 0x1, 0x 0, 0x0) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:371 +0xdc 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).reconnectToPeer(0xc4200ad040, 0x123e000, 0xc42007bb00) 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:290 +0x25f 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: created by github.com/tendermint/tendermint/p2p.(*Switch).StopPeerForError 2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:256 +0x1b7 ```
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "sync"
  9. "time"
  10. crypto "github.com/tendermint/go-crypto"
  11. cmn "github.com/tendermint/tmlibs/common"
  12. )
  13. // TODO: type ?
  14. const (
  15. stepNone int8 = 0 // Used to distinguish the initial state
  16. stepPropose int8 = 1
  17. stepPrevote int8 = 2
  18. stepPrecommit int8 = 3
  19. )
  20. func voteToStep(vote *Vote) int8 {
  21. switch vote.Type {
  22. case VoteTypePrevote:
  23. return stepPrevote
  24. case VoteTypePrecommit:
  25. return stepPrecommit
  26. default:
  27. cmn.PanicSanity("Unknown vote type")
  28. return 0
  29. }
  30. }
  31. //--------------------------------------------------------------
  32. // PrivValidator is being upgraded! See types/priv_validator/
  33. // ValidatorID contains the identity of the validator.
  34. type ValidatorID struct {
  35. Address cmn.HexBytes `json:"address"`
  36. PubKey crypto.PubKey `json:"pub_key"`
  37. }
  38. // PrivValidator defines the functionality of a local Tendermint validator
  39. // that signs votes, proposals, and heartbeats, and never double signs.
  40. type PrivValidator2 interface {
  41. Address() (Address, error) // redundant since .PubKey().Address()
  42. PubKey() (crypto.PubKey, error)
  43. SignVote(chainID string, vote *Vote) error
  44. SignProposal(chainID string, proposal *Proposal) error
  45. SignHeartbeat(chainID string, heartbeat *Heartbeat) error
  46. }
  47. type TestSigner interface {
  48. Address() cmn.HexBytes
  49. PubKey() crypto.PubKey
  50. Sign([]byte) (crypto.Signature, error)
  51. }
  52. func GenSigner() TestSigner {
  53. return &DefaultTestSigner{
  54. crypto.GenPrivKeyEd25519().Wrap(),
  55. }
  56. }
  57. type DefaultTestSigner struct {
  58. crypto.PrivKey
  59. }
  60. func (ds *DefaultTestSigner) Address() cmn.HexBytes {
  61. return ds.PubKey().Address()
  62. }
  63. func (ds *DefaultTestSigner) PubKey() crypto.PubKey {
  64. return ds.PrivKey.PubKey()
  65. }
  66. func (ds *DefaultTestSigner) Sign(msg []byte) (crypto.Signature, error) {
  67. return ds.PrivKey.Sign(msg), nil
  68. }
  69. //--------------------------------------------------------------
  70. // TODO: Deprecate!
  71. // PrivValidator defines the functionality of a local Tendermint validator
  72. // that signs votes, proposals, and heartbeats, and never double signs.
  73. type PrivValidator interface {
  74. GetAddress() Address // redundant since .PubKey().Address()
  75. GetPubKey() crypto.PubKey
  76. SignVote(chainID string, vote *Vote) error
  77. SignProposal(chainID string, proposal *Proposal) error
  78. SignHeartbeat(chainID string, heartbeat *Heartbeat) error
  79. }
  80. // PrivValidatorFS implements PrivValidator using data persisted to disk
  81. // to prevent double signing. The Signer itself can be mutated to use
  82. // something besides the default, for instance a hardware signer.
  83. type PrivValidatorFS struct {
  84. Address Address `json:"address"`
  85. PubKey crypto.PubKey `json:"pub_key"`
  86. LastHeight int64 `json:"last_height"`
  87. LastRound int `json:"last_round"`
  88. LastStep int8 `json:"last_step"`
  89. LastSignature crypto.Signature `json:"last_signature,omitempty"` // so we dont lose signatures
  90. LastSignBytes cmn.HexBytes `json:"last_signbytes,omitempty"` // so we dont lose signatures
  91. // PrivKey should be empty if a Signer other than the default is being used.
  92. PrivKey crypto.PrivKey `json:"priv_key"`
  93. Signer `json:"-"`
  94. // For persistence.
  95. // Overloaded for testing.
  96. filePath string
  97. mtx sync.Mutex
  98. }
  99. // Signer is an interface that defines how to sign messages.
  100. // It is the caller's duty to verify the msg before calling Sign,
  101. // eg. to avoid double signing.
  102. // Currently, the only callers are SignVote, SignProposal, and SignHeartbeat.
  103. type Signer interface {
  104. Sign(msg []byte) (crypto.Signature, error)
  105. }
  106. // DefaultSigner implements Signer.
  107. // It uses a standard, unencrypted crypto.PrivKey.
  108. type DefaultSigner struct {
  109. PrivKey crypto.PrivKey `json:"priv_key"`
  110. }
  111. // NewDefaultSigner returns an instance of DefaultSigner.
  112. func NewDefaultSigner(priv crypto.PrivKey) *DefaultSigner {
  113. return &DefaultSigner{
  114. PrivKey: priv,
  115. }
  116. }
  117. // Sign implements Signer. It signs the byte slice with a private key.
  118. func (ds *DefaultSigner) Sign(msg []byte) (crypto.Signature, error) {
  119. return ds.PrivKey.Sign(msg), nil
  120. }
  121. // GetAddress returns the address of the validator.
  122. // Implements PrivValidator.
  123. func (pv *PrivValidatorFS) GetAddress() Address {
  124. return pv.Address
  125. }
  126. // GetPubKey returns the public key of the validator.
  127. // Implements PrivValidator.
  128. func (pv *PrivValidatorFS) GetPubKey() crypto.PubKey {
  129. return pv.PubKey
  130. }
  131. // GenPrivValidatorFS generates a new validator with randomly generated private key
  132. // and sets the filePath, but does not call Save().
  133. func GenPrivValidatorFS(filePath string) *PrivValidatorFS {
  134. privKey := crypto.GenPrivKeyEd25519().Wrap()
  135. return &PrivValidatorFS{
  136. Address: privKey.PubKey().Address(),
  137. PubKey: privKey.PubKey(),
  138. PrivKey: privKey,
  139. LastStep: stepNone,
  140. Signer: NewDefaultSigner(privKey),
  141. filePath: filePath,
  142. }
  143. }
  144. // LoadPrivValidatorFS loads a PrivValidatorFS from the filePath.
  145. func LoadPrivValidatorFS(filePath string) *PrivValidatorFS {
  146. return LoadPrivValidatorFSWithSigner(filePath, func(privVal PrivValidator) Signer {
  147. return NewDefaultSigner(privVal.(*PrivValidatorFS).PrivKey)
  148. })
  149. }
  150. // LoadOrGenPrivValidatorFS loads a PrivValidatorFS from the given filePath
  151. // or else generates a new one and saves it to the filePath.
  152. func LoadOrGenPrivValidatorFS(filePath string) *PrivValidatorFS {
  153. var privVal *PrivValidatorFS
  154. if cmn.FileExists(filePath) {
  155. privVal = LoadPrivValidatorFS(filePath)
  156. } else {
  157. privVal = GenPrivValidatorFS(filePath)
  158. privVal.Save()
  159. }
  160. return privVal
  161. }
  162. // LoadPrivValidatorWithSigner loads a PrivValidatorFS with a custom
  163. // signer object. The PrivValidatorFS handles double signing prevention by persisting
  164. // data to the filePath, while the Signer handles the signing.
  165. // If the filePath does not exist, the PrivValidatorFS must be created manually and saved.
  166. func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(PrivValidator) Signer) *PrivValidatorFS {
  167. privValJSONBytes, err := ioutil.ReadFile(filePath)
  168. if err != nil {
  169. cmn.Exit(err.Error())
  170. }
  171. privVal := &PrivValidatorFS{}
  172. err = json.Unmarshal(privValJSONBytes, &privVal)
  173. if err != nil {
  174. cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
  175. }
  176. privVal.filePath = filePath
  177. privVal.Signer = signerFunc(privVal)
  178. return privVal
  179. }
  180. // Save persists the PrivValidatorFS to disk.
  181. func (privVal *PrivValidatorFS) Save() {
  182. privVal.mtx.Lock()
  183. defer privVal.mtx.Unlock()
  184. privVal.save()
  185. }
  186. func (privVal *PrivValidatorFS) save() {
  187. if privVal.filePath == "" {
  188. cmn.PanicSanity("Cannot save PrivValidator: filePath not set")
  189. }
  190. jsonBytes, err := json.Marshal(privVal)
  191. if err != nil {
  192. // `@; BOOM!!!
  193. cmn.PanicCrisis(err)
  194. }
  195. err = cmn.WriteFileAtomic(privVal.filePath, jsonBytes, 0600)
  196. if err != nil {
  197. // `@; BOOM!!!
  198. cmn.PanicCrisis(err)
  199. }
  200. }
  201. // Reset resets all fields in the PrivValidatorFS.
  202. // NOTE: Unsafe!
  203. func (privVal *PrivValidatorFS) Reset() {
  204. var sig crypto.Signature
  205. privVal.LastHeight = 0
  206. privVal.LastRound = 0
  207. privVal.LastStep = 0
  208. privVal.LastSignature = sig
  209. privVal.LastSignBytes = nil
  210. privVal.Save()
  211. }
  212. // SignVote signs a canonical representation of the vote, along with the
  213. // chainID. Implements PrivValidator.
  214. func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error {
  215. privVal.mtx.Lock()
  216. defer privVal.mtx.Unlock()
  217. if err := privVal.signVote(chainID, vote); err != nil {
  218. return errors.New(cmn.Fmt("Error signing vote: %v", err))
  219. }
  220. return nil
  221. }
  222. // SignProposal signs a canonical representation of the proposal, along with
  223. // the chainID. Implements PrivValidator.
  224. func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error {
  225. privVal.mtx.Lock()
  226. defer privVal.mtx.Unlock()
  227. if err := privVal.signProposal(chainID, proposal); err != nil {
  228. return fmt.Errorf("Error signing proposal: %v", err)
  229. }
  230. return nil
  231. }
  232. // returns error if HRS regression or no LastSignBytes. returns true if HRS is unchanged
  233. func (privVal *PrivValidatorFS) checkHRS(height int64, round int, step int8) (bool, error) {
  234. if privVal.LastHeight > height {
  235. return false, errors.New("Height regression")
  236. }
  237. if privVal.LastHeight == height {
  238. if privVal.LastRound > round {
  239. return false, errors.New("Round regression")
  240. }
  241. if privVal.LastRound == round {
  242. if privVal.LastStep > step {
  243. return false, errors.New("Step regression")
  244. } else if privVal.LastStep == step {
  245. if privVal.LastSignBytes != nil {
  246. if privVal.LastSignature.Empty() {
  247. panic("privVal: LastSignature is nil but LastSignBytes is not!")
  248. }
  249. return true, nil
  250. }
  251. return false, errors.New("No LastSignature found")
  252. }
  253. }
  254. }
  255. return false, nil
  256. }
  257. // signVote checks if the vote is good to sign and sets the vote signature.
  258. // It may need to set the timestamp as well if the vote is otherwise the same as
  259. // a previously signed vote (ie. we crashed after signing but before the vote hit the WAL).
  260. func (privVal *PrivValidatorFS) signVote(chainID string, vote *Vote) error {
  261. height, round, step := vote.Height, vote.Round, voteToStep(vote)
  262. signBytes := vote.SignBytes(chainID)
  263. sameHRS, err := privVal.checkHRS(height, round, step)
  264. if err != nil {
  265. return err
  266. }
  267. // We might crash before writing to the wal,
  268. // causing us to try to re-sign for the same HRS.
  269. // If signbytes are the same, use the last signature.
  270. // If they only differ by timestamp, use last timestamp and signature
  271. // Otherwise, return error
  272. if sameHRS {
  273. if bytes.Equal(signBytes, privVal.LastSignBytes) {
  274. vote.Signature = privVal.LastSignature
  275. } else if timestamp, ok := checkVotesOnlyDifferByTimestamp(privVal.LastSignBytes, signBytes); ok {
  276. vote.Timestamp = timestamp
  277. vote.Signature = privVal.LastSignature
  278. } else {
  279. err = fmt.Errorf("Conflicting data")
  280. }
  281. return err
  282. }
  283. // It passed the checks. Sign the vote
  284. sig, err := privVal.Sign(signBytes)
  285. if err != nil {
  286. return err
  287. }
  288. privVal.saveSigned(height, round, step, signBytes, sig)
  289. vote.Signature = sig
  290. return nil
  291. }
  292. // signProposal checks if the proposal is good to sign and sets the proposal signature.
  293. // It may need to set the timestamp as well if the proposal is otherwise the same as
  294. // a previously signed proposal ie. we crashed after signing but before the proposal hit the WAL).
  295. func (privVal *PrivValidatorFS) signProposal(chainID string, proposal *Proposal) error {
  296. height, round, step := proposal.Height, proposal.Round, stepPropose
  297. signBytes := proposal.SignBytes(chainID)
  298. sameHRS, err := privVal.checkHRS(height, round, step)
  299. if err != nil {
  300. return err
  301. }
  302. // We might crash before writing to the wal,
  303. // causing us to try to re-sign for the same HRS.
  304. // If signbytes are the same, use the last signature.
  305. // If they only differ by timestamp, use last timestamp and signature
  306. // Otherwise, return error
  307. if sameHRS {
  308. if bytes.Equal(signBytes, privVal.LastSignBytes) {
  309. proposal.Signature = privVal.LastSignature
  310. } else if timestamp, ok := checkProposalsOnlyDifferByTimestamp(privVal.LastSignBytes, signBytes); ok {
  311. proposal.Timestamp = timestamp
  312. proposal.Signature = privVal.LastSignature
  313. } else {
  314. err = fmt.Errorf("Conflicting data")
  315. }
  316. return err
  317. }
  318. // It passed the checks. Sign the proposal
  319. sig, err := privVal.Sign(signBytes)
  320. if err != nil {
  321. return err
  322. }
  323. privVal.saveSigned(height, round, step, signBytes, sig)
  324. proposal.Signature = sig
  325. return nil
  326. }
  327. // Persist height/round/step and signature
  328. func (privVal *PrivValidatorFS) saveSigned(height int64, round int, step int8,
  329. signBytes []byte, sig crypto.Signature) {
  330. privVal.LastHeight = height
  331. privVal.LastRound = round
  332. privVal.LastStep = step
  333. privVal.LastSignature = sig
  334. privVal.LastSignBytes = signBytes
  335. privVal.save()
  336. }
  337. // SignHeartbeat signs a canonical representation of the heartbeat, along with the chainID.
  338. // Implements PrivValidator.
  339. func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
  340. privVal.mtx.Lock()
  341. defer privVal.mtx.Unlock()
  342. var err error
  343. heartbeat.Signature, err = privVal.Sign(heartbeat.SignBytes(chainID))
  344. return err
  345. }
  346. // String returns a string representation of the PrivValidatorFS.
  347. func (privVal *PrivValidatorFS) String() string {
  348. return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.GetAddress(), privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  349. }
  350. //-------------------------------------
  351. type PrivValidatorsByAddress []*PrivValidatorFS
  352. func (pvs PrivValidatorsByAddress) Len() int {
  353. return len(pvs)
  354. }
  355. func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
  356. return bytes.Compare(pvs[i].GetAddress(), pvs[j].GetAddress()) == -1
  357. }
  358. func (pvs PrivValidatorsByAddress) Swap(i, j int) {
  359. it := pvs[i]
  360. pvs[i] = pvs[j]
  361. pvs[j] = it
  362. }
  363. //-------------------------------------
  364. // returns the timestamp from the lastSignBytes.
  365. // returns true if the only difference in the votes is their timestamp.
  366. func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
  367. var lastVote, newVote CanonicalJSONOnceVote
  368. if err := json.Unmarshal(lastSignBytes, &lastVote); err != nil {
  369. panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err))
  370. }
  371. if err := json.Unmarshal(newSignBytes, &newVote); err != nil {
  372. panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err))
  373. }
  374. lastTime, err := time.Parse(TimeFormat, lastVote.Vote.Timestamp)
  375. if err != nil {
  376. panic(err)
  377. }
  378. // set the times to the same value and check equality
  379. now := CanonicalTime(time.Now())
  380. lastVote.Vote.Timestamp = now
  381. newVote.Vote.Timestamp = now
  382. lastVoteBytes, _ := json.Marshal(lastVote)
  383. newVoteBytes, _ := json.Marshal(newVote)
  384. return lastTime, bytes.Equal(newVoteBytes, lastVoteBytes)
  385. }
  386. // returns the timestamp from the lastSignBytes.
  387. // returns true if the only difference in the proposals is their timestamp
  388. func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
  389. var lastProposal, newProposal CanonicalJSONOnceProposal
  390. if err := json.Unmarshal(lastSignBytes, &lastProposal); err != nil {
  391. panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into proposal: %v", err))
  392. }
  393. if err := json.Unmarshal(newSignBytes, &newProposal); err != nil {
  394. panic(fmt.Sprintf("signBytes cannot be unmarshalled into proposal: %v", err))
  395. }
  396. lastTime, err := time.Parse(TimeFormat, lastProposal.Proposal.Timestamp)
  397. if err != nil {
  398. panic(err)
  399. }
  400. // set the times to the same value and check equality
  401. now := CanonicalTime(time.Now())
  402. lastProposal.Proposal.Timestamp = now
  403. newProposal.Proposal.Timestamp = now
  404. lastProposalBytes, _ := json.Marshal(lastProposal)
  405. newProposalBytes, _ := json.Marshal(newProposal)
  406. return lastTime, bytes.Equal(newProposalBytes, lastProposalBytes)
  407. }