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.

386 lines
9.9 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/tendermint/consensus"
  11. tmproto "github.com/tendermint/tendermint/proto/tendermint/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. pbPartSetHeader := msg.BlockPartSetHeader.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. BlockPartSetHeader: pbPartSetHeader,
  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. pbPartSetHeader, err := types.PartSetHeaderFromProto(&msg.NewValidBlock.BlockPartSetHeader)
  157. if err != nil {
  158. return nil, fmt.Errorf("parts header to proto error: %w", err)
  159. }
  160. pbBits := new(bits.BitArray)
  161. err = pbBits.FromProto(msg.NewValidBlock.BlockParts)
  162. if err != nil {
  163. return nil, fmt.Errorf("parts to proto error: %w", err)
  164. }
  165. pb = &NewValidBlockMessage{
  166. Height: msg.NewValidBlock.Height,
  167. Round: msg.NewValidBlock.Round,
  168. BlockPartSetHeader: *pbPartSetHeader,
  169. BlockParts: pbBits,
  170. IsCommit: msg.NewValidBlock.IsCommit,
  171. }
  172. case *tmcons.Message_Proposal:
  173. pbP, err := types.ProposalFromProto(&msg.Proposal.Proposal)
  174. if err != nil {
  175. return nil, fmt.Errorf("proposal msg to proto error: %w", err)
  176. }
  177. pb = &ProposalMessage{
  178. Proposal: pbP,
  179. }
  180. case *tmcons.Message_ProposalPol:
  181. pbBits := new(bits.BitArray)
  182. err := pbBits.FromProto(&msg.ProposalPol.ProposalPol)
  183. if err != nil {
  184. return nil, fmt.Errorf("proposal PoL to proto error: %w", err)
  185. }
  186. pb = &ProposalPOLMessage{
  187. Height: msg.ProposalPol.Height,
  188. ProposalPOLRound: msg.ProposalPol.ProposalPolRound,
  189. ProposalPOL: pbBits,
  190. }
  191. case *tmcons.Message_BlockPart:
  192. parts, err := types.PartFromProto(&msg.BlockPart.Part)
  193. if err != nil {
  194. return nil, fmt.Errorf("blockpart msg to proto error: %w", err)
  195. }
  196. pb = &BlockPartMessage{
  197. Height: msg.BlockPart.Height,
  198. Round: msg.BlockPart.Round,
  199. Part: parts,
  200. }
  201. case *tmcons.Message_Vote:
  202. vote, err := types.VoteFromProto(msg.Vote.Vote)
  203. if err != nil {
  204. return nil, fmt.Errorf("vote msg to proto error: %w", err)
  205. }
  206. pb = &VoteMessage{
  207. Vote: vote,
  208. }
  209. case *tmcons.Message_HasVote:
  210. pb = &HasVoteMessage{
  211. Height: msg.HasVote.Height,
  212. Round: msg.HasVote.Round,
  213. Type: msg.HasVote.Type,
  214. Index: msg.HasVote.Index,
  215. }
  216. case *tmcons.Message_VoteSetMaj23:
  217. bi, err := types.BlockIDFromProto(&msg.VoteSetMaj23.BlockID)
  218. if err != nil {
  219. return nil, fmt.Errorf("voteSetMaj23 msg to proto error: %w", err)
  220. }
  221. pb = &VoteSetMaj23Message{
  222. Height: msg.VoteSetMaj23.Height,
  223. Round: msg.VoteSetMaj23.Round,
  224. Type: msg.VoteSetMaj23.Type,
  225. BlockID: *bi,
  226. }
  227. case *tmcons.Message_VoteSetBits:
  228. bi, err := types.BlockIDFromProto(&msg.VoteSetBits.BlockID)
  229. if err != nil {
  230. return nil, fmt.Errorf("block ID to proto error: %w", err)
  231. }
  232. bits := new(bits.BitArray)
  233. err = bits.FromProto(&msg.VoteSetBits.Votes)
  234. if err != nil {
  235. return nil, fmt.Errorf("votes to proto error: %w", err)
  236. }
  237. pb = &VoteSetBitsMessage{
  238. Height: msg.VoteSetBits.Height,
  239. Round: msg.VoteSetBits.Round,
  240. Type: msg.VoteSetBits.Type,
  241. BlockID: *bi,
  242. Votes: bits,
  243. }
  244. default:
  245. return nil, fmt.Errorf("consensus: message not recognized: %T", msg)
  246. }
  247. if err := pb.ValidateBasic(); err != nil {
  248. return nil, err
  249. }
  250. return pb, nil
  251. }
  252. // MustEncode takes the reactors msg, makes it proto and marshals it
  253. // this mimics `MustMarshalBinaryBare` in that is panics on error
  254. func MustEncode(msg Message) []byte {
  255. pb, err := MsgToProto(msg)
  256. if err != nil {
  257. panic(err)
  258. }
  259. enc, err := proto.Marshal(pb)
  260. if err != nil {
  261. panic(err)
  262. }
  263. return enc
  264. }
  265. // WALToProto takes a WAL message and return a proto walMessage and error
  266. func WALToProto(msg WALMessage) (*tmcons.WALMessage, error) {
  267. var pb tmcons.WALMessage
  268. switch msg := msg.(type) {
  269. case types.EventDataRoundState:
  270. pb = tmcons.WALMessage{
  271. Sum: &tmcons.WALMessage_EventDataRoundState{
  272. EventDataRoundState: &tmproto.EventDataRoundState{
  273. Height: msg.Height,
  274. Round: msg.Round,
  275. Step: msg.Step,
  276. },
  277. },
  278. }
  279. case msgInfo:
  280. consMsg, err := MsgToProto(msg.Msg)
  281. if err != nil {
  282. return nil, err
  283. }
  284. pb = tmcons.WALMessage{
  285. Sum: &tmcons.WALMessage_MsgInfo{
  286. MsgInfo: &tmcons.MsgInfo{
  287. Msg: *consMsg,
  288. PeerID: string(msg.PeerID),
  289. },
  290. },
  291. }
  292. case timeoutInfo:
  293. pb = tmcons.WALMessage{
  294. Sum: &tmcons.WALMessage_TimeoutInfo{
  295. TimeoutInfo: &tmcons.TimeoutInfo{
  296. Duration: msg.Duration,
  297. Height: msg.Height,
  298. Round: msg.Round,
  299. Step: uint32(msg.Step),
  300. },
  301. },
  302. }
  303. case EndHeightMessage:
  304. pb = tmcons.WALMessage{
  305. Sum: &tmcons.WALMessage_EndHeight{
  306. EndHeight: &tmcons.EndHeight{
  307. Height: msg.Height,
  308. },
  309. },
  310. }
  311. default:
  312. return nil, fmt.Errorf("to proto: wal message not recognized: %T", msg)
  313. }
  314. return &pb, nil
  315. }
  316. // WALFromProto takes a proto wal message and return a consensus walMessage and error
  317. func WALFromProto(msg *tmcons.WALMessage) (WALMessage, error) {
  318. if msg == nil {
  319. return nil, errors.New("nil WAL message")
  320. }
  321. var pb WALMessage
  322. switch msg := msg.Sum.(type) {
  323. case *tmcons.WALMessage_EventDataRoundState:
  324. pb = types.EventDataRoundState{
  325. Height: msg.EventDataRoundState.Height,
  326. Round: msg.EventDataRoundState.Round,
  327. Step: msg.EventDataRoundState.Step,
  328. }
  329. case *tmcons.WALMessage_MsgInfo:
  330. walMsg, err := MsgFromProto(&msg.MsgInfo.Msg)
  331. if err != nil {
  332. return nil, fmt.Errorf("msgInfo from proto error: %w", err)
  333. }
  334. pb = msgInfo{
  335. Msg: walMsg,
  336. PeerID: p2p.ID(msg.MsgInfo.PeerID),
  337. }
  338. case *tmcons.WALMessage_TimeoutInfo:
  339. tis, err := tmmath.SafeConvertUint8(int64(msg.TimeoutInfo.Step))
  340. // deny message based on possible overflow
  341. if err != nil {
  342. return nil, fmt.Errorf("denying message due to possible overflow: %w", err)
  343. }
  344. pb = timeoutInfo{
  345. Duration: msg.TimeoutInfo.Duration,
  346. Height: msg.TimeoutInfo.Height,
  347. Round: msg.TimeoutInfo.Round,
  348. Step: cstypes.RoundStepType(tis),
  349. }
  350. return pb, nil
  351. case *tmcons.WALMessage_EndHeight:
  352. pb := EndHeightMessage{
  353. Height: msg.EndHeight.Height,
  354. }
  355. return pb, nil
  356. default:
  357. return nil, fmt.Errorf("from proto: wal message not recognized: %T", msg)
  358. }
  359. return pb, nil
  360. }