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.

377 lines
9.6 KiB

  1. package consensus
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/gogo/protobuf/proto"
  6. cstypes "github.com/tendermint/tendermint/consensus/types"
  7. "github.com/tendermint/tendermint/libs/bits"
  8. tmmath "github.com/tendermint/tendermint/libs/math"
  9. "github.com/tendermint/tendermint/p2p"
  10. tmcons "github.com/tendermint/tendermint/proto/consensus"
  11. tmproto "github.com/tendermint/tendermint/proto/types"
  12. "github.com/tendermint/tendermint/types"
  13. )
  14. // MsgToProto takes a consensus message type and returns the proto defined consensus message
  15. func MsgToProto(msg Message) (*tmcons.Message, error) {
  16. if msg == nil {
  17. return nil, errors.New("consensus: message is nil")
  18. }
  19. var pb tmcons.Message
  20. switch msg := msg.(type) {
  21. case *NewRoundStepMessage:
  22. pb = tmcons.Message{
  23. Sum: &tmcons.Message_NewRoundStep{
  24. NewRoundStep: &tmcons.NewRoundStep{
  25. Height: msg.Height,
  26. Round: msg.Round,
  27. Step: uint32(msg.Step),
  28. SecondsSinceStartTime: msg.SecondsSinceStartTime,
  29. LastCommitRound: msg.LastCommitRound,
  30. },
  31. },
  32. }
  33. case *NewValidBlockMessage:
  34. pbPartsHeader := msg.BlockPartsHeader.ToProto()
  35. pbBits := msg.BlockParts.ToProto()
  36. pb = tmcons.Message{
  37. Sum: &tmcons.Message_NewValidBlock{
  38. NewValidBlock: &tmcons.NewValidBlock{
  39. Height: msg.Height,
  40. Round: msg.Round,
  41. BlockPartsHeader: pbPartsHeader,
  42. BlockParts: pbBits,
  43. IsCommit: msg.IsCommit,
  44. },
  45. },
  46. }
  47. case *ProposalMessage:
  48. pbP := msg.Proposal.ToProto()
  49. pb = tmcons.Message{
  50. Sum: &tmcons.Message_Proposal{
  51. Proposal: &tmcons.Proposal{
  52. Proposal: *pbP,
  53. },
  54. },
  55. }
  56. case *ProposalPOLMessage:
  57. pbBits := msg.ProposalPOL.ToProto()
  58. pb = tmcons.Message{
  59. Sum: &tmcons.Message_ProposalPol{
  60. ProposalPol: &tmcons.ProposalPOL{
  61. Height: msg.Height,
  62. ProposalPolRound: msg.ProposalPOLRound,
  63. ProposalPol: *pbBits,
  64. },
  65. },
  66. }
  67. case *BlockPartMessage:
  68. parts, err := msg.Part.ToProto()
  69. if err != nil {
  70. return nil, fmt.Errorf("msg to proto error: %w", err)
  71. }
  72. pb = tmcons.Message{
  73. Sum: &tmcons.Message_BlockPart{
  74. BlockPart: &tmcons.BlockPart{
  75. Height: msg.Height,
  76. Round: msg.Round,
  77. Part: *parts,
  78. },
  79. },
  80. }
  81. case *VoteMessage:
  82. vote := msg.Vote.ToProto()
  83. pb = tmcons.Message{
  84. Sum: &tmcons.Message_Vote{
  85. Vote: &tmcons.Vote{
  86. Vote: vote,
  87. },
  88. },
  89. }
  90. case *HasVoteMessage:
  91. pb = tmcons.Message{
  92. Sum: &tmcons.Message_HasVote{
  93. HasVote: &tmcons.HasVote{
  94. Height: msg.Height,
  95. Round: msg.Round,
  96. Type: msg.Type,
  97. Index: msg.Index,
  98. },
  99. },
  100. }
  101. case *VoteSetMaj23Message:
  102. bi := msg.BlockID.ToProto()
  103. pb = tmcons.Message{
  104. Sum: &tmcons.Message_VoteSetMaj23{
  105. VoteSetMaj23: &tmcons.VoteSetMaj23{
  106. Height: msg.Height,
  107. Round: msg.Round,
  108. Type: msg.Type,
  109. BlockID: bi,
  110. },
  111. },
  112. }
  113. case *VoteSetBitsMessage:
  114. bi := msg.BlockID.ToProto()
  115. bits := msg.Votes.ToProto()
  116. vsb := &tmcons.Message_VoteSetBits{
  117. VoteSetBits: &tmcons.VoteSetBits{
  118. Height: msg.Height,
  119. Round: msg.Round,
  120. Type: msg.Type,
  121. BlockID: bi,
  122. },
  123. }
  124. if bits != nil {
  125. vsb.VoteSetBits.Votes = *bits
  126. }
  127. pb = tmcons.Message{
  128. Sum: vsb,
  129. }
  130. default:
  131. return nil, fmt.Errorf("consensus: message not recognized: %T", msg)
  132. }
  133. return &pb, nil
  134. }
  135. // MsgFromProto takes a consensus proto message and returns the native go type
  136. func MsgFromProto(msg *tmcons.Message) (Message, error) {
  137. if msg == nil {
  138. return nil, errors.New("consensus: nil message")
  139. }
  140. var pb Message
  141. switch msg := msg.Sum.(type) {
  142. case *tmcons.Message_NewRoundStep:
  143. rs, err := tmmath.SafeConvertUint8(int64(msg.NewRoundStep.Step))
  144. // deny message based on possible overflow
  145. if err != nil {
  146. return nil, fmt.Errorf("denying message due to possible overflow: %w", err)
  147. }
  148. pb = &NewRoundStepMessage{
  149. Height: msg.NewRoundStep.Height,
  150. Round: msg.NewRoundStep.Round,
  151. Step: cstypes.RoundStepType(rs),
  152. SecondsSinceStartTime: msg.NewRoundStep.SecondsSinceStartTime,
  153. LastCommitRound: msg.NewRoundStep.LastCommitRound,
  154. }
  155. case *tmcons.Message_NewValidBlock:
  156. pbPartsHeader, err := types.PartSetHeaderFromProto(&msg.NewValidBlock.BlockPartsHeader)
  157. if err != nil {
  158. return nil, fmt.Errorf("parts to proto error: %w", err)
  159. }
  160. pbBits := new(bits.BitArray)
  161. pbBits.FromProto(msg.NewValidBlock.BlockParts)
  162. pb = &NewValidBlockMessage{
  163. Height: msg.NewValidBlock.Height,
  164. Round: msg.NewValidBlock.Round,
  165. BlockPartsHeader: *pbPartsHeader,
  166. BlockParts: pbBits,
  167. IsCommit: msg.NewValidBlock.IsCommit,
  168. }
  169. case *tmcons.Message_Proposal:
  170. pbP, err := types.ProposalFromProto(&msg.Proposal.Proposal)
  171. if err != nil {
  172. return nil, fmt.Errorf("proposal msg to proto error: %w", err)
  173. }
  174. pb = &ProposalMessage{
  175. Proposal: pbP,
  176. }
  177. case *tmcons.Message_ProposalPol:
  178. pbBits := new(bits.BitArray)
  179. pbBits.FromProto(&msg.ProposalPol.ProposalPol)
  180. pb = &ProposalPOLMessage{
  181. Height: msg.ProposalPol.Height,
  182. ProposalPOLRound: msg.ProposalPol.ProposalPolRound,
  183. ProposalPOL: pbBits,
  184. }
  185. case *tmcons.Message_BlockPart:
  186. parts, err := types.PartFromProto(&msg.BlockPart.Part)
  187. if err != nil {
  188. return nil, fmt.Errorf("blockpart msg to proto error: %w", err)
  189. }
  190. pb = &BlockPartMessage{
  191. Height: msg.BlockPart.Height,
  192. Round: msg.BlockPart.Round,
  193. Part: parts,
  194. }
  195. case *tmcons.Message_Vote:
  196. vote, err := types.VoteFromProto(msg.Vote.Vote)
  197. if err != nil {
  198. return nil, fmt.Errorf("vote msg to proto error: %w", err)
  199. }
  200. pb = &VoteMessage{
  201. Vote: vote,
  202. }
  203. case *tmcons.Message_HasVote:
  204. pb = &HasVoteMessage{
  205. Height: msg.HasVote.Height,
  206. Round: msg.HasVote.Round,
  207. Type: msg.HasVote.Type,
  208. Index: msg.HasVote.Index,
  209. }
  210. case *tmcons.Message_VoteSetMaj23:
  211. bi, err := types.BlockIDFromProto(&msg.VoteSetMaj23.BlockID)
  212. if err != nil {
  213. return nil, fmt.Errorf("voteSetMaj23 msg to proto error: %w", err)
  214. }
  215. pb = &VoteSetMaj23Message{
  216. Height: msg.VoteSetMaj23.Height,
  217. Round: msg.VoteSetMaj23.Round,
  218. Type: msg.VoteSetMaj23.Type,
  219. BlockID: *bi,
  220. }
  221. case *tmcons.Message_VoteSetBits:
  222. bi, err := types.BlockIDFromProto(&msg.VoteSetBits.BlockID)
  223. if err != nil {
  224. return nil, fmt.Errorf("voteSetBits msg to proto error: %w", err)
  225. }
  226. bits := new(bits.BitArray)
  227. bits.FromProto(&msg.VoteSetBits.Votes)
  228. pb = &VoteSetBitsMessage{
  229. Height: msg.VoteSetBits.Height,
  230. Round: msg.VoteSetBits.Round,
  231. Type: msg.VoteSetBits.Type,
  232. BlockID: *bi,
  233. Votes: bits,
  234. }
  235. default:
  236. return nil, fmt.Errorf("consensus: message not recognized: %T", msg)
  237. }
  238. if err := pb.ValidateBasic(); err != nil {
  239. return nil, err
  240. }
  241. return pb, nil
  242. }
  243. // MustEncode takes the reactors msg, makes it proto and marshals it
  244. // this mimics `MustMarshalBinaryBare` in that is panics on error
  245. func MustEncode(msg Message) []byte {
  246. pb, err := MsgToProto(msg)
  247. if err != nil {
  248. panic(err)
  249. }
  250. enc, err := proto.Marshal(pb)
  251. if err != nil {
  252. panic(err)
  253. }
  254. return enc
  255. }
  256. // WALToProto takes a WAL message and return a proto walMessage and error
  257. func WALToProto(msg WALMessage) (*tmcons.WALMessage, error) {
  258. var pb tmcons.WALMessage
  259. switch msg := msg.(type) {
  260. case types.EventDataRoundState:
  261. pb = tmcons.WALMessage{
  262. Sum: &tmcons.WALMessage_EventDataRoundState{
  263. EventDataRoundState: &tmproto.EventDataRoundState{
  264. Height: msg.Height,
  265. Round: msg.Round,
  266. Step: msg.Step,
  267. },
  268. },
  269. }
  270. case msgInfo:
  271. consMsg, err := MsgToProto(msg.Msg)
  272. if err != nil {
  273. return nil, err
  274. }
  275. pb = tmcons.WALMessage{
  276. Sum: &tmcons.WALMessage_MsgInfo{
  277. MsgInfo: &tmcons.MsgInfo{
  278. Msg: *consMsg,
  279. PeerID: string(msg.PeerID),
  280. },
  281. },
  282. }
  283. case timeoutInfo:
  284. pb = tmcons.WALMessage{
  285. Sum: &tmcons.WALMessage_TimeoutInfo{
  286. TimeoutInfo: &tmcons.TimeoutInfo{
  287. Duration: msg.Duration,
  288. Height: msg.Height,
  289. Round: msg.Round,
  290. Step: uint32(msg.Step),
  291. },
  292. },
  293. }
  294. case EndHeightMessage:
  295. pb = tmcons.WALMessage{
  296. Sum: &tmcons.WALMessage_EndHeight{
  297. EndHeight: &tmcons.EndHeight{
  298. Height: msg.Height,
  299. },
  300. },
  301. }
  302. default:
  303. return nil, fmt.Errorf("to proto: wal message not recognized: %T", msg)
  304. }
  305. return &pb, nil
  306. }
  307. // WALFromProto takes a proto wal message and return a consensus walMessage and error
  308. func WALFromProto(msg *tmcons.WALMessage) (WALMessage, error) {
  309. if msg == nil {
  310. return nil, errors.New("nil WAL message")
  311. }
  312. var pb WALMessage
  313. switch msg := msg.Sum.(type) {
  314. case *tmcons.WALMessage_EventDataRoundState:
  315. pb = types.EventDataRoundState{
  316. Height: msg.EventDataRoundState.Height,
  317. Round: msg.EventDataRoundState.Round,
  318. Step: msg.EventDataRoundState.Step,
  319. }
  320. case *tmcons.WALMessage_MsgInfo:
  321. walMsg, err := MsgFromProto(&msg.MsgInfo.Msg)
  322. if err != nil {
  323. return nil, fmt.Errorf("msgInfo from proto error: %w", err)
  324. }
  325. pb = msgInfo{
  326. Msg: walMsg,
  327. PeerID: p2p.ID(msg.MsgInfo.PeerID),
  328. }
  329. case *tmcons.WALMessage_TimeoutInfo:
  330. tis, err := tmmath.SafeConvertUint8(int64(msg.TimeoutInfo.Step))
  331. // deny message based on possible overflow
  332. if err != nil {
  333. return nil, fmt.Errorf("denying message due to possible overflow: %w", err)
  334. }
  335. pb = timeoutInfo{
  336. Duration: msg.TimeoutInfo.Duration,
  337. Height: msg.TimeoutInfo.Height,
  338. Round: msg.TimeoutInfo.Round,
  339. Step: cstypes.RoundStepType(tis),
  340. }
  341. return pb, nil
  342. case *tmcons.WALMessage_EndHeight:
  343. pb := EndHeightMessage{
  344. Height: msg.EndHeight.Height,
  345. }
  346. return pb, nil
  347. default:
  348. return nil, fmt.Errorf("from proto: wal message not recognized: %T", msg)
  349. }
  350. return pb, nil
  351. }