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.

1311 lines
34 KiB

max-bytes PR follow-up (#2318) * ReapMaxTxs: return all txs if max is negative this mirrors ReapMaxBytes behavior See https://github.com/tendermint/tendermint/pull/2184#discussion_r214439950 * increase MaxAminoOverheadForBlock tested with: ``` func TestMaxAminoOverheadForBlock(t *testing.T) { maxChainID := "" for i := 0; i < MaxChainIDLen; i++ { maxChainID += "𠜎" } h := Header{ ChainID: maxChainID, Height: 10, Time: time.Now().UTC(), NumTxs: 100, TotalTxs: 200, LastBlockID: makeBlockID(make([]byte, 20), 300, make([]byte, 20)), LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), DataHash: tmhash.Sum([]byte("data_hash")), ValidatorsHash: tmhash.Sum([]byte("validators_hash")), NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: tmhash.Sum([]byte("app_hash")), LastResultsHash: tmhash.Sum([]byte("last_results_hash")), EvidenceHash: tmhash.Sum([]byte("evidence_hash")), ProposerAddress: tmhash.Sum([]byte("proposer_address")), } b := Block{ Header: h, Data: Data{Txs: makeTxs(10000, 100)}, Evidence: EvidenceData{}, LastCommit: &Commit{}, } bz, err := cdc.MarshalBinary(b) require.NoError(t, err) assert.Equal(t, MaxHeaderBytes+MaxAminoOverheadForBlock-2, len(bz)-1000000-20000-1) } ``` * fix MaxYYY constants calculation by using math.MaxInt64 See https://github.com/tendermint/tendermint/pull/2184#discussion_r214444244 * pass mempool filter as an option See https://github.com/tendermint/tendermint/pull/2184#discussion_r214445869 * fixes after Dev's comments
6 years ago
max-bytes PR follow-up (#2318) * ReapMaxTxs: return all txs if max is negative this mirrors ReapMaxBytes behavior See https://github.com/tendermint/tendermint/pull/2184#discussion_r214439950 * increase MaxAminoOverheadForBlock tested with: ``` func TestMaxAminoOverheadForBlock(t *testing.T) { maxChainID := "" for i := 0; i < MaxChainIDLen; i++ { maxChainID += "𠜎" } h := Header{ ChainID: maxChainID, Height: 10, Time: time.Now().UTC(), NumTxs: 100, TotalTxs: 200, LastBlockID: makeBlockID(make([]byte, 20), 300, make([]byte, 20)), LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), DataHash: tmhash.Sum([]byte("data_hash")), ValidatorsHash: tmhash.Sum([]byte("validators_hash")), NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: tmhash.Sum([]byte("app_hash")), LastResultsHash: tmhash.Sum([]byte("last_results_hash")), EvidenceHash: tmhash.Sum([]byte("evidence_hash")), ProposerAddress: tmhash.Sum([]byte("proposer_address")), } b := Block{ Header: h, Data: Data{Txs: makeTxs(10000, 100)}, Evidence: EvidenceData{}, LastCommit: &Commit{}, } bz, err := cdc.MarshalBinary(b) require.NoError(t, err) assert.Equal(t, MaxHeaderBytes+MaxAminoOverheadForBlock-2, len(bz)-1000000-20000-1) } ``` * fix MaxYYY constants calculation by using math.MaxInt64 See https://github.com/tendermint/tendermint/pull/2184#discussion_r214444244 * pass mempool filter as an option See https://github.com/tendermint/tendermint/pull/2184#discussion_r214445869 * fixes after Dev's comments
6 years ago
7 years ago
10 years ago
10 years ago
7 years ago
7 years ago
10 years ago
11 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/tendermint/tendermint/crypto"
  10. "github.com/tendermint/tendermint/crypto/merkle"
  11. "github.com/tendermint/tendermint/crypto/tmhash"
  12. "github.com/tendermint/tendermint/libs/bits"
  13. tmbytes "github.com/tendermint/tendermint/libs/bytes"
  14. tmmath "github.com/tendermint/tendermint/libs/math"
  15. tmproto "github.com/tendermint/tendermint/proto/types"
  16. tmversion "github.com/tendermint/tendermint/proto/version"
  17. )
  18. const (
  19. // MaxHeaderBytes is a maximum header size (including amino overhead).
  20. MaxHeaderBytes int64 = 628
  21. // MaxAminoOverheadForBlock - maximum amino overhead to encode a block (up to
  22. // MaxBlockSizeBytes in size) not including it's parts except Data.
  23. // This means it also excludes the overhead for individual transactions.
  24. //
  25. // Uvarint length of MaxBlockSizeBytes: 4 bytes
  26. // 2 fields (2 embedded): 2 bytes
  27. // Uvarint length of Data.Txs: 4 bytes
  28. // Data.Txs field: 1 byte
  29. MaxAminoOverheadForBlock int64 = 11
  30. )
  31. // Block defines the atomic unit of a Tendermint blockchain.
  32. type Block struct {
  33. mtx sync.Mutex
  34. Header `json:"header"`
  35. Data `json:"data"`
  36. Evidence EvidenceData `json:"evidence"`
  37. LastCommit *Commit `json:"last_commit"`
  38. }
  39. // ValidateBasic performs basic validation that doesn't involve state data.
  40. // It checks the internal consistency of the block.
  41. // Further validation is done using state#ValidateBlock.
  42. func (b *Block) ValidateBasic() error {
  43. if b == nil {
  44. return errors.New("nil block")
  45. }
  46. b.mtx.Lock()
  47. defer b.mtx.Unlock()
  48. if err := b.Header.ValidateBasic(); err != nil {
  49. return fmt.Errorf("invalid header: %w", err)
  50. }
  51. // Validate the last commit and its hash.
  52. if b.LastCommit == nil {
  53. return errors.New("nil LastCommit")
  54. }
  55. if b.Header.Height > 1 {
  56. if err := b.LastCommit.ValidateBasic(); err != nil {
  57. return fmt.Errorf("wrong LastCommit: %v", err)
  58. }
  59. }
  60. if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) {
  61. return fmt.Errorf("wrong Header.LastCommitHash. Expected %v, got %v",
  62. b.LastCommit.Hash(),
  63. b.LastCommitHash,
  64. )
  65. }
  66. // NOTE: b.Data.Txs may be nil, but b.Data.Hash() still works fine.
  67. if !bytes.Equal(b.DataHash, b.Data.Hash()) {
  68. return fmt.Errorf(
  69. "wrong Header.DataHash. Expected %v, got %v",
  70. b.Data.Hash(),
  71. b.DataHash,
  72. )
  73. }
  74. // NOTE: b.Evidence.Evidence may be nil, but we're just looping.
  75. for i, ev := range b.Evidence.Evidence {
  76. if err := ev.ValidateBasic(); err != nil {
  77. return fmt.Errorf("invalid evidence (#%d): %v", i, err)
  78. }
  79. }
  80. if !bytes.Equal(b.EvidenceHash, b.Evidence.Hash()) {
  81. return fmt.Errorf("wrong Header.EvidenceHash. Expected %v, got %v",
  82. b.EvidenceHash,
  83. b.Evidence.Hash(),
  84. )
  85. }
  86. return nil
  87. }
  88. // fillHeader fills in any remaining header fields that are a function of the block data
  89. func (b *Block) fillHeader() {
  90. if b.LastCommitHash == nil {
  91. b.LastCommitHash = b.LastCommit.Hash()
  92. }
  93. if b.DataHash == nil {
  94. b.DataHash = b.Data.Hash()
  95. }
  96. if b.EvidenceHash == nil {
  97. b.EvidenceHash = b.Evidence.Hash()
  98. }
  99. }
  100. // Hash computes and returns the block hash.
  101. // If the block is incomplete, block hash is nil for safety.
  102. func (b *Block) Hash() tmbytes.HexBytes {
  103. if b == nil {
  104. return nil
  105. }
  106. b.mtx.Lock()
  107. defer b.mtx.Unlock()
  108. if b.LastCommit == nil {
  109. return nil
  110. }
  111. b.fillHeader()
  112. return b.Header.Hash()
  113. }
  114. // MakePartSet returns a PartSet containing parts of a serialized block.
  115. // This is the form in which the block is gossipped to peers.
  116. // CONTRACT: partSize is greater than zero.
  117. func (b *Block) MakePartSet(partSize uint32) *PartSet {
  118. if b == nil {
  119. return nil
  120. }
  121. b.mtx.Lock()
  122. defer b.mtx.Unlock()
  123. // We prefix the byte length, so that unmarshaling
  124. // can easily happen via a reader.
  125. bz, err := cdc.MarshalBinaryLengthPrefixed(b)
  126. if err != nil {
  127. panic(err)
  128. }
  129. return NewPartSetFromData(bz, partSize)
  130. }
  131. // HashesTo is a convenience function that checks if a block hashes to the given argument.
  132. // Returns false if the block is nil or the hash is empty.
  133. func (b *Block) HashesTo(hash []byte) bool {
  134. if len(hash) == 0 {
  135. return false
  136. }
  137. if b == nil {
  138. return false
  139. }
  140. return bytes.Equal(b.Hash(), hash)
  141. }
  142. // Size returns size of the block in bytes.
  143. func (b *Block) Size() int {
  144. bz, err := cdc.MarshalBinaryBare(b)
  145. if err != nil {
  146. return 0
  147. }
  148. return len(bz)
  149. }
  150. // String returns a string representation of the block
  151. func (b *Block) String() string {
  152. return b.StringIndented("")
  153. }
  154. // StringIndented returns a string representation of the block
  155. func (b *Block) StringIndented(indent string) string {
  156. if b == nil {
  157. return "nil-Block"
  158. }
  159. return fmt.Sprintf(`Block{
  160. %s %v
  161. %s %v
  162. %s %v
  163. %s %v
  164. %s}#%v`,
  165. indent, b.Header.StringIndented(indent+" "),
  166. indent, b.Data.StringIndented(indent+" "),
  167. indent, b.Evidence.StringIndented(indent+" "),
  168. indent, b.LastCommit.StringIndented(indent+" "),
  169. indent, b.Hash())
  170. }
  171. // StringShort returns a shortened string representation of the block
  172. func (b *Block) StringShort() string {
  173. if b == nil {
  174. return "nil-Block"
  175. }
  176. return fmt.Sprintf("Block#%v", b.Hash())
  177. }
  178. // ToProto converts Block to protobuf
  179. func (b *Block) ToProto() (*tmproto.Block, error) {
  180. if b == nil {
  181. return nil, errors.New("nil Block")
  182. }
  183. pb := new(tmproto.Block)
  184. pb.Header = *b.Header.ToProto()
  185. pb.LastCommit = b.LastCommit.ToProto()
  186. pb.Data = b.Data.ToProto()
  187. protoEvidence, err := b.Evidence.ToProto()
  188. if err != nil {
  189. return nil, err
  190. }
  191. pb.Evidence = *protoEvidence
  192. return pb, nil
  193. }
  194. // FromProto sets a protobuf Block to the given pointer.
  195. // It returns an error if the block is invalid.
  196. func BlockFromProto(bp *tmproto.Block) (*Block, error) {
  197. if bp == nil {
  198. return nil, errors.New("nil block")
  199. }
  200. b := new(Block)
  201. h, err := HeaderFromProto(&bp.Header)
  202. if err != nil {
  203. return nil, err
  204. }
  205. b.Header = h
  206. data, err := DataFromProto(&bp.Data)
  207. if err != nil {
  208. return nil, err
  209. }
  210. b.Data = data
  211. b.Evidence.FromProto(&bp.Evidence)
  212. if bp.LastCommit != nil {
  213. lc, err := CommitFromProto(bp.LastCommit)
  214. if err != nil {
  215. return nil, err
  216. }
  217. b.LastCommit = lc
  218. }
  219. return b, b.ValidateBasic()
  220. }
  221. //-----------------------------------------------------------
  222. // These methods are for Protobuf Compatibility
  223. // Marshal returns the amino encoding.
  224. func (b *Block) Marshal() ([]byte, error) {
  225. return cdc.MarshalBinaryBare(b)
  226. }
  227. // MarshalTo calls Marshal and copies to the given buffer.
  228. func (b *Block) MarshalTo(data []byte) (int, error) {
  229. bs, err := b.Marshal()
  230. if err != nil {
  231. return -1, err
  232. }
  233. return copy(data, bs), nil
  234. }
  235. // Unmarshal deserializes from amino encoded form.
  236. func (b *Block) Unmarshal(bs []byte) error {
  237. return cdc.UnmarshalBinaryBare(bs, b)
  238. }
  239. //-----------------------------------------------------------------------------
  240. // MaxDataBytes returns the maximum size of block's data.
  241. //
  242. // XXX: Panics on negative result.
  243. func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 {
  244. maxDataBytes := maxBytes -
  245. MaxAminoOverheadForBlock -
  246. MaxHeaderBytes -
  247. int64(valsCount)*MaxVoteBytes -
  248. int64(evidenceCount)*MaxEvidenceBytes
  249. if maxDataBytes < 0 {
  250. panic(fmt.Sprintf(
  251. "Negative MaxDataBytes. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d",
  252. maxBytes,
  253. -(maxDataBytes - maxBytes),
  254. ))
  255. }
  256. return maxDataBytes
  257. }
  258. // MaxDataBytesUnknownEvidence returns the maximum size of block's data when
  259. // evidence count is unknown. MaxEvidencePerBlock will be used for the size
  260. // of evidence.
  261. //
  262. // XXX: Panics on negative result.
  263. func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int, maxNumEvidence uint32) int64 {
  264. maxEvidenceBytes := int64(maxNumEvidence) * MaxEvidenceBytes
  265. maxDataBytes := maxBytes -
  266. MaxAminoOverheadForBlock -
  267. MaxHeaderBytes -
  268. int64(valsCount)*MaxVoteBytes -
  269. maxEvidenceBytes
  270. if maxDataBytes < 0 {
  271. panic(fmt.Sprintf(
  272. "Negative MaxDataBytesUnknownEvidence. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d",
  273. maxBytes,
  274. -(maxDataBytes - maxBytes),
  275. ))
  276. }
  277. return maxDataBytes
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Header defines the structure of a Tendermint block header.
  281. // NOTE: changes to the Header should be duplicated in:
  282. // - header.Hash()
  283. // - abci.Header
  284. // - https://github.com/tendermint/spec/blob/master/spec/blockchain/blockchain.md
  285. type Header struct {
  286. // basic block info
  287. Version tmversion.Consensus `json:"version"`
  288. ChainID string `json:"chain_id"`
  289. Height int64 `json:"height"`
  290. Time time.Time `json:"time"`
  291. // prev block info
  292. LastBlockID BlockID `json:"last_block_id"`
  293. // hashes of block data
  294. LastCommitHash tmbytes.HexBytes `json:"last_commit_hash"` // commit from validators from the last block
  295. DataHash tmbytes.HexBytes `json:"data_hash"` // transactions
  296. // hashes from the app output from the prev block
  297. ValidatorsHash tmbytes.HexBytes `json:"validators_hash"` // validators for the current block
  298. NextValidatorsHash tmbytes.HexBytes `json:"next_validators_hash"` // validators for the next block
  299. ConsensusHash tmbytes.HexBytes `json:"consensus_hash"` // consensus params for current block
  300. AppHash tmbytes.HexBytes `json:"app_hash"` // state after txs from the previous block
  301. // root hash of all results from the txs from the previous block
  302. LastResultsHash tmbytes.HexBytes `json:"last_results_hash"`
  303. // consensus info
  304. EvidenceHash tmbytes.HexBytes `json:"evidence_hash"` // evidence included in the block
  305. ProposerAddress Address `json:"proposer_address"` // original proposer of the block
  306. }
  307. // Populate the Header with state-derived data.
  308. // Call this after MakeBlock to complete the Header.
  309. func (h *Header) Populate(
  310. version tmversion.Consensus, chainID string,
  311. timestamp time.Time, lastBlockID BlockID,
  312. valHash, nextValHash []byte,
  313. consensusHash, appHash, lastResultsHash []byte,
  314. proposerAddress Address,
  315. ) {
  316. h.Version = version
  317. h.ChainID = chainID
  318. h.Time = timestamp
  319. h.LastBlockID = lastBlockID
  320. h.ValidatorsHash = valHash
  321. h.NextValidatorsHash = nextValHash
  322. h.ConsensusHash = consensusHash
  323. h.AppHash = appHash
  324. h.LastResultsHash = lastResultsHash
  325. h.ProposerAddress = proposerAddress
  326. }
  327. // ValidateBasic performs stateless validation on a Header returning an error
  328. // if any validation fails.
  329. //
  330. // NOTE: Timestamp validation is subtle and handled elsewhere.
  331. func (h Header) ValidateBasic() error {
  332. if len(h.ChainID) > MaxChainIDLen {
  333. return fmt.Errorf("chainID is too long; got: %d, max: %d", len(h.ChainID), MaxChainIDLen)
  334. }
  335. if h.Height < 0 {
  336. return errors.New("negative Height")
  337. } else if h.Height == 0 {
  338. return errors.New("zero Height")
  339. }
  340. if err := h.LastBlockID.ValidateBasic(); err != nil {
  341. return fmt.Errorf("wrong LastBlockID: %w", err)
  342. }
  343. if err := ValidateHash(h.LastCommitHash); err != nil {
  344. return fmt.Errorf("wrong LastCommitHash: %v", err)
  345. }
  346. if err := ValidateHash(h.DataHash); err != nil {
  347. return fmt.Errorf("wrong DataHash: %v", err)
  348. }
  349. if err := ValidateHash(h.EvidenceHash); err != nil {
  350. return fmt.Errorf("wrong EvidenceHash: %v", err)
  351. }
  352. if len(h.ProposerAddress) != crypto.AddressSize {
  353. return fmt.Errorf(
  354. "invalid ProposerAddress length; got: %d, expected: %d",
  355. len(h.ProposerAddress), crypto.AddressSize,
  356. )
  357. }
  358. // Basic validation of hashes related to application data.
  359. // Will validate fully against state in state#ValidateBlock.
  360. if err := ValidateHash(h.ValidatorsHash); err != nil {
  361. return fmt.Errorf("wrong ValidatorsHash: %v", err)
  362. }
  363. if err := ValidateHash(h.NextValidatorsHash); err != nil {
  364. return fmt.Errorf("wrong NextValidatorsHash: %v", err)
  365. }
  366. if err := ValidateHash(h.ConsensusHash); err != nil {
  367. return fmt.Errorf("wrong ConsensusHash: %v", err)
  368. }
  369. // NOTE: AppHash is arbitrary length
  370. if err := ValidateHash(h.LastResultsHash); err != nil {
  371. return fmt.Errorf("wrong LastResultsHash: %v", err)
  372. }
  373. return nil
  374. }
  375. // Hash returns the hash of the header.
  376. // It computes a Merkle tree from the header fields
  377. // ordered as they appear in the Header.
  378. // Returns nil if ValidatorHash is missing,
  379. // since a Header is not valid unless there is
  380. // a ValidatorsHash (corresponding to the validator set).
  381. func (h *Header) Hash() tmbytes.HexBytes {
  382. if h == nil || len(h.ValidatorsHash) == 0 {
  383. return nil
  384. }
  385. return merkle.SimpleHashFromByteSlices([][]byte{
  386. cdcEncode(h.Version),
  387. cdcEncode(h.ChainID),
  388. cdcEncode(h.Height),
  389. cdcEncode(h.Time),
  390. cdcEncode(h.LastBlockID),
  391. cdcEncode(h.LastCommitHash),
  392. cdcEncode(h.DataHash),
  393. cdcEncode(h.ValidatorsHash),
  394. cdcEncode(h.NextValidatorsHash),
  395. cdcEncode(h.ConsensusHash),
  396. cdcEncode(h.AppHash),
  397. cdcEncode(h.LastResultsHash),
  398. cdcEncode(h.EvidenceHash),
  399. cdcEncode(h.ProposerAddress),
  400. })
  401. }
  402. // StringIndented returns a string representation of the header
  403. func (h *Header) StringIndented(indent string) string {
  404. if h == nil {
  405. return "nil-Header"
  406. }
  407. return fmt.Sprintf(`Header{
  408. %s Version: %v
  409. %s ChainID: %v
  410. %s Height: %v
  411. %s Time: %v
  412. %s LastBlockID: %v
  413. %s LastCommit: %v
  414. %s Data: %v
  415. %s Validators: %v
  416. %s NextValidators: %v
  417. %s App: %v
  418. %s Consensus: %v
  419. %s Results: %v
  420. %s Evidence: %v
  421. %s Proposer: %v
  422. %s}#%v`,
  423. indent, h.Version,
  424. indent, h.ChainID,
  425. indent, h.Height,
  426. indent, h.Time,
  427. indent, h.LastBlockID,
  428. indent, h.LastCommitHash,
  429. indent, h.DataHash,
  430. indent, h.ValidatorsHash,
  431. indent, h.NextValidatorsHash,
  432. indent, h.AppHash,
  433. indent, h.ConsensusHash,
  434. indent, h.LastResultsHash,
  435. indent, h.EvidenceHash,
  436. indent, h.ProposerAddress,
  437. indent, h.Hash())
  438. }
  439. // ToProto converts Header to protobuf
  440. func (h *Header) ToProto() *tmproto.Header {
  441. if h == nil {
  442. return nil
  443. }
  444. return &tmproto.Header{
  445. Version: h.Version,
  446. ChainID: h.ChainID,
  447. Height: h.Height,
  448. Time: h.Time,
  449. LastBlockId: h.LastBlockID.ToProto(),
  450. ValidatorsHash: h.ValidatorsHash,
  451. NextValidatorsHash: h.NextValidatorsHash,
  452. ConsensusHash: h.ConsensusHash,
  453. AppHash: h.AppHash,
  454. DataHash: h.DataHash,
  455. EvidenceHash: h.EvidenceHash,
  456. LastResultsHash: h.LastResultsHash,
  457. LastCommitHash: h.LastCommitHash,
  458. ProposerAddress: h.ProposerAddress,
  459. }
  460. }
  461. // FromProto sets a protobuf Header to the given pointer.
  462. // It returns an error if the header is invalid.
  463. func HeaderFromProto(ph *tmproto.Header) (Header, error) {
  464. if ph == nil {
  465. return Header{}, errors.New("nil Header")
  466. }
  467. h := new(Header)
  468. bi, err := BlockIDFromProto(&ph.LastBlockId)
  469. if err != nil {
  470. return Header{}, err
  471. }
  472. h.Version = ph.Version
  473. h.ChainID = ph.ChainID
  474. h.Height = ph.Height
  475. h.Time = ph.Time
  476. h.Height = ph.Height
  477. h.LastBlockID = *bi
  478. h.ValidatorsHash = ph.ValidatorsHash
  479. h.NextValidatorsHash = ph.NextValidatorsHash
  480. h.ConsensusHash = ph.ConsensusHash
  481. h.AppHash = ph.AppHash
  482. h.DataHash = ph.DataHash
  483. h.EvidenceHash = ph.EvidenceHash
  484. h.LastResultsHash = ph.LastResultsHash
  485. h.LastCommitHash = ph.LastCommitHash
  486. h.ProposerAddress = ph.ProposerAddress
  487. return *h, h.ValidateBasic()
  488. }
  489. //-------------------------------------
  490. // BlockIDFlag indicates which BlockID the signature is for.
  491. type BlockIDFlag byte
  492. const (
  493. // BlockIDFlagAbsent - no vote was received from a validator.
  494. BlockIDFlagAbsent BlockIDFlag = iota + 1
  495. // BlockIDFlagCommit - voted for the Commit.BlockID.
  496. BlockIDFlagCommit
  497. // BlockIDFlagNil - voted for nil.
  498. BlockIDFlagNil
  499. )
  500. // CommitSig is a part of the Vote included in a Commit.
  501. type CommitSig struct {
  502. BlockIDFlag BlockIDFlag `json:"block_id_flag"`
  503. ValidatorAddress Address `json:"validator_address"`
  504. Timestamp time.Time `json:"timestamp"`
  505. Signature []byte `json:"signature"`
  506. }
  507. // NewCommitSigForBlock returns new CommitSig with BlockIDFlagCommit.
  508. func NewCommitSigForBlock(signature []byte, valAddr Address, ts time.Time) CommitSig {
  509. return CommitSig{
  510. BlockIDFlag: BlockIDFlagCommit,
  511. ValidatorAddress: valAddr,
  512. Timestamp: ts,
  513. Signature: signature,
  514. }
  515. }
  516. // ForBlock returns true if CommitSig is for the block.
  517. func (cs CommitSig) ForBlock() bool {
  518. return cs.BlockIDFlag == BlockIDFlagCommit
  519. }
  520. // NewCommitSigAbsent returns new CommitSig with BlockIDFlagAbsent. Other
  521. // fields are all empty.
  522. func NewCommitSigAbsent() CommitSig {
  523. return CommitSig{
  524. BlockIDFlag: BlockIDFlagAbsent,
  525. }
  526. }
  527. // Absent returns true if CommitSig is absent.
  528. func (cs CommitSig) Absent() bool {
  529. return cs.BlockIDFlag == BlockIDFlagAbsent
  530. }
  531. func (cs CommitSig) String() string {
  532. return fmt.Sprintf("CommitSig{%X by %X on %v @ %s}",
  533. tmbytes.Fingerprint(cs.Signature),
  534. tmbytes.Fingerprint(cs.ValidatorAddress),
  535. cs.BlockIDFlag,
  536. CanonicalTime(cs.Timestamp))
  537. }
  538. // BlockID returns the Commit's BlockID if CommitSig indicates signing,
  539. // otherwise - empty BlockID.
  540. func (cs CommitSig) BlockID(commitBlockID BlockID) BlockID {
  541. var blockID BlockID
  542. switch cs.BlockIDFlag {
  543. case BlockIDFlagAbsent:
  544. blockID = BlockID{}
  545. case BlockIDFlagCommit:
  546. blockID = commitBlockID
  547. case BlockIDFlagNil:
  548. blockID = BlockID{}
  549. default:
  550. panic(fmt.Sprintf("Unknown BlockIDFlag: %v", cs.BlockIDFlag))
  551. }
  552. return blockID
  553. }
  554. // ValidateBasic performs basic validation.
  555. func (cs CommitSig) ValidateBasic() error {
  556. switch cs.BlockIDFlag {
  557. case BlockIDFlagAbsent:
  558. case BlockIDFlagCommit:
  559. case BlockIDFlagNil:
  560. default:
  561. return fmt.Errorf("unknown BlockIDFlag: %v", cs.BlockIDFlag)
  562. }
  563. switch cs.BlockIDFlag {
  564. case BlockIDFlagAbsent:
  565. if len(cs.ValidatorAddress) != 0 {
  566. return errors.New("validator address is present")
  567. }
  568. if !cs.Timestamp.IsZero() {
  569. return errors.New("time is present")
  570. }
  571. if len(cs.Signature) != 0 {
  572. return errors.New("signature is present")
  573. }
  574. default:
  575. if len(cs.ValidatorAddress) != crypto.AddressSize {
  576. return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes",
  577. crypto.AddressSize,
  578. len(cs.ValidatorAddress),
  579. )
  580. }
  581. // NOTE: Timestamp validation is subtle and handled elsewhere.
  582. if len(cs.Signature) == 0 {
  583. return errors.New("signature is missing")
  584. }
  585. if len(cs.Signature) > MaxSignatureSize {
  586. return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
  587. }
  588. }
  589. return nil
  590. }
  591. // ToProto converts CommitSig to protobuf
  592. func (cs *CommitSig) ToProto() *tmproto.CommitSig {
  593. if cs == nil {
  594. return nil
  595. }
  596. return &tmproto.CommitSig{
  597. BlockIdFlag: tmproto.BlockIDFlag(cs.BlockIDFlag),
  598. ValidatorAddress: cs.ValidatorAddress,
  599. Timestamp: cs.Timestamp,
  600. Signature: cs.Signature,
  601. }
  602. }
  603. // FromProto sets a protobuf CommitSig to the given pointer.
  604. // It returns an error if the CommitSig is invalid.
  605. func (cs *CommitSig) FromProto(csp tmproto.CommitSig) error {
  606. cs.BlockIDFlag = BlockIDFlag(csp.BlockIdFlag)
  607. cs.ValidatorAddress = csp.ValidatorAddress
  608. cs.Timestamp = csp.Timestamp
  609. cs.Signature = csp.Signature
  610. return cs.ValidateBasic()
  611. }
  612. //-------------------------------------
  613. // Commit contains the evidence that a block was committed by a set of validators.
  614. // NOTE: Commit is empty for height 1, but never nil.
  615. type Commit struct {
  616. // NOTE: The signatures are in order of address to preserve the bonded
  617. // ValidatorSet order.
  618. // Any peer with a block can gossip signatures by index with a peer without
  619. // recalculating the active ValidatorSet.
  620. Height int64 `json:"height"`
  621. Round int32 `json:"round"`
  622. BlockID BlockID `json:"block_id"`
  623. Signatures []CommitSig `json:"signatures"`
  624. // Memoized in first call to corresponding method.
  625. // NOTE: can't memoize in constructor because constructor isn't used for
  626. // unmarshaling.
  627. hash tmbytes.HexBytes
  628. bitArray *bits.BitArray
  629. }
  630. // NewCommit returns a new Commit.
  631. func NewCommit(height int64, round int32, blockID BlockID, commitSigs []CommitSig) *Commit {
  632. return &Commit{
  633. Height: height,
  634. Round: round,
  635. BlockID: blockID,
  636. Signatures: commitSigs,
  637. }
  638. }
  639. // CommitToVoteSet constructs a VoteSet from the Commit and validator set.
  640. // Panics if signatures from the commit can't be added to the voteset.
  641. // Inverse of VoteSet.MakeCommit().
  642. func CommitToVoteSet(chainID string, commit *Commit, vals *ValidatorSet) *VoteSet {
  643. voteSet := NewVoteSet(chainID, commit.Height, commit.Round, tmproto.PrecommitType, vals)
  644. for idx, commitSig := range commit.Signatures {
  645. if commitSig.Absent() {
  646. continue // OK, some precommits can be missing.
  647. }
  648. added, err := voteSet.AddVote(commit.GetVote(int32(idx)))
  649. if !added || err != nil {
  650. panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err))
  651. }
  652. }
  653. return voteSet
  654. }
  655. // GetVote converts the CommitSig for the given valIdx to a Vote.
  656. // Returns nil if the precommit at valIdx is nil.
  657. // Panics if valIdx >= commit.Size().
  658. func (commit *Commit) GetVote(valIdx int32) *Vote {
  659. commitSig := commit.Signatures[valIdx]
  660. return &Vote{
  661. Type: tmproto.PrecommitType,
  662. Height: commit.Height,
  663. Round: commit.Round,
  664. BlockID: commitSig.BlockID(commit.BlockID),
  665. Timestamp: commitSig.Timestamp,
  666. ValidatorAddress: commitSig.ValidatorAddress,
  667. ValidatorIndex: valIdx,
  668. Signature: commitSig.Signature,
  669. }
  670. }
  671. // VoteSignBytes constructs the SignBytes for the given CommitSig.
  672. // The only unique part of the SignBytes is the Timestamp - all other fields
  673. // signed over are otherwise the same for all validators.
  674. // Panics if valIdx >= commit.Size().
  675. func (commit *Commit) VoteSignBytes(chainID string, valIdx int32) []byte {
  676. return commit.GetVote(valIdx).SignBytes(chainID)
  677. }
  678. // Type returns the vote type of the commit, which is always VoteTypePrecommit
  679. // Implements VoteSetReader.
  680. func (commit *Commit) Type() byte {
  681. return byte(tmproto.PrecommitType)
  682. }
  683. // GetHeight returns height of the commit.
  684. // Implements VoteSetReader.
  685. func (commit *Commit) GetHeight() int64 {
  686. return commit.Height
  687. }
  688. // GetRound returns height of the commit.
  689. // Implements VoteSetReader.
  690. func (commit *Commit) GetRound() int32 {
  691. return commit.Round
  692. }
  693. // Size returns the number of signatures in the commit.
  694. // Implements VoteSetReader.
  695. func (commit *Commit) Size() int {
  696. if commit == nil {
  697. return 0
  698. }
  699. return len(commit.Signatures)
  700. }
  701. // BitArray returns a BitArray of which validators voted for BlockID or nil in this commit.
  702. // Implements VoteSetReader.
  703. func (commit *Commit) BitArray() *bits.BitArray {
  704. if commit.bitArray == nil {
  705. commit.bitArray = bits.NewBitArray(len(commit.Signatures))
  706. for i, commitSig := range commit.Signatures {
  707. // TODO: need to check the BlockID otherwise we could be counting conflicts,
  708. // not just the one with +2/3 !
  709. commit.bitArray.SetIndex(i, !commitSig.Absent())
  710. }
  711. }
  712. return commit.bitArray
  713. }
  714. // GetByIndex returns the vote corresponding to a given validator index.
  715. // Panics if `index >= commit.Size()`.
  716. // Implements VoteSetReader.
  717. func (commit *Commit) GetByIndex(valIdx int32) *Vote {
  718. return commit.GetVote(valIdx)
  719. }
  720. // IsCommit returns true if there is at least one signature.
  721. // Implements VoteSetReader.
  722. func (commit *Commit) IsCommit() bool {
  723. return len(commit.Signatures) != 0
  724. }
  725. // ValidateBasic performs basic validation that doesn't involve state data.
  726. // Does not actually check the cryptographic signatures.
  727. func (commit *Commit) ValidateBasic() error {
  728. if commit.Height < 0 {
  729. return errors.New("negative Height")
  730. }
  731. if commit.Round < 0 {
  732. return errors.New("negative Round")
  733. }
  734. if commit.Height >= 1 {
  735. if commit.BlockID.IsZero() {
  736. return errors.New("commit cannot be for nil block")
  737. }
  738. if len(commit.Signatures) == 0 {
  739. return errors.New("no signatures in commit")
  740. }
  741. for i, commitSig := range commit.Signatures {
  742. if err := commitSig.ValidateBasic(); err != nil {
  743. return fmt.Errorf("wrong CommitSig #%d: %v", i, err)
  744. }
  745. }
  746. }
  747. return nil
  748. }
  749. // Hash returns the hash of the commit
  750. func (commit *Commit) Hash() tmbytes.HexBytes {
  751. if commit == nil {
  752. return nil
  753. }
  754. if commit.hash == nil {
  755. bs := make([][]byte, len(commit.Signatures))
  756. for i, commitSig := range commit.Signatures {
  757. bs[i] = cdcEncode(commitSig)
  758. }
  759. commit.hash = merkle.SimpleHashFromByteSlices(bs)
  760. }
  761. return commit.hash
  762. }
  763. // StringIndented returns a string representation of the commit
  764. func (commit *Commit) StringIndented(indent string) string {
  765. if commit == nil {
  766. return "nil-Commit"
  767. }
  768. commitSigStrings := make([]string, len(commit.Signatures))
  769. for i, commitSig := range commit.Signatures {
  770. commitSigStrings[i] = commitSig.String()
  771. }
  772. return fmt.Sprintf(`Commit{
  773. %s Height: %d
  774. %s Round: %d
  775. %s BlockID: %v
  776. %s Signatures:
  777. %s %v
  778. %s}#%v`,
  779. indent, commit.Height,
  780. indent, commit.Round,
  781. indent, commit.BlockID,
  782. indent,
  783. indent, strings.Join(commitSigStrings, "\n"+indent+" "),
  784. indent, commit.hash)
  785. }
  786. // ToProto converts Commit to protobuf
  787. func (commit *Commit) ToProto() *tmproto.Commit {
  788. if commit == nil {
  789. return nil
  790. }
  791. c := new(tmproto.Commit)
  792. sigs := make([]tmproto.CommitSig, len(commit.Signatures))
  793. for i := range commit.Signatures {
  794. sigs[i] = *commit.Signatures[i].ToProto()
  795. }
  796. c.Signatures = sigs
  797. c.Height = commit.Height
  798. c.Round = commit.Round
  799. c.BlockID = commit.BlockID.ToProto()
  800. if commit.hash != nil {
  801. c.Hash = commit.hash
  802. }
  803. c.BitArray = commit.bitArray.ToProto()
  804. return c
  805. }
  806. // FromProto sets a protobuf Commit to the given pointer.
  807. // It returns an error if the commit is invalid.
  808. func CommitFromProto(cp *tmproto.Commit) (*Commit, error) {
  809. if cp == nil {
  810. return nil, errors.New("nil Commit")
  811. }
  812. var (
  813. commit = new(Commit)
  814. bitArray *bits.BitArray
  815. )
  816. bi, err := BlockIDFromProto(&cp.BlockID)
  817. if err != nil {
  818. return nil, err
  819. }
  820. bitArray.FromProto(cp.BitArray)
  821. sigs := make([]CommitSig, len(cp.Signatures))
  822. for i := range cp.Signatures {
  823. if err := sigs[i].FromProto(cp.Signatures[i]); err != nil {
  824. return nil, err
  825. }
  826. }
  827. commit.Signatures = sigs
  828. commit.Height = cp.Height
  829. commit.Round = cp.Round
  830. commit.BlockID = *bi
  831. commit.hash = cp.Hash
  832. commit.bitArray = bitArray
  833. return commit, commit.ValidateBasic()
  834. }
  835. //-----------------------------------------------------------------------------
  836. // SignedHeader is a header along with the commits that prove it.
  837. // It is the basis of the light client.
  838. type SignedHeader struct {
  839. *Header `json:"header"`
  840. Commit *Commit `json:"commit"`
  841. }
  842. // ValidateBasic does basic consistency checks and makes sure the header
  843. // and commit are consistent.
  844. //
  845. // NOTE: This does not actually check the cryptographic signatures. Make sure
  846. // to use a Verifier to validate the signatures actually provide a
  847. // significantly strong proof for this header's validity.
  848. func (sh SignedHeader) ValidateBasic(chainID string) error {
  849. if sh.Header == nil {
  850. return errors.New("missing header")
  851. }
  852. if sh.Commit == nil {
  853. return errors.New("missing commit")
  854. }
  855. if err := sh.Header.ValidateBasic(); err != nil {
  856. return fmt.Errorf("invalid header: %w", err)
  857. }
  858. if err := sh.Commit.ValidateBasic(); err != nil {
  859. return fmt.Errorf("invalid commit: %w", err)
  860. }
  861. if sh.ChainID != chainID {
  862. return fmt.Errorf("header belongs to another chain %q, not %q", sh.ChainID, chainID)
  863. }
  864. // Make sure the header is consistent with the commit.
  865. if sh.Commit.Height != sh.Height {
  866. return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
  867. }
  868. if hhash, chash := sh.Hash(), sh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) {
  869. return fmt.Errorf("commit signs block %X, header is block %X", chash, hhash)
  870. }
  871. return nil
  872. }
  873. func (sh SignedHeader) String() string {
  874. return sh.StringIndented("")
  875. }
  876. // StringIndented returns a string representation of the SignedHeader.
  877. func (sh SignedHeader) StringIndented(indent string) string {
  878. return fmt.Sprintf(`SignedHeader{
  879. %s %v
  880. %s %v
  881. %s}`,
  882. indent, sh.Header.StringIndented(indent+" "),
  883. indent, sh.Commit.StringIndented(indent+" "),
  884. indent)
  885. }
  886. // ToProto converts SignedHeader to protobuf
  887. func (sh *SignedHeader) ToProto() *tmproto.SignedHeader {
  888. if sh == nil {
  889. return nil
  890. }
  891. psh := new(tmproto.SignedHeader)
  892. if sh.Header != nil {
  893. psh.Header = sh.Header.ToProto()
  894. }
  895. if sh.Commit != nil {
  896. psh.Commit = sh.Commit.ToProto()
  897. }
  898. return psh
  899. }
  900. // FromProto sets a protobuf SignedHeader to the given pointer.
  901. // It returns an error if the hader or the commit is invalid.
  902. func SignedHeaderFromProto(shp *tmproto.SignedHeader) (*SignedHeader, error) {
  903. if shp == nil {
  904. return nil, errors.New("nil SignedHeader")
  905. }
  906. sh := new(SignedHeader)
  907. if shp.Header != nil {
  908. h, err := HeaderFromProto(shp.Header)
  909. if err != nil {
  910. return nil, err
  911. }
  912. sh.Header = &h
  913. }
  914. if shp.Commit != nil {
  915. c, err := CommitFromProto(shp.Commit)
  916. if err != nil {
  917. return nil, err
  918. }
  919. sh.Commit = c
  920. }
  921. return sh, nil
  922. }
  923. //-----------------------------------------------------------------------------
  924. // Data contains the set of transactions included in the block
  925. type Data struct {
  926. // Txs that will be applied by state @ block.Height+1.
  927. // NOTE: not all txs here are valid. We're just agreeing on the order first.
  928. // This means that block.AppHash does not include these txs.
  929. Txs Txs `json:"txs"`
  930. // Volatile
  931. hash tmbytes.HexBytes
  932. }
  933. // Hash returns the hash of the data
  934. func (data *Data) Hash() tmbytes.HexBytes {
  935. if data == nil {
  936. return (Txs{}).Hash()
  937. }
  938. if data.hash == nil {
  939. data.hash = data.Txs.Hash() // NOTE: leaves of merkle tree are TxIDs
  940. }
  941. return data.hash
  942. }
  943. // StringIndented returns a string representation of the transactions
  944. func (data *Data) StringIndented(indent string) string {
  945. if data == nil {
  946. return "nil-Data"
  947. }
  948. txStrings := make([]string, tmmath.MinInt(len(data.Txs), 21))
  949. for i, tx := range data.Txs {
  950. if i == 20 {
  951. txStrings[i] = fmt.Sprintf("... (%v total)", len(data.Txs))
  952. break
  953. }
  954. txStrings[i] = fmt.Sprintf("%X (%d bytes)", tx.Hash(), len(tx))
  955. }
  956. return fmt.Sprintf(`Data{
  957. %s %v
  958. %s}#%v`,
  959. indent, strings.Join(txStrings, "\n"+indent+" "),
  960. indent, data.hash)
  961. }
  962. // ToProto converts Data to protobuf
  963. func (data *Data) ToProto() tmproto.Data {
  964. tp := new(tmproto.Data)
  965. if len(data.Txs) > 0 {
  966. txBzs := make([][]byte, len(data.Txs))
  967. for i := range data.Txs {
  968. txBzs[i] = data.Txs[i]
  969. }
  970. tp.Txs = txBzs
  971. }
  972. if data.hash != nil {
  973. tp.Hash = data.hash
  974. }
  975. return *tp
  976. }
  977. // DataFromProto takes a protobud representation of Data &
  978. // returns the native type.
  979. func DataFromProto(dp *tmproto.Data) (Data, error) {
  980. if dp == nil {
  981. return Data{}, errors.New("nil data")
  982. }
  983. data := new(Data)
  984. if len(dp.Txs) > 0 {
  985. txBzs := make(Txs, len(dp.Txs))
  986. for i := range dp.Txs {
  987. txBzs[i] = Tx(dp.Txs[i])
  988. }
  989. data.Txs = txBzs
  990. } else {
  991. data.Txs = Txs{}
  992. }
  993. data.hash = dp.Hash
  994. return *data, nil
  995. }
  996. //-----------------------------------------------------------------------------
  997. // EvidenceData contains any evidence of malicious wrong-doing by validators
  998. type EvidenceData struct {
  999. Evidence EvidenceList `json:"evidence"`
  1000. // Volatile
  1001. hash tmbytes.HexBytes
  1002. }
  1003. // Hash returns the hash of the data.
  1004. func (data *EvidenceData) Hash() tmbytes.HexBytes {
  1005. if data.hash == nil {
  1006. data.hash = data.Evidence.Hash()
  1007. }
  1008. return data.hash
  1009. }
  1010. // StringIndented returns a string representation of the evidence.
  1011. func (data *EvidenceData) StringIndented(indent string) string {
  1012. if data == nil {
  1013. return "nil-Evidence"
  1014. }
  1015. evStrings := make([]string, tmmath.MinInt(len(data.Evidence), 21))
  1016. for i, ev := range data.Evidence {
  1017. if i == 20 {
  1018. evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidence))
  1019. break
  1020. }
  1021. evStrings[i] = fmt.Sprintf("Evidence:%v", ev)
  1022. }
  1023. return fmt.Sprintf(`EvidenceData{
  1024. %s %v
  1025. %s}#%v`,
  1026. indent, strings.Join(evStrings, "\n"+indent+" "),
  1027. indent, data.hash)
  1028. }
  1029. // ToProto converts EvidenceData to protobuf
  1030. func (data *EvidenceData) ToProto() (*tmproto.EvidenceData, error) {
  1031. if data == nil {
  1032. return nil, errors.New("nil evidence data")
  1033. }
  1034. evi := new(tmproto.EvidenceData)
  1035. eviBzs := make([]tmproto.Evidence, len(data.Evidence))
  1036. for i := range data.Evidence {
  1037. protoEvi, err := EvidenceToProto(data.Evidence[i])
  1038. if err != nil {
  1039. return nil, err
  1040. }
  1041. eviBzs[i] = *protoEvi
  1042. }
  1043. evi.Evidence = eviBzs
  1044. if data.hash != nil {
  1045. evi.Hash = data.hash
  1046. }
  1047. return evi, nil
  1048. }
  1049. // FromProto sets a protobuf EvidenceData to the given pointer.
  1050. func (data *EvidenceData) FromProto(eviData *tmproto.EvidenceData) error {
  1051. if eviData == nil {
  1052. return errors.New("nil evidenceData")
  1053. }
  1054. eviBzs := make(EvidenceList, len(eviData.Evidence))
  1055. for i := range eviData.Evidence {
  1056. evi, err := EvidenceFromProto(&eviData.Evidence[i])
  1057. if err != nil {
  1058. return err
  1059. }
  1060. eviBzs[i] = evi
  1061. }
  1062. data.Evidence = eviBzs
  1063. data.hash = eviData.GetHash()
  1064. return nil
  1065. }
  1066. //--------------------------------------------------------------------------------
  1067. // BlockID
  1068. type BlockID struct {
  1069. Hash tmbytes.HexBytes `json:"hash"`
  1070. PartsHeader PartSetHeader `json:"parts"`
  1071. }
  1072. // Equals returns true if the BlockID matches the given BlockID
  1073. func (blockID BlockID) Equals(other BlockID) bool {
  1074. return bytes.Equal(blockID.Hash, other.Hash) &&
  1075. blockID.PartsHeader.Equals(other.PartsHeader)
  1076. }
  1077. // Key returns a machine-readable string representation of the BlockID
  1078. func (blockID BlockID) Key() string {
  1079. bz, err := cdc.MarshalBinaryBare(blockID.PartsHeader)
  1080. if err != nil {
  1081. panic(err)
  1082. }
  1083. return string(blockID.Hash) + string(bz)
  1084. }
  1085. // ValidateBasic performs basic validation.
  1086. func (blockID BlockID) ValidateBasic() error {
  1087. // Hash can be empty in case of POLBlockID in Proposal.
  1088. if err := ValidateHash(blockID.Hash); err != nil {
  1089. return fmt.Errorf("wrong Hash")
  1090. }
  1091. if err := blockID.PartsHeader.ValidateBasic(); err != nil {
  1092. return fmt.Errorf("wrong PartsHeader: %v", err)
  1093. }
  1094. return nil
  1095. }
  1096. // IsZero returns true if this is the BlockID of a nil block.
  1097. func (blockID BlockID) IsZero() bool {
  1098. return len(blockID.Hash) == 0 &&
  1099. blockID.PartsHeader.IsZero()
  1100. }
  1101. // IsComplete returns true if this is a valid BlockID of a non-nil block.
  1102. func (blockID BlockID) IsComplete() bool {
  1103. return len(blockID.Hash) == tmhash.Size &&
  1104. blockID.PartsHeader.Total > 0 &&
  1105. len(blockID.PartsHeader.Hash) == tmhash.Size
  1106. }
  1107. // String returns a human readable string representation of the BlockID
  1108. func (blockID BlockID) String() string {
  1109. return fmt.Sprintf(`%v:%v`, blockID.Hash, blockID.PartsHeader)
  1110. }
  1111. // ToProto converts BlockID to protobuf
  1112. func (blockID *BlockID) ToProto() tmproto.BlockID {
  1113. if blockID == nil {
  1114. return tmproto.BlockID{}
  1115. }
  1116. return tmproto.BlockID{
  1117. Hash: blockID.Hash,
  1118. PartsHeader: blockID.PartsHeader.ToProto(),
  1119. }
  1120. }
  1121. // FromProto sets a protobuf BlockID to the given pointer.
  1122. // It returns an error if the block id is invalid.
  1123. func BlockIDFromProto(bID *tmproto.BlockID) (*BlockID, error) {
  1124. if bID == nil {
  1125. return nil, errors.New("nil BlockID")
  1126. }
  1127. blockID := new(BlockID)
  1128. ph, err := PartSetHeaderFromProto(&bID.PartsHeader)
  1129. if err != nil {
  1130. return nil, err
  1131. }
  1132. blockID.PartsHeader = *ph
  1133. blockID.Hash = bID.Hash
  1134. return blockID, blockID.ValidateBasic()
  1135. }