github.com/evdatsion/aphelion-dpos-bft@v0.32.1/types/block.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/pkg/errors" 11 12 "github.com/evdatsion/aphelion-dpos-bft/crypto" 13 "github.com/evdatsion/aphelion-dpos-bft/crypto/merkle" 14 "github.com/evdatsion/aphelion-dpos-bft/crypto/tmhash" 15 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 16 "github.com/evdatsion/aphelion-dpos-bft/version" 17 ) 18 19 const ( 20 // MaxHeaderBytes is a maximum header size (including amino overhead). 21 MaxHeaderBytes int64 = 653 22 23 // MaxAminoOverheadForBlock - maximum amino overhead to encode a block (up to 24 // MaxBlockSizeBytes in size) not including it's parts except Data. 25 // This means it also excludes the overhead for individual transactions. 26 // To compute individual transactions' overhead use types.ComputeAminoOverhead(tx types.Tx, fieldNum int). 27 // 28 // Uvarint length of MaxBlockSizeBytes: 4 bytes 29 // 2 fields (2 embedded): 2 bytes 30 // Uvarint length of Data.Txs: 4 bytes 31 // Data.Txs field: 1 byte 32 MaxAminoOverheadForBlock int64 = 11 33 ) 34 35 // Block defines the atomic unit of a Tendermint blockchain. 36 type Block struct { 37 mtx sync.Mutex 38 Header `json:"header"` 39 Data `json:"data"` 40 Evidence EvidenceData `json:"evidence"` 41 LastCommit *Commit `json:"last_commit"` 42 } 43 44 // MakeBlock returns a new block with an empty header, except what can be 45 // computed from itself. 46 // It populates the same set of fields validated by ValidateBasic. 47 func MakeBlock(height int64, txs []Tx, lastCommit *Commit, evidence []Evidence) *Block { 48 block := &Block{ 49 Header: Header{ 50 Height: height, 51 NumTxs: int64(len(txs)), 52 }, 53 Data: Data{ 54 Txs: txs, 55 }, 56 Evidence: EvidenceData{Evidence: evidence}, 57 LastCommit: lastCommit, 58 } 59 block.fillHeader() 60 return block 61 } 62 63 // ValidateBasic performs basic validation that doesn't involve state data. 64 // It checks the internal consistency of the block. 65 // Further validation is done using state#ValidateBlock. 66 func (b *Block) ValidateBasic() error { 67 if b == nil { 68 return errors.New("nil block") 69 } 70 b.mtx.Lock() 71 defer b.mtx.Unlock() 72 73 if len(b.ChainID) > MaxChainIDLen { 74 return fmt.Errorf("ChainID is too long. Max is %d, got %d", MaxChainIDLen, len(b.ChainID)) 75 } 76 77 if b.Height < 0 { 78 return errors.New("Negative Header.Height") 79 } else if b.Height == 0 { 80 return errors.New("Zero Header.Height") 81 } 82 83 // NOTE: Timestamp validation is subtle and handled elsewhere. 84 85 newTxs := int64(len(b.Data.Txs)) 86 if b.NumTxs != newTxs { 87 return fmt.Errorf("Wrong Header.NumTxs. Expected %v, got %v", 88 newTxs, 89 b.NumTxs, 90 ) 91 } 92 93 // TODO: fix tests so we can do this 94 /*if b.TotalTxs < b.NumTxs { 95 return fmt.Errorf("Header.TotalTxs (%d) is less than Header.NumTxs (%d)", b.TotalTxs, b.NumTxs) 96 }*/ 97 if b.TotalTxs < 0 { 98 return errors.New("Negative Header.TotalTxs") 99 } 100 101 if err := b.LastBlockID.ValidateBasic(); err != nil { 102 return fmt.Errorf("Wrong Header.LastBlockID: %v", err) 103 } 104 105 // Validate the last commit and its hash. 106 if b.Header.Height > 1 { 107 if b.LastCommit == nil { 108 return errors.New("nil LastCommit") 109 } 110 if err := b.LastCommit.ValidateBasic(); err != nil { 111 return fmt.Errorf("Wrong LastCommit") 112 } 113 } 114 if err := ValidateHash(b.LastCommitHash); err != nil { 115 return fmt.Errorf("Wrong Header.LastCommitHash: %v", err) 116 } 117 if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) { 118 return fmt.Errorf("Wrong Header.LastCommitHash. Expected %v, got %v", 119 b.LastCommit.Hash(), 120 b.LastCommitHash, 121 ) 122 } 123 124 // Validate the hash of the transactions. 125 // NOTE: b.Data.Txs may be nil, but b.Data.Hash() 126 // still works fine 127 if err := ValidateHash(b.DataHash); err != nil { 128 return fmt.Errorf("Wrong Header.DataHash: %v", err) 129 } 130 if !bytes.Equal(b.DataHash, b.Data.Hash()) { 131 return fmt.Errorf( 132 "Wrong Header.DataHash. Expected %v, got %v", 133 b.Data.Hash(), 134 b.DataHash, 135 ) 136 } 137 138 // Basic validation of hashes related to application data. 139 // Will validate fully against state in state#ValidateBlock. 140 if err := ValidateHash(b.ValidatorsHash); err != nil { 141 return fmt.Errorf("Wrong Header.ValidatorsHash: %v", err) 142 } 143 if err := ValidateHash(b.NextValidatorsHash); err != nil { 144 return fmt.Errorf("Wrong Header.NextValidatorsHash: %v", err) 145 } 146 if err := ValidateHash(b.ConsensusHash); err != nil { 147 return fmt.Errorf("Wrong Header.ConsensusHash: %v", err) 148 } 149 // NOTE: AppHash is arbitrary length 150 if err := ValidateHash(b.LastResultsHash); err != nil { 151 return fmt.Errorf("Wrong Header.LastResultsHash: %v", err) 152 } 153 154 // Validate evidence and its hash. 155 if err := ValidateHash(b.EvidenceHash); err != nil { 156 return fmt.Errorf("Wrong Header.EvidenceHash: %v", err) 157 } 158 // NOTE: b.Evidence.Evidence may be nil, but we're just looping. 159 for i, ev := range b.Evidence.Evidence { 160 if err := ev.ValidateBasic(); err != nil { 161 return fmt.Errorf("Invalid evidence (#%d): %v", i, err) 162 } 163 } 164 if !bytes.Equal(b.EvidenceHash, b.Evidence.Hash()) { 165 return fmt.Errorf("Wrong Header.EvidenceHash. Expected %v, got %v", 166 b.EvidenceHash, 167 b.Evidence.Hash(), 168 ) 169 } 170 171 if len(b.ProposerAddress) != crypto.AddressSize { 172 return fmt.Errorf("Expected len(Header.ProposerAddress) to be %d, got %d", 173 crypto.AddressSize, len(b.ProposerAddress)) 174 } 175 176 return nil 177 } 178 179 // fillHeader fills in any remaining header fields that are a function of the block data 180 func (b *Block) fillHeader() { 181 if b.LastCommitHash == nil { 182 b.LastCommitHash = b.LastCommit.Hash() 183 } 184 if b.DataHash == nil { 185 b.DataHash = b.Data.Hash() 186 } 187 if b.EvidenceHash == nil { 188 b.EvidenceHash = b.Evidence.Hash() 189 } 190 } 191 192 // Hash computes and returns the block hash. 193 // If the block is incomplete, block hash is nil for safety. 194 func (b *Block) Hash() cmn.HexBytes { 195 if b == nil { 196 return nil 197 } 198 b.mtx.Lock() 199 defer b.mtx.Unlock() 200 201 if b.LastCommit == nil { 202 return nil 203 } 204 b.fillHeader() 205 return b.Header.Hash() 206 } 207 208 // MakePartSet returns a PartSet containing parts of a serialized block. 209 // This is the form in which the block is gossipped to peers. 210 // CONTRACT: partSize is greater than zero. 211 func (b *Block) MakePartSet(partSize int) *PartSet { 212 if b == nil { 213 return nil 214 } 215 b.mtx.Lock() 216 defer b.mtx.Unlock() 217 218 // We prefix the byte length, so that unmarshaling 219 // can easily happen via a reader. 220 bz, err := cdc.MarshalBinaryLengthPrefixed(b) 221 if err != nil { 222 panic(err) 223 } 224 return NewPartSetFromData(bz, partSize) 225 } 226 227 // HashesTo is a convenience function that checks if a block hashes to the given argument. 228 // Returns false if the block is nil or the hash is empty. 229 func (b *Block) HashesTo(hash []byte) bool { 230 if len(hash) == 0 { 231 return false 232 } 233 if b == nil { 234 return false 235 } 236 return bytes.Equal(b.Hash(), hash) 237 } 238 239 // Size returns size of the block in bytes. 240 func (b *Block) Size() int { 241 bz, err := cdc.MarshalBinaryBare(b) 242 if err != nil { 243 return 0 244 } 245 return len(bz) 246 } 247 248 // String returns a string representation of the block 249 func (b *Block) String() string { 250 return b.StringIndented("") 251 } 252 253 // StringIndented returns a string representation of the block 254 func (b *Block) StringIndented(indent string) string { 255 if b == nil { 256 return "nil-Block" 257 } 258 return fmt.Sprintf(`Block{ 259 %s %v 260 %s %v 261 %s %v 262 %s %v 263 %s}#%v`, 264 indent, b.Header.StringIndented(indent+" "), 265 indent, b.Data.StringIndented(indent+" "), 266 indent, b.Evidence.StringIndented(indent+" "), 267 indent, b.LastCommit.StringIndented(indent+" "), 268 indent, b.Hash()) 269 } 270 271 // StringShort returns a shortened string representation of the block 272 func (b *Block) StringShort() string { 273 if b == nil { 274 return "nil-Block" 275 } 276 return fmt.Sprintf("Block#%v", b.Hash()) 277 } 278 279 //----------------------------------------------------------- 280 // These methods are for Protobuf Compatibility 281 282 // Marshal returns the amino encoding. 283 func (b *Block) Marshal() ([]byte, error) { 284 return cdc.MarshalBinaryBare(b) 285 } 286 287 // MarshalTo calls Marshal and copies to the given buffer. 288 func (b *Block) MarshalTo(data []byte) (int, error) { 289 bs, err := b.Marshal() 290 if err != nil { 291 return -1, err 292 } 293 return copy(data, bs), nil 294 } 295 296 // Unmarshal deserializes from amino encoded form. 297 func (b *Block) Unmarshal(bs []byte) error { 298 return cdc.UnmarshalBinaryBare(bs, b) 299 } 300 301 //----------------------------------------------------------------------------- 302 303 // MaxDataBytes returns the maximum size of block's data. 304 // 305 // XXX: Panics on negative result. 306 func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 { 307 maxDataBytes := maxBytes - 308 MaxAminoOverheadForBlock - 309 MaxHeaderBytes - 310 int64(valsCount)*MaxVoteBytes - 311 int64(evidenceCount)*MaxEvidenceBytes 312 313 if maxDataBytes < 0 { 314 panic(fmt.Sprintf( 315 "Negative MaxDataBytes. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d", 316 maxBytes, 317 -(maxDataBytes - maxBytes), 318 )) 319 } 320 321 return maxDataBytes 322 323 } 324 325 // MaxDataBytesUnknownEvidence returns the maximum size of block's data when 326 // evidence count is unknown. MaxEvidencePerBlock will be used for the size 327 // of evidence. 328 // 329 // XXX: Panics on negative result. 330 func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int) int64 { 331 _, maxEvidenceBytes := MaxEvidencePerBlock(maxBytes) 332 maxDataBytes := maxBytes - 333 MaxAminoOverheadForBlock - 334 MaxHeaderBytes - 335 int64(valsCount)*MaxVoteBytes - 336 maxEvidenceBytes 337 338 if maxDataBytes < 0 { 339 panic(fmt.Sprintf( 340 "Negative MaxDataBytesUnknownEvidence. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d", 341 maxBytes, 342 -(maxDataBytes - maxBytes), 343 )) 344 } 345 346 return maxDataBytes 347 } 348 349 //----------------------------------------------------------------------------- 350 351 // Header defines the structure of a Tendermint block header. 352 // NOTE: changes to the Header should be duplicated in: 353 // - header.Hash() 354 // - abci.Header 355 // - /docs/spec/blockchain/blockchain.md 356 type Header struct { 357 // basic block info 358 Version version.Consensus `json:"version"` 359 ChainID string `json:"chain_id"` 360 Height int64 `json:"height"` 361 Time time.Time `json:"time"` 362 NumTxs int64 `json:"num_txs"` 363 TotalTxs int64 `json:"total_txs"` 364 365 // prev block info 366 LastBlockID BlockID `json:"last_block_id"` 367 368 // hashes of block data 369 LastCommitHash cmn.HexBytes `json:"last_commit_hash"` // commit from validators from the last block 370 DataHash cmn.HexBytes `json:"data_hash"` // transactions 371 372 // hashes from the app output from the prev block 373 ValidatorsHash cmn.HexBytes `json:"validators_hash"` // validators for the current block 374 NextValidatorsHash cmn.HexBytes `json:"next_validators_hash"` // validators for the next block 375 ConsensusHash cmn.HexBytes `json:"consensus_hash"` // consensus params for current block 376 AppHash cmn.HexBytes `json:"app_hash"` // state after txs from the previous block 377 LastResultsHash cmn.HexBytes `json:"last_results_hash"` // root hash of all results from the txs from the previous block 378 379 // consensus info 380 EvidenceHash cmn.HexBytes `json:"evidence_hash"` // evidence included in the block 381 ProposerAddress Address `json:"proposer_address"` // original proposer of the block 382 } 383 384 // Populate the Header with state-derived data. 385 // Call this after MakeBlock to complete the Header. 386 func (h *Header) Populate( 387 version version.Consensus, chainID string, 388 timestamp time.Time, lastBlockID BlockID, totalTxs int64, 389 valHash, nextValHash []byte, 390 consensusHash, appHash, lastResultsHash []byte, 391 proposerAddress Address, 392 ) { 393 h.Version = version 394 h.ChainID = chainID 395 h.Time = timestamp 396 h.LastBlockID = lastBlockID 397 h.TotalTxs = totalTxs 398 h.ValidatorsHash = valHash 399 h.NextValidatorsHash = nextValHash 400 h.ConsensusHash = consensusHash 401 h.AppHash = appHash 402 h.LastResultsHash = lastResultsHash 403 h.ProposerAddress = proposerAddress 404 } 405 406 // Hash returns the hash of the header. 407 // It computes a Merkle tree from the header fields 408 // ordered as they appear in the Header. 409 // Returns nil if ValidatorHash is missing, 410 // since a Header is not valid unless there is 411 // a ValidatorsHash (corresponding to the validator set). 412 func (h *Header) Hash() cmn.HexBytes { 413 if h == nil || len(h.ValidatorsHash) == 0 { 414 return nil 415 } 416 return merkle.SimpleHashFromByteSlices([][]byte{ 417 cdcEncode(h.Version), 418 cdcEncode(h.ChainID), 419 cdcEncode(h.Height), 420 cdcEncode(h.Time), 421 cdcEncode(h.NumTxs), 422 cdcEncode(h.TotalTxs), 423 cdcEncode(h.LastBlockID), 424 cdcEncode(h.LastCommitHash), 425 cdcEncode(h.DataHash), 426 cdcEncode(h.ValidatorsHash), 427 cdcEncode(h.NextValidatorsHash), 428 cdcEncode(h.ConsensusHash), 429 cdcEncode(h.AppHash), 430 cdcEncode(h.LastResultsHash), 431 cdcEncode(h.EvidenceHash), 432 cdcEncode(h.ProposerAddress), 433 }) 434 } 435 436 // StringIndented returns a string representation of the header 437 func (h *Header) StringIndented(indent string) string { 438 if h == nil { 439 return "nil-Header" 440 } 441 return fmt.Sprintf(`Header{ 442 %s Version: %v 443 %s ChainID: %v 444 %s Height: %v 445 %s Time: %v 446 %s NumTxs: %v 447 %s TotalTxs: %v 448 %s LastBlockID: %v 449 %s LastCommit: %v 450 %s Data: %v 451 %s Validators: %v 452 %s NextValidators: %v 453 %s App: %v 454 %s Consensus: %v 455 %s Results: %v 456 %s Evidence: %v 457 %s Proposer: %v 458 %s}#%v`, 459 indent, h.Version, 460 indent, h.ChainID, 461 indent, h.Height, 462 indent, h.Time, 463 indent, h.NumTxs, 464 indent, h.TotalTxs, 465 indent, h.LastBlockID, 466 indent, h.LastCommitHash, 467 indent, h.DataHash, 468 indent, h.ValidatorsHash, 469 indent, h.NextValidatorsHash, 470 indent, h.AppHash, 471 indent, h.ConsensusHash, 472 indent, h.LastResultsHash, 473 indent, h.EvidenceHash, 474 indent, h.ProposerAddress, 475 indent, h.Hash()) 476 } 477 478 //------------------------------------- 479 480 // CommitSig is a vote included in a Commit. 481 // For now, it is identical to a vote, 482 // but in the future it will contain fewer fields 483 // to eliminate the redundancy in commits. 484 // See https://github.com/evdatsion/aphelion-dpos-bft/issues/1648. 485 type CommitSig Vote 486 487 // String returns the underlying Vote.String() 488 func (cs *CommitSig) String() string { 489 return cs.toVote().String() 490 } 491 492 // toVote converts the CommitSig to a vote. 493 // TODO: deprecate for #1648. Converting to Vote will require 494 // access to ValidatorSet. 495 func (cs *CommitSig) toVote() *Vote { 496 if cs == nil { 497 return nil 498 } 499 v := Vote(*cs) 500 return &v 501 } 502 503 //------------------------------------- 504 505 // Commit contains the evidence that a block was committed by a set of validators. 506 // NOTE: Commit is empty for height 1, but never nil. 507 type Commit struct { 508 // NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order. 509 // Any peer with a block can gossip precommits by index with a peer without recalculating the 510 // active ValidatorSet. 511 BlockID BlockID `json:"block_id"` 512 Precommits []*CommitSig `json:"precommits"` 513 514 // memoized in first call to corresponding method 515 // NOTE: can't memoize in constructor because constructor 516 // isn't used for unmarshaling 517 height int64 518 round int 519 hash cmn.HexBytes 520 bitArray *cmn.BitArray 521 } 522 523 // NewCommit returns a new Commit with the given blockID and precommits. 524 // TODO: memoize ValidatorSet in constructor so votes can be easily reconstructed 525 // from CommitSig after #1648. 526 func NewCommit(blockID BlockID, precommits []*CommitSig) *Commit { 527 return &Commit{ 528 BlockID: blockID, 529 Precommits: precommits, 530 } 531 } 532 533 // Construct a VoteSet from the Commit and validator set. Panics 534 // if precommits from the commit can't be added to the voteset. 535 // Inverse of VoteSet.MakeCommit(). 536 func CommitToVoteSet(chainID string, commit *Commit, vals *ValidatorSet) *VoteSet { 537 height, round, typ := commit.Height(), commit.Round(), PrecommitType 538 voteSet := NewVoteSet(chainID, height, round, typ, vals) 539 for idx, precommit := range commit.Precommits { 540 if precommit == nil { 541 continue 542 } 543 added, err := voteSet.AddVote(commit.GetVote(idx)) 544 if !added || err != nil { 545 panic(fmt.Sprintf("Failed to reconstruct LastCommit: %v", err)) 546 } 547 } 548 return voteSet 549 } 550 551 // GetVote converts the CommitSig for the given valIdx to a Vote. 552 // Returns nil if the precommit at valIdx is nil. 553 // Panics if valIdx >= commit.Size(). 554 func (commit *Commit) GetVote(valIdx int) *Vote { 555 commitSig := commit.Precommits[valIdx] 556 if commitSig == nil { 557 return nil 558 } 559 560 // NOTE: this commitSig might be for a nil blockID, 561 // so we can't just use commit.BlockID here. 562 // For #1648, CommitSig will need to indicate what BlockID it's for ! 563 blockID := commitSig.BlockID 564 commit.memoizeHeightRound() 565 return &Vote{ 566 Type: PrecommitType, 567 Height: commit.height, 568 Round: commit.round, 569 BlockID: blockID, 570 Timestamp: commitSig.Timestamp, 571 ValidatorAddress: commitSig.ValidatorAddress, 572 ValidatorIndex: valIdx, 573 Signature: commitSig.Signature, 574 } 575 } 576 577 // VoteSignBytes constructs the SignBytes for the given CommitSig. 578 // The only unique part of the SignBytes is the Timestamp - all other fields 579 // signed over are otherwise the same for all validators. 580 // Panics if valIdx >= commit.Size(). 581 func (commit *Commit) VoteSignBytes(chainID string, valIdx int) []byte { 582 return commit.GetVote(valIdx).SignBytes(chainID) 583 } 584 585 // memoizeHeightRound memoizes the height and round of the commit using 586 // the first non-nil vote. 587 // Should be called before any attempt to access `commit.height` or `commit.round`. 588 func (commit *Commit) memoizeHeightRound() { 589 if len(commit.Precommits) == 0 { 590 return 591 } 592 if commit.height > 0 { 593 return 594 } 595 for _, precommit := range commit.Precommits { 596 if precommit != nil { 597 commit.height = precommit.Height 598 commit.round = precommit.Round 599 return 600 } 601 } 602 } 603 604 // Height returns the height of the commit 605 func (commit *Commit) Height() int64 { 606 commit.memoizeHeightRound() 607 return commit.height 608 } 609 610 // Round returns the round of the commit 611 func (commit *Commit) Round() int { 612 commit.memoizeHeightRound() 613 return commit.round 614 } 615 616 // Type returns the vote type of the commit, which is always VoteTypePrecommit 617 func (commit *Commit) Type() byte { 618 return byte(PrecommitType) 619 } 620 621 // Size returns the number of votes in the commit 622 func (commit *Commit) Size() int { 623 if commit == nil { 624 return 0 625 } 626 return len(commit.Precommits) 627 } 628 629 // BitArray returns a BitArray of which validators voted in this commit 630 func (commit *Commit) BitArray() *cmn.BitArray { 631 if commit.bitArray == nil { 632 commit.bitArray = cmn.NewBitArray(len(commit.Precommits)) 633 for i, precommit := range commit.Precommits { 634 // TODO: need to check the BlockID otherwise we could be counting conflicts, 635 // not just the one with +2/3 ! 636 commit.bitArray.SetIndex(i, precommit != nil) 637 } 638 } 639 return commit.bitArray 640 } 641 642 // GetByIndex returns the vote corresponding to a given validator index. 643 // Panics if `index >= commit.Size()`. 644 // Implements VoteSetReader. 645 func (commit *Commit) GetByIndex(valIdx int) *Vote { 646 return commit.GetVote(valIdx) 647 } 648 649 // IsCommit returns true if there is at least one vote. 650 func (commit *Commit) IsCommit() bool { 651 return len(commit.Precommits) != 0 652 } 653 654 // ValidateBasic performs basic validation that doesn't involve state data. 655 // Does not actually check the cryptographic signatures. 656 func (commit *Commit) ValidateBasic() error { 657 if commit.BlockID.IsZero() { 658 return errors.New("Commit cannot be for nil block") 659 } 660 if len(commit.Precommits) == 0 { 661 return errors.New("No precommits in commit") 662 } 663 height, round := commit.Height(), commit.Round() 664 665 // Validate the precommits. 666 for _, precommit := range commit.Precommits { 667 // It's OK for precommits to be missing. 668 if precommit == nil { 669 continue 670 } 671 // Ensure that all votes are precommits. 672 if precommit.Type != PrecommitType { 673 return fmt.Errorf("Invalid commit vote. Expected precommit, got %v", 674 precommit.Type) 675 } 676 // Ensure that all heights are the same. 677 if precommit.Height != height { 678 return fmt.Errorf("Invalid commit precommit height. Expected %v, got %v", 679 height, precommit.Height) 680 } 681 // Ensure that all rounds are the same. 682 if precommit.Round != round { 683 return fmt.Errorf("Invalid commit precommit round. Expected %v, got %v", 684 round, precommit.Round) 685 } 686 } 687 return nil 688 } 689 690 // Hash returns the hash of the commit 691 func (commit *Commit) Hash() cmn.HexBytes { 692 if commit == nil { 693 return nil 694 } 695 if commit.hash == nil { 696 bs := make([][]byte, len(commit.Precommits)) 697 for i, precommit := range commit.Precommits { 698 bs[i] = cdcEncode(precommit) 699 } 700 commit.hash = merkle.SimpleHashFromByteSlices(bs) 701 } 702 return commit.hash 703 } 704 705 // StringIndented returns a string representation of the commit 706 func (commit *Commit) StringIndented(indent string) string { 707 if commit == nil { 708 return "nil-Commit" 709 } 710 precommitStrings := make([]string, len(commit.Precommits)) 711 for i, precommit := range commit.Precommits { 712 precommitStrings[i] = precommit.String() 713 } 714 return fmt.Sprintf(`Commit{ 715 %s BlockID: %v 716 %s Precommits: 717 %s %v 718 %s}#%v`, 719 indent, commit.BlockID, 720 indent, 721 indent, strings.Join(precommitStrings, "\n"+indent+" "), 722 indent, commit.hash) 723 } 724 725 //----------------------------------------------------------------------------- 726 727 // SignedHeader is a header along with the commits that prove it. 728 // It is the basis of the lite client. 729 type SignedHeader struct { 730 *Header `json:"header"` 731 Commit *Commit `json:"commit"` 732 } 733 734 // ValidateBasic does basic consistency checks and makes sure the header 735 // and commit are consistent. 736 // 737 // NOTE: This does not actually check the cryptographic signatures. Make 738 // sure to use a Verifier to validate the signatures actually provide a 739 // significantly strong proof for this header's validity. 740 func (sh SignedHeader) ValidateBasic(chainID string) error { 741 742 // Make sure the header is consistent with the commit. 743 if sh.Header == nil { 744 return errors.New("SignedHeader missing header.") 745 } 746 if sh.Commit == nil { 747 return errors.New("SignedHeader missing commit (precommit votes).") 748 } 749 750 // Check ChainID. 751 if sh.ChainID != chainID { 752 return fmt.Errorf("Header belongs to another chain '%s' not '%s'", 753 sh.ChainID, chainID) 754 } 755 // Check Height. 756 if sh.Commit.Height() != sh.Height { 757 return fmt.Errorf("SignedHeader header and commit height mismatch: %v vs %v", 758 sh.Height, sh.Commit.Height()) 759 } 760 // Check Hash. 761 hhash := sh.Hash() 762 chash := sh.Commit.BlockID.Hash 763 if !bytes.Equal(hhash, chash) { 764 return fmt.Errorf("SignedHeader commit signs block %X, header is block %X", 765 chash, hhash) 766 } 767 // ValidateBasic on the Commit. 768 err := sh.Commit.ValidateBasic() 769 if err != nil { 770 return cmn.ErrorWrap(err, "commit.ValidateBasic failed during SignedHeader.ValidateBasic") 771 } 772 return nil 773 } 774 775 func (sh SignedHeader) String() string { 776 return sh.StringIndented("") 777 } 778 779 // StringIndented returns a string representation of the SignedHeader. 780 func (sh SignedHeader) StringIndented(indent string) string { 781 return fmt.Sprintf(`SignedHeader{ 782 %s %v 783 %s %v 784 %s}`, 785 indent, sh.Header.StringIndented(indent+" "), 786 indent, sh.Commit.StringIndented(indent+" "), 787 indent) 788 } 789 790 //----------------------------------------------------------------------------- 791 792 // Data contains the set of transactions included in the block 793 type Data struct { 794 795 // Txs that will be applied by state @ block.Height+1. 796 // NOTE: not all txs here are valid. We're just agreeing on the order first. 797 // This means that block.AppHash does not include these txs. 798 Txs Txs `json:"txs"` 799 800 // Volatile 801 hash cmn.HexBytes 802 } 803 804 // Hash returns the hash of the data 805 func (data *Data) Hash() cmn.HexBytes { 806 if data == nil { 807 return (Txs{}).Hash() 808 } 809 if data.hash == nil { 810 data.hash = data.Txs.Hash() // NOTE: leaves of merkle tree are TxIDs 811 } 812 return data.hash 813 } 814 815 // StringIndented returns a string representation of the transactions 816 func (data *Data) StringIndented(indent string) string { 817 if data == nil { 818 return "nil-Data" 819 } 820 txStrings := make([]string, cmn.MinInt(len(data.Txs), 21)) 821 for i, tx := range data.Txs { 822 if i == 20 { 823 txStrings[i] = fmt.Sprintf("... (%v total)", len(data.Txs)) 824 break 825 } 826 txStrings[i] = fmt.Sprintf("%X (%d bytes)", tx.Hash(), len(tx)) 827 } 828 return fmt.Sprintf(`Data{ 829 %s %v 830 %s}#%v`, 831 indent, strings.Join(txStrings, "\n"+indent+" "), 832 indent, data.hash) 833 } 834 835 //----------------------------------------------------------------------------- 836 837 // EvidenceData contains any evidence of malicious wrong-doing by validators 838 type EvidenceData struct { 839 Evidence EvidenceList `json:"evidence"` 840 841 // Volatile 842 hash cmn.HexBytes 843 } 844 845 // Hash returns the hash of the data. 846 func (data *EvidenceData) Hash() cmn.HexBytes { 847 if data.hash == nil { 848 data.hash = data.Evidence.Hash() 849 } 850 return data.hash 851 } 852 853 // StringIndented returns a string representation of the evidence. 854 func (data *EvidenceData) StringIndented(indent string) string { 855 if data == nil { 856 return "nil-Evidence" 857 } 858 evStrings := make([]string, cmn.MinInt(len(data.Evidence), 21)) 859 for i, ev := range data.Evidence { 860 if i == 20 { 861 evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidence)) 862 break 863 } 864 evStrings[i] = fmt.Sprintf("Evidence:%v", ev) 865 } 866 return fmt.Sprintf(`EvidenceData{ 867 %s %v 868 %s}#%v`, 869 indent, strings.Join(evStrings, "\n"+indent+" "), 870 indent, data.hash) 871 } 872 873 //-------------------------------------------------------------------------------- 874 875 // BlockID defines the unique ID of a block as its Hash and its PartSetHeader 876 type BlockID struct { 877 Hash cmn.HexBytes `json:"hash"` 878 PartsHeader PartSetHeader `json:"parts"` 879 } 880 881 // Equals returns true if the BlockID matches the given BlockID 882 func (blockID BlockID) Equals(other BlockID) bool { 883 return bytes.Equal(blockID.Hash, other.Hash) && 884 blockID.PartsHeader.Equals(other.PartsHeader) 885 } 886 887 // Key returns a machine-readable string representation of the BlockID 888 func (blockID BlockID) Key() string { 889 bz, err := cdc.MarshalBinaryBare(blockID.PartsHeader) 890 if err != nil { 891 panic(err) 892 } 893 return string(blockID.Hash) + string(bz) 894 } 895 896 // ValidateBasic performs basic validation. 897 func (blockID BlockID) ValidateBasic() error { 898 // Hash can be empty in case of POLBlockID in Proposal. 899 if err := ValidateHash(blockID.Hash); err != nil { 900 return fmt.Errorf("Wrong Hash") 901 } 902 if err := blockID.PartsHeader.ValidateBasic(); err != nil { 903 return fmt.Errorf("Wrong PartsHeader: %v", err) 904 } 905 return nil 906 } 907 908 // IsZero returns true if this is the BlockID of a nil block. 909 func (blockID BlockID) IsZero() bool { 910 return len(blockID.Hash) == 0 && 911 blockID.PartsHeader.IsZero() 912 } 913 914 // IsComplete returns true if this is a valid BlockID of a non-nil block. 915 func (blockID BlockID) IsComplete() bool { 916 return len(blockID.Hash) == tmhash.Size && 917 blockID.PartsHeader.Total > 0 && 918 len(blockID.PartsHeader.Hash) == tmhash.Size 919 } 920 921 // String returns a human readable string representation of the BlockID 922 func (blockID BlockID) String() string { 923 return fmt.Sprintf(`%v:%v`, blockID.Hash, blockID.PartsHeader) 924 }