github.com/aakash4dev/cometbft@v0.38.2/types/block.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "strings" 8 "time" 9 10 "github.com/cosmos/gogoproto/proto" 11 gogotypes "github.com/cosmos/gogoproto/types" 12 13 "github.com/aakash4dev/cometbft/crypto" 14 "github.com/aakash4dev/cometbft/crypto/merkle" 15 "github.com/aakash4dev/cometbft/crypto/tmhash" 16 "github.com/aakash4dev/cometbft/libs/bits" 17 cmtbytes "github.com/aakash4dev/cometbft/libs/bytes" 18 cmtmath "github.com/aakash4dev/cometbft/libs/math" 19 cmtsync "github.com/aakash4dev/cometbft/libs/sync" 20 cmtproto "github.com/aakash4dev/cometbft/proto/tendermint/types" 21 cmtversion "github.com/aakash4dev/cometbft/proto/tendermint/version" 22 "github.com/aakash4dev/cometbft/version" 23 ) 24 25 const ( 26 // MaxHeaderBytes is a maximum header size. 27 // NOTE: Because app hash can be of arbitrary size, the header is therefore not 28 // capped in size and thus this number should be seen as a soft max 29 MaxHeaderBytes int64 = 626 30 31 // MaxOverheadForBlock - maximum overhead to encode a block (up to 32 // MaxBlockSizeBytes in size) not including it's parts except Data. 33 // This means it also excludes the overhead for individual transactions. 34 // 35 // Uvarint length of MaxBlockSizeBytes: 4 bytes 36 // 2 fields (2 embedded): 2 bytes 37 // Uvarint length of Data.Txs: 4 bytes 38 // Data.Txs field: 1 byte 39 MaxOverheadForBlock int64 = 11 40 ) 41 42 // Block defines the atomic unit of a CometBFT blockchain. 43 type Block struct { 44 mtx cmtsync.Mutex 45 46 Header `json:"header"` 47 Data `json:"data"` 48 Evidence EvidenceData `json:"evidence"` 49 LastCommit *Commit `json:"last_commit"` 50 } 51 52 // ValidateBasic performs basic validation that doesn't involve state data. 53 // It checks the internal consistency of the block. 54 // Further validation is done using state#ValidateBlock. 55 func (b *Block) ValidateBasic() error { 56 if b == nil { 57 return errors.New("nil block") 58 } 59 60 b.mtx.Lock() 61 defer b.mtx.Unlock() 62 63 if err := b.Header.ValidateBasic(); err != nil { 64 return fmt.Errorf("invalid header: %w", err) 65 } 66 67 // Validate the last commit and its hash. 68 if b.LastCommit == nil { 69 return errors.New("nil LastCommit") 70 } 71 if err := b.LastCommit.ValidateBasic(); err != nil { 72 return fmt.Errorf("wrong LastCommit: %v", err) 73 } 74 75 if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) { 76 return fmt.Errorf("wrong Header.LastCommitHash. Expected %v, got %v", 77 b.LastCommit.Hash(), 78 b.LastCommitHash, 79 ) 80 } 81 82 // NOTE: b.Data.Txs may be nil, but b.Data.Hash() still works fine. 83 if !bytes.Equal(b.DataHash, b.Data.Hash()) { 84 return fmt.Errorf( 85 "wrong Header.DataHash. Expected %v, got %v", 86 b.Data.Hash(), 87 b.DataHash, 88 ) 89 } 90 91 // NOTE: b.Evidence.Evidence may be nil, but we're just looping. 92 for i, ev := range b.Evidence.Evidence { 93 if err := ev.ValidateBasic(); err != nil { 94 return fmt.Errorf("invalid evidence (#%d): %v", i, err) 95 } 96 } 97 98 if !bytes.Equal(b.EvidenceHash, b.Evidence.Hash()) { 99 return fmt.Errorf("wrong Header.EvidenceHash. Expected %v, got %v", 100 b.EvidenceHash, 101 b.Evidence.Hash(), 102 ) 103 } 104 105 return nil 106 } 107 108 // fillHeader fills in any remaining header fields that are a function of the block data 109 func (b *Block) fillHeader() { 110 if b.LastCommitHash == nil { 111 b.LastCommitHash = b.LastCommit.Hash() 112 } 113 if b.DataHash == nil { 114 b.DataHash = b.Data.Hash() 115 } 116 if b.EvidenceHash == nil { 117 b.EvidenceHash = b.Evidence.Hash() 118 } 119 } 120 121 // Hash computes and returns the block hash. 122 // If the block is incomplete, block hash is nil for safety. 123 func (b *Block) Hash() cmtbytes.HexBytes { 124 if b == nil { 125 return nil 126 } 127 b.mtx.Lock() 128 defer b.mtx.Unlock() 129 130 if b.LastCommit == nil { 131 return nil 132 } 133 b.fillHeader() 134 return b.Header.Hash() 135 } 136 137 // MakePartSet returns a PartSet containing parts of a serialized block. 138 // This is the form in which the block is gossipped to peers. 139 // CONTRACT: partSize is greater than zero. 140 func (b *Block) MakePartSet(partSize uint32) (*PartSet, error) { 141 if b == nil { 142 return nil, errors.New("nil block") 143 } 144 b.mtx.Lock() 145 defer b.mtx.Unlock() 146 147 pbb, err := b.ToProto() 148 if err != nil { 149 return nil, err 150 } 151 bz, err := proto.Marshal(pbb) 152 if err != nil { 153 return nil, err 154 } 155 return NewPartSetFromData(bz, partSize), nil 156 } 157 158 // HashesTo is a convenience function that checks if a block hashes to the given argument. 159 // Returns false if the block is nil or the hash is empty. 160 func (b *Block) HashesTo(hash []byte) bool { 161 if len(hash) == 0 { 162 return false 163 } 164 if b == nil { 165 return false 166 } 167 return bytes.Equal(b.Hash(), hash) 168 } 169 170 // Size returns size of the block in bytes. 171 func (b *Block) Size() int { 172 pbb, err := b.ToProto() 173 if err != nil { 174 return 0 175 } 176 177 return pbb.Size() 178 } 179 180 // String returns a string representation of the block 181 // 182 // See StringIndented. 183 func (b *Block) String() string { 184 return b.StringIndented("") 185 } 186 187 // StringIndented returns an indented String. 188 // 189 // Header 190 // Data 191 // Evidence 192 // LastCommit 193 // Hash 194 func (b *Block) StringIndented(indent string) string { 195 if b == nil { 196 return "nil-Block" 197 } 198 return fmt.Sprintf(`Block{ 199 %s %v 200 %s %v 201 %s %v 202 %s %v 203 %s}#%v`, 204 indent, b.Header.StringIndented(indent+" "), 205 indent, b.Data.StringIndented(indent+" "), 206 indent, b.Evidence.StringIndented(indent+" "), 207 indent, b.LastCommit.StringIndented(indent+" "), 208 indent, b.Hash()) 209 } 210 211 // StringShort returns a shortened string representation of the block. 212 func (b *Block) StringShort() string { 213 if b == nil { 214 return "nil-Block" 215 } 216 return fmt.Sprintf("Block#%X", b.Hash()) 217 } 218 219 // ToProto converts Block to protobuf 220 func (b *Block) ToProto() (*cmtproto.Block, error) { 221 if b == nil { 222 return nil, errors.New("nil Block") 223 } 224 225 pb := new(cmtproto.Block) 226 227 pb.Header = *b.Header.ToProto() 228 pb.LastCommit = b.LastCommit.ToProto() 229 pb.Data = b.Data.ToProto() 230 231 protoEvidence, err := b.Evidence.ToProto() 232 if err != nil { 233 return nil, err 234 } 235 pb.Evidence = *protoEvidence 236 237 return pb, nil 238 } 239 240 // FromProto sets a protobuf Block to the given pointer. 241 // It returns an error if the block is invalid. 242 func BlockFromProto(bp *cmtproto.Block) (*Block, error) { 243 if bp == nil { 244 return nil, errors.New("nil block") 245 } 246 247 b := new(Block) 248 h, err := HeaderFromProto(&bp.Header) 249 if err != nil { 250 return nil, err 251 } 252 b.Header = h 253 data, err := DataFromProto(&bp.Data) 254 if err != nil { 255 return nil, err 256 } 257 b.Data = data 258 if err := b.Evidence.FromProto(&bp.Evidence); err != nil { 259 return nil, err 260 } 261 262 if bp.LastCommit != nil { 263 lc, err := CommitFromProto(bp.LastCommit) 264 if err != nil { 265 return nil, err 266 } 267 b.LastCommit = lc 268 } 269 270 return b, b.ValidateBasic() 271 } 272 273 //----------------------------------------------------------------------------- 274 275 // MaxDataBytes returns the maximum size of block's data. 276 // 277 // XXX: Panics on negative result. 278 func MaxDataBytes(maxBytes, evidenceBytes int64, valsCount int) int64 { 279 maxDataBytes := maxBytes - 280 MaxOverheadForBlock - 281 MaxHeaderBytes - 282 MaxCommitBytes(valsCount) - 283 evidenceBytes 284 285 if maxDataBytes < 0 { 286 panic(fmt.Sprintf( 287 "Negative MaxDataBytes. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d", 288 maxBytes, 289 -(maxDataBytes - maxBytes), 290 )) 291 } 292 293 return maxDataBytes 294 } 295 296 // MaxDataBytesNoEvidence returns the maximum size of block's data when 297 // evidence count is unknown (will be assumed to be 0). 298 // 299 // XXX: Panics on negative result. 300 func MaxDataBytesNoEvidence(maxBytes int64, valsCount int) int64 { 301 maxDataBytes := maxBytes - 302 MaxOverheadForBlock - 303 MaxHeaderBytes - 304 MaxCommitBytes(valsCount) 305 306 if maxDataBytes < 0 { 307 panic(fmt.Sprintf( 308 "Negative MaxDataBytesNoEvidence. Block.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d", 309 maxBytes, 310 -(maxDataBytes - maxBytes), 311 )) 312 } 313 314 return maxDataBytes 315 } 316 317 //----------------------------------------------------------------------------- 318 319 // Header defines the structure of a CometBFT block header. 320 // NOTE: changes to the Header should be duplicated in: 321 // - header.Hash() 322 // - abci.Header 323 // - https://github.com/aakash4dev/cometbft/blob/main/spec/blockchain/blockchain.md 324 type Header struct { 325 // basic block info 326 Version cmtversion.Consensus `json:"version"` 327 ChainID string `json:"chain_id"` 328 Height int64 `json:"height"` 329 Time time.Time `json:"time"` 330 331 // prev block info 332 LastBlockID BlockID `json:"last_block_id"` 333 334 // hashes of block data 335 LastCommitHash cmtbytes.HexBytes `json:"last_commit_hash"` // commit from validators from the last block 336 DataHash cmtbytes.HexBytes `json:"data_hash"` // transactions 337 338 // hashes from the app output from the prev block 339 ValidatorsHash cmtbytes.HexBytes `json:"validators_hash"` // validators for the current block 340 NextValidatorsHash cmtbytes.HexBytes `json:"next_validators_hash"` // validators for the next block 341 ConsensusHash cmtbytes.HexBytes `json:"consensus_hash"` // consensus params for current block 342 AppHash cmtbytes.HexBytes `json:"app_hash"` // state after txs from the previous block 343 // root hash of all results from the txs from the previous block 344 // see `DeterministicExecTxResult` to understand which parts of a tx is hashed into here 345 LastResultsHash cmtbytes.HexBytes `json:"last_results_hash"` 346 347 // consensus info 348 EvidenceHash cmtbytes.HexBytes `json:"evidence_hash"` // evidence included in the block 349 ProposerAddress Address `json:"proposer_address"` // original proposer of the block 350 } 351 352 // Populate the Header with state-derived data. 353 // Call this after MakeBlock to complete the Header. 354 func (h *Header) Populate( 355 version cmtversion.Consensus, chainID string, 356 timestamp time.Time, lastBlockID BlockID, 357 valHash, nextValHash []byte, 358 consensusHash, appHash, lastResultsHash []byte, 359 proposerAddress Address, 360 ) { 361 h.Version = version 362 h.ChainID = chainID 363 h.Time = timestamp 364 h.LastBlockID = lastBlockID 365 h.ValidatorsHash = valHash 366 h.NextValidatorsHash = nextValHash 367 h.ConsensusHash = consensusHash 368 h.AppHash = appHash 369 h.LastResultsHash = lastResultsHash 370 h.ProposerAddress = proposerAddress 371 } 372 373 // ValidateBasic performs stateless validation on a Header returning an error 374 // if any validation fails. 375 // 376 // NOTE: Timestamp validation is subtle and handled elsewhere. 377 func (h Header) ValidateBasic() error { 378 if h.Version.Block != version.BlockProtocol { 379 return fmt.Errorf("block protocol is incorrect: got: %d, want: %d ", h.Version.Block, version.BlockProtocol) 380 } 381 if len(h.ChainID) > MaxChainIDLen { 382 return fmt.Errorf("chainID is too long; got: %d, max: %d", len(h.ChainID), MaxChainIDLen) 383 } 384 385 if h.Height < 0 { 386 return errors.New("negative Height") 387 } else if h.Height == 0 { 388 return errors.New("zero Height") 389 } 390 391 if err := h.LastBlockID.ValidateBasic(); err != nil { 392 return fmt.Errorf("wrong LastBlockID: %w", err) 393 } 394 395 if err := ValidateHash(h.LastCommitHash); err != nil { 396 return fmt.Errorf("wrong LastCommitHash: %v", err) 397 } 398 399 if err := ValidateHash(h.DataHash); err != nil { 400 return fmt.Errorf("wrong DataHash: %v", err) 401 } 402 403 if err := ValidateHash(h.EvidenceHash); err != nil { 404 return fmt.Errorf("wrong EvidenceHash: %v", err) 405 } 406 407 if len(h.ProposerAddress) != crypto.AddressSize { 408 return fmt.Errorf( 409 "invalid ProposerAddress length; got: %d, expected: %d", 410 len(h.ProposerAddress), crypto.AddressSize, 411 ) 412 } 413 414 // Basic validation of hashes related to application data. 415 // Will validate fully against state in state#ValidateBlock. 416 if err := ValidateHash(h.ValidatorsHash); err != nil { 417 return fmt.Errorf("wrong ValidatorsHash: %v", err) 418 } 419 if err := ValidateHash(h.NextValidatorsHash); err != nil { 420 return fmt.Errorf("wrong NextValidatorsHash: %v", err) 421 } 422 if err := ValidateHash(h.ConsensusHash); err != nil { 423 return fmt.Errorf("wrong ConsensusHash: %v", err) 424 } 425 // NOTE: AppHash is arbitrary length 426 if err := ValidateHash(h.LastResultsHash); err != nil { 427 return fmt.Errorf("wrong LastResultsHash: %v", err) 428 } 429 430 return nil 431 } 432 433 // Hash returns the hash of the header. 434 // It computes a Merkle tree from the header fields 435 // ordered as they appear in the Header. 436 // Returns nil if ValidatorHash is missing, 437 // since a Header is not valid unless there is 438 // a ValidatorsHash (corresponding to the validator set). 439 func (h *Header) Hash() cmtbytes.HexBytes { 440 if h == nil || len(h.ValidatorsHash) == 0 { 441 return nil 442 } 443 hbz, err := h.Version.Marshal() 444 if err != nil { 445 return nil 446 } 447 448 pbt, err := gogotypes.StdTimeMarshal(h.Time) 449 if err != nil { 450 return nil 451 } 452 453 pbbi := h.LastBlockID.ToProto() 454 bzbi, err := pbbi.Marshal() 455 if err != nil { 456 return nil 457 } 458 return merkle.HashFromByteSlices([][]byte{ 459 hbz, 460 cdcEncode(h.ChainID), 461 cdcEncode(h.Height), 462 pbt, 463 bzbi, 464 cdcEncode(h.LastCommitHash), 465 cdcEncode(h.DataHash), 466 cdcEncode(h.ValidatorsHash), 467 cdcEncode(h.NextValidatorsHash), 468 cdcEncode(h.ConsensusHash), 469 cdcEncode(h.AppHash), 470 cdcEncode(h.LastResultsHash), 471 cdcEncode(h.EvidenceHash), 472 cdcEncode(h.ProposerAddress), 473 }) 474 } 475 476 // StringIndented returns an indented string representation of the header. 477 func (h *Header) StringIndented(indent string) string { 478 if h == nil { 479 return "nil-Header" 480 } 481 return fmt.Sprintf(`Header{ 482 %s Version: %v 483 %s ChainID: %v 484 %s Height: %v 485 %s Time: %v 486 %s LastBlockID: %v 487 %s LastCommit: %v 488 %s Data: %v 489 %s Validators: %v 490 %s NextValidators: %v 491 %s App: %v 492 %s Consensus: %v 493 %s Results: %v 494 %s Evidence: %v 495 %s Proposer: %v 496 %s}#%v`, 497 indent, h.Version, 498 indent, h.ChainID, 499 indent, h.Height, 500 indent, h.Time, 501 indent, h.LastBlockID, 502 indent, h.LastCommitHash, 503 indent, h.DataHash, 504 indent, h.ValidatorsHash, 505 indent, h.NextValidatorsHash, 506 indent, h.AppHash, 507 indent, h.ConsensusHash, 508 indent, h.LastResultsHash, 509 indent, h.EvidenceHash, 510 indent, h.ProposerAddress, 511 indent, h.Hash(), 512 ) 513 } 514 515 // ToProto converts Header to protobuf 516 func (h *Header) ToProto() *cmtproto.Header { 517 if h == nil { 518 return nil 519 } 520 521 return &cmtproto.Header{ 522 Version: h.Version, 523 ChainID: h.ChainID, 524 Height: h.Height, 525 Time: h.Time, 526 LastBlockId: h.LastBlockID.ToProto(), 527 ValidatorsHash: h.ValidatorsHash, 528 NextValidatorsHash: h.NextValidatorsHash, 529 ConsensusHash: h.ConsensusHash, 530 AppHash: h.AppHash, 531 DataHash: h.DataHash, 532 EvidenceHash: h.EvidenceHash, 533 LastResultsHash: h.LastResultsHash, 534 LastCommitHash: h.LastCommitHash, 535 ProposerAddress: h.ProposerAddress, 536 } 537 } 538 539 // FromProto sets a protobuf Header to the given pointer. 540 // It returns an error if the header is invalid. 541 func HeaderFromProto(ph *cmtproto.Header) (Header, error) { 542 if ph == nil { 543 return Header{}, errors.New("nil Header") 544 } 545 546 h := new(Header) 547 548 bi, err := BlockIDFromProto(&ph.LastBlockId) 549 if err != nil { 550 return Header{}, err 551 } 552 553 h.Version = ph.Version 554 h.ChainID = ph.ChainID 555 h.Height = ph.Height 556 h.Time = ph.Time 557 h.Height = ph.Height 558 h.LastBlockID = *bi 559 h.ValidatorsHash = ph.ValidatorsHash 560 h.NextValidatorsHash = ph.NextValidatorsHash 561 h.ConsensusHash = ph.ConsensusHash 562 h.AppHash = ph.AppHash 563 h.DataHash = ph.DataHash 564 h.EvidenceHash = ph.EvidenceHash 565 h.LastResultsHash = ph.LastResultsHash 566 h.LastCommitHash = ph.LastCommitHash 567 h.ProposerAddress = ph.ProposerAddress 568 569 return *h, h.ValidateBasic() 570 } 571 572 //------------------------------------- 573 574 // BlockIDFlag indicates which BlockID the signature is for. 575 type BlockIDFlag byte 576 577 const ( 578 // BlockIDFlagAbsent - no vote was received from a validator. 579 BlockIDFlagAbsent BlockIDFlag = iota + 1 580 // BlockIDFlagCommit - voted for the Commit.BlockID. 581 BlockIDFlagCommit 582 // BlockIDFlagNil - voted for nil. 583 BlockIDFlagNil 584 ) 585 586 const ( 587 // Max size of commit without any commitSigs -> 82 for BlockID, 8 for Height, 4 for Round. 588 MaxCommitOverheadBytes int64 = 94 589 // Commit sig size is made up of 64 bytes for the signature, 20 bytes for the address, 590 // 1 byte for the flag and 14 bytes for the timestamp 591 MaxCommitSigBytes int64 = 109 592 ) 593 594 // CommitSig is a part of the Vote included in a Commit. 595 type CommitSig struct { 596 BlockIDFlag BlockIDFlag `json:"block_id_flag"` 597 ValidatorAddress Address `json:"validator_address"` 598 Timestamp time.Time `json:"timestamp"` 599 Signature []byte `json:"signature"` 600 } 601 602 func MaxCommitBytes(valCount int) int64 { 603 // From the repeated commit sig field 604 var protoEncodingOverhead int64 = 2 605 return MaxCommitOverheadBytes + ((MaxCommitSigBytes + protoEncodingOverhead) * int64(valCount)) 606 } 607 608 // NewCommitSigAbsent returns new CommitSig with BlockIDFlagAbsent. Other 609 // fields are all empty. 610 func NewCommitSigAbsent() CommitSig { 611 return CommitSig{ 612 BlockIDFlag: BlockIDFlagAbsent, 613 } 614 } 615 616 // CommitSig returns a string representation of CommitSig. 617 // 618 // 1. first 6 bytes of signature 619 // 2. first 6 bytes of validator address 620 // 3. block ID flag 621 // 4. timestamp 622 func (cs CommitSig) String() string { 623 return fmt.Sprintf("CommitSig{%X by %X on %v @ %s}", 624 cmtbytes.Fingerprint(cs.Signature), 625 cmtbytes.Fingerprint(cs.ValidatorAddress), 626 cs.BlockIDFlag, 627 CanonicalTime(cs.Timestamp)) 628 } 629 630 // BlockID returns the Commit's BlockID if CommitSig indicates signing, 631 // otherwise - empty BlockID. 632 func (cs CommitSig) BlockID(commitBlockID BlockID) BlockID { 633 var blockID BlockID 634 switch cs.BlockIDFlag { 635 case BlockIDFlagAbsent: 636 blockID = BlockID{} 637 case BlockIDFlagCommit: 638 blockID = commitBlockID 639 case BlockIDFlagNil: 640 blockID = BlockID{} 641 default: 642 panic(fmt.Sprintf("Unknown BlockIDFlag: %v", cs.BlockIDFlag)) 643 } 644 return blockID 645 } 646 647 // ValidateBasic performs basic validation. 648 func (cs CommitSig) ValidateBasic() error { 649 switch cs.BlockIDFlag { 650 case BlockIDFlagAbsent: 651 case BlockIDFlagCommit: 652 case BlockIDFlagNil: 653 default: 654 return fmt.Errorf("unknown BlockIDFlag: %v", cs.BlockIDFlag) 655 } 656 657 switch cs.BlockIDFlag { 658 case BlockIDFlagAbsent: 659 if len(cs.ValidatorAddress) != 0 { 660 return errors.New("validator address is present") 661 } 662 if !cs.Timestamp.IsZero() { 663 return errors.New("time is present") 664 } 665 if len(cs.Signature) != 0 { 666 return errors.New("signature is present") 667 } 668 default: 669 if len(cs.ValidatorAddress) != crypto.AddressSize { 670 return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes", 671 crypto.AddressSize, 672 len(cs.ValidatorAddress), 673 ) 674 } 675 // NOTE: Timestamp validation is subtle and handled elsewhere. 676 if len(cs.Signature) == 0 { 677 return errors.New("signature is missing") 678 } 679 if len(cs.Signature) > MaxSignatureSize { 680 return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize) 681 } 682 } 683 684 return nil 685 } 686 687 // ToProto converts CommitSig to protobuf 688 func (cs *CommitSig) ToProto() *cmtproto.CommitSig { 689 if cs == nil { 690 return nil 691 } 692 693 return &cmtproto.CommitSig{ 694 BlockIdFlag: cmtproto.BlockIDFlag(cs.BlockIDFlag), 695 ValidatorAddress: cs.ValidatorAddress, 696 Timestamp: cs.Timestamp, 697 Signature: cs.Signature, 698 } 699 } 700 701 // FromProto sets a protobuf CommitSig to the given pointer. 702 // It returns an error if the CommitSig is invalid. 703 func (cs *CommitSig) FromProto(csp cmtproto.CommitSig) error { 704 cs.BlockIDFlag = BlockIDFlag(csp.BlockIdFlag) 705 cs.ValidatorAddress = csp.ValidatorAddress 706 cs.Timestamp = csp.Timestamp 707 cs.Signature = csp.Signature 708 709 return cs.ValidateBasic() 710 } 711 712 //------------------------------------- 713 714 // ExtendedCommitSig contains a commit signature along with its corresponding 715 // vote extension and vote extension signature. 716 type ExtendedCommitSig struct { 717 CommitSig // Commit signature 718 Extension []byte // Vote extension 719 ExtensionSignature []byte // Vote extension signature 720 } 721 722 // NewExtendedCommitSigAbsent returns new ExtendedCommitSig with 723 // BlockIDFlagAbsent. Other fields are all empty. 724 func NewExtendedCommitSigAbsent() ExtendedCommitSig { 725 return ExtendedCommitSig{CommitSig: NewCommitSigAbsent()} 726 } 727 728 // String returns a string representation of an ExtendedCommitSig. 729 // 730 // 1. commit sig 731 // 2. first 6 bytes of vote extension 732 // 3. first 6 bytes of vote extension signature 733 func (ecs ExtendedCommitSig) String() string { 734 return fmt.Sprintf("ExtendedCommitSig{%s with %X %X}", 735 ecs.CommitSig, 736 cmtbytes.Fingerprint(ecs.Extension), 737 cmtbytes.Fingerprint(ecs.ExtensionSignature), 738 ) 739 } 740 741 // ValidateBasic checks whether the structure is well-formed. 742 func (ecs ExtendedCommitSig) ValidateBasic() error { 743 if err := ecs.CommitSig.ValidateBasic(); err != nil { 744 return err 745 } 746 747 if ecs.BlockIDFlag == BlockIDFlagCommit { 748 if len(ecs.Extension) > MaxVoteExtensionSize { 749 return fmt.Errorf("vote extension is too big (max: %d)", MaxVoteExtensionSize) 750 } 751 if len(ecs.ExtensionSignature) > MaxSignatureSize { 752 return fmt.Errorf("vote extension signature is too big (max: %d)", MaxSignatureSize) 753 } 754 return nil 755 } 756 757 if len(ecs.ExtensionSignature) == 0 && len(ecs.Extension) != 0 { 758 return errors.New("vote extension signature absent on vote with extension") 759 } 760 return nil 761 } 762 763 // EnsureExtensions validates that a vote extensions signature is present for 764 // this ExtendedCommitSig. 765 func (ecs ExtendedCommitSig) EnsureExtension(extEnabled bool) error { 766 if extEnabled { 767 if ecs.BlockIDFlag == BlockIDFlagCommit && len(ecs.ExtensionSignature) == 0 { 768 return fmt.Errorf("vote extension signature is missing; validator addr %s, timestamp %v", 769 ecs.ValidatorAddress.String(), 770 ecs.Timestamp, 771 ) 772 } 773 if ecs.BlockIDFlag != BlockIDFlagCommit && len(ecs.Extension) != 0 { 774 return fmt.Errorf("non-commit vote extension present; validator addr %s, timestamp %v", 775 ecs.ValidatorAddress.String(), 776 ecs.Timestamp, 777 ) 778 } 779 if ecs.BlockIDFlag != BlockIDFlagCommit && len(ecs.ExtensionSignature) != 0 { 780 return fmt.Errorf("non-commit vote extension signature present; validator addr %s, timestamp %v", 781 ecs.ValidatorAddress.String(), 782 ecs.Timestamp, 783 ) 784 } 785 } else { 786 if len(ecs.Extension) != 0 { 787 return fmt.Errorf("vote extension present but extensions disabled; validator addr %s, timestamp %v", 788 ecs.ValidatorAddress.String(), 789 ecs.Timestamp, 790 ) 791 } 792 if len(ecs.ExtensionSignature) != 0 { 793 return fmt.Errorf("vote extension signature present but extensions disabled; validator addr %s, timestamp %v", 794 ecs.ValidatorAddress.String(), 795 ecs.Timestamp, 796 ) 797 } 798 } 799 return nil 800 } 801 802 // ToProto converts the ExtendedCommitSig to its Protobuf representation. 803 func (ecs *ExtendedCommitSig) ToProto() *cmtproto.ExtendedCommitSig { 804 if ecs == nil { 805 return nil 806 } 807 808 return &cmtproto.ExtendedCommitSig{ 809 BlockIdFlag: cmtproto.BlockIDFlag(ecs.BlockIDFlag), 810 ValidatorAddress: ecs.ValidatorAddress, 811 Timestamp: ecs.Timestamp, 812 Signature: ecs.Signature, 813 Extension: ecs.Extension, 814 ExtensionSignature: ecs.ExtensionSignature, 815 } 816 } 817 818 // FromProto populates the ExtendedCommitSig with values from the given 819 // Protobuf representation. Returns an error if the ExtendedCommitSig is 820 // invalid. 821 func (ecs *ExtendedCommitSig) FromProto(ecsp cmtproto.ExtendedCommitSig) error { 822 ecs.BlockIDFlag = BlockIDFlag(ecsp.BlockIdFlag) 823 ecs.ValidatorAddress = ecsp.ValidatorAddress 824 ecs.Timestamp = ecsp.Timestamp 825 ecs.Signature = ecsp.Signature 826 ecs.Extension = ecsp.Extension 827 ecs.ExtensionSignature = ecsp.ExtensionSignature 828 829 return ecs.ValidateBasic() 830 } 831 832 //------------------------------------- 833 834 // Commit contains the evidence that a block was committed by a set of validators. 835 // NOTE: Commit is empty for height 1, but never nil. 836 type Commit struct { 837 // NOTE: The signatures are in order of address to preserve the bonded 838 // ValidatorSet order. 839 // Any peer with a block can gossip signatures by index with a peer without 840 // recalculating the active ValidatorSet. 841 Height int64 `json:"height"` 842 Round int32 `json:"round"` 843 BlockID BlockID `json:"block_id"` 844 Signatures []CommitSig `json:"signatures"` 845 846 // Memoized in first call to corresponding method. 847 // NOTE: can't memoize in constructor because constructor isn't used for 848 // unmarshaling. 849 hash cmtbytes.HexBytes 850 } 851 852 // GetVote converts the CommitSig for the given valIdx to a Vote. Commits do 853 // not contain vote extensions, so the vote extension and vote extension 854 // signature will not be present in the returned vote. 855 // Returns nil if the precommit at valIdx is nil. 856 // Panics if valIdx >= commit.Size(). 857 func (commit *Commit) GetVote(valIdx int32) *Vote { 858 commitSig := commit.Signatures[valIdx] 859 return &Vote{ 860 Type: cmtproto.PrecommitType, 861 Height: commit.Height, 862 Round: commit.Round, 863 BlockID: commitSig.BlockID(commit.BlockID), 864 Timestamp: commitSig.Timestamp, 865 ValidatorAddress: commitSig.ValidatorAddress, 866 ValidatorIndex: valIdx, 867 Signature: commitSig.Signature, 868 } 869 } 870 871 // VoteSignBytes returns the bytes of the Vote corresponding to valIdx for 872 // signing. 873 // 874 // The only unique part is the Timestamp - all other fields signed over are 875 // otherwise the same for all validators. 876 // 877 // Panics if valIdx >= commit.Size(). 878 // 879 // See VoteSignBytes 880 func (commit *Commit) VoteSignBytes(chainID string, valIdx int32) []byte { 881 v := commit.GetVote(valIdx).ToProto() 882 return VoteSignBytes(chainID, v) 883 } 884 885 // Size returns the number of signatures in the commit. 886 func (commit *Commit) Size() int { 887 if commit == nil { 888 return 0 889 } 890 return len(commit.Signatures) 891 } 892 893 // ValidateBasic performs basic validation that doesn't involve state data. 894 // Does not actually check the cryptographic signatures. 895 func (commit *Commit) ValidateBasic() error { 896 if commit.Height < 0 { 897 return errors.New("negative Height") 898 } 899 if commit.Round < 0 { 900 return errors.New("negative Round") 901 } 902 903 if commit.Height >= 1 { 904 if commit.BlockID.IsZero() { 905 return errors.New("commit cannot be for nil block") 906 } 907 908 if len(commit.Signatures) == 0 { 909 return errors.New("no signatures in commit") 910 } 911 for i, commitSig := range commit.Signatures { 912 if err := commitSig.ValidateBasic(); err != nil { 913 return fmt.Errorf("wrong CommitSig #%d: %v", i, err) 914 } 915 } 916 } 917 return nil 918 } 919 920 // Hash returns the hash of the commit 921 func (commit *Commit) Hash() cmtbytes.HexBytes { 922 if commit == nil { 923 return nil 924 } 925 if commit.hash == nil { 926 bs := make([][]byte, len(commit.Signatures)) 927 for i, commitSig := range commit.Signatures { 928 pbcs := commitSig.ToProto() 929 bz, err := pbcs.Marshal() 930 if err != nil { 931 panic(err) 932 } 933 934 bs[i] = bz 935 } 936 commit.hash = merkle.HashFromByteSlices(bs) 937 } 938 return commit.hash 939 } 940 941 // WrappedExtendedCommit wraps a commit as an ExtendedCommit. 942 // The VoteExtension fields of the resulting value will by nil. 943 // Wrapping a Commit as an ExtendedCommit is useful when an API 944 // requires an ExtendedCommit wire type but does not 945 // need the VoteExtension data. 946 func (commit *Commit) WrappedExtendedCommit() *ExtendedCommit { 947 cs := make([]ExtendedCommitSig, len(commit.Signatures)) 948 for idx, s := range commit.Signatures { 949 cs[idx] = ExtendedCommitSig{ 950 CommitSig: s, 951 } 952 } 953 return &ExtendedCommit{ 954 Height: commit.Height, 955 Round: commit.Round, 956 BlockID: commit.BlockID, 957 ExtendedSignatures: cs, 958 } 959 } 960 961 // StringIndented returns a string representation of the commit. 962 func (commit *Commit) StringIndented(indent string) string { 963 if commit == nil { 964 return "nil-Commit" 965 } 966 commitSigStrings := make([]string, len(commit.Signatures)) 967 for i, commitSig := range commit.Signatures { 968 commitSigStrings[i] = commitSig.String() 969 } 970 return fmt.Sprintf(`Commit{ 971 %s Height: %d 972 %s Round: %d 973 %s BlockID: %v 974 %s Signatures: 975 %s %v 976 %s}#%v`, 977 indent, commit.Height, 978 indent, commit.Round, 979 indent, commit.BlockID, 980 indent, 981 indent, strings.Join(commitSigStrings, "\n"+indent+" "), 982 indent, commit.hash) 983 } 984 985 // ToProto converts Commit to protobuf 986 func (commit *Commit) ToProto() *cmtproto.Commit { 987 if commit == nil { 988 return nil 989 } 990 991 c := new(cmtproto.Commit) 992 sigs := make([]cmtproto.CommitSig, len(commit.Signatures)) 993 for i := range commit.Signatures { 994 sigs[i] = *commit.Signatures[i].ToProto() 995 } 996 c.Signatures = sigs 997 998 c.Height = commit.Height 999 c.Round = commit.Round 1000 c.BlockID = commit.BlockID.ToProto() 1001 1002 return c 1003 } 1004 1005 // FromProto sets a protobuf Commit to the given pointer. 1006 // It returns an error if the commit is invalid. 1007 func CommitFromProto(cp *cmtproto.Commit) (*Commit, error) { 1008 if cp == nil { 1009 return nil, errors.New("nil Commit") 1010 } 1011 1012 var ( 1013 commit = new(Commit) 1014 ) 1015 1016 bi, err := BlockIDFromProto(&cp.BlockID) 1017 if err != nil { 1018 return nil, err 1019 } 1020 1021 sigs := make([]CommitSig, len(cp.Signatures)) 1022 for i := range cp.Signatures { 1023 if err := sigs[i].FromProto(cp.Signatures[i]); err != nil { 1024 return nil, err 1025 } 1026 } 1027 commit.Signatures = sigs 1028 1029 commit.Height = cp.Height 1030 commit.Round = cp.Round 1031 commit.BlockID = *bi 1032 1033 return commit, commit.ValidateBasic() 1034 } 1035 1036 //------------------------------------- 1037 1038 // ExtendedCommit is similar to Commit, except that its signatures also retain 1039 // their corresponding vote extensions and vote extension signatures. 1040 type ExtendedCommit struct { 1041 Height int64 1042 Round int32 1043 BlockID BlockID 1044 ExtendedSignatures []ExtendedCommitSig 1045 1046 bitArray *bits.BitArray 1047 } 1048 1049 // Clone creates a deep copy of this extended commit. 1050 func (ec *ExtendedCommit) Clone() *ExtendedCommit { 1051 sigs := make([]ExtendedCommitSig, len(ec.ExtendedSignatures)) 1052 copy(sigs, ec.ExtendedSignatures) 1053 ecc := *ec 1054 ecc.ExtendedSignatures = sigs 1055 return &ecc 1056 } 1057 1058 // ToExtendedVoteSet constructs a VoteSet from the Commit and validator set. 1059 // Panics if signatures from the ExtendedCommit can't be added to the voteset. 1060 // Panics if any of the votes have invalid or absent vote extension data. 1061 // Inverse of VoteSet.MakeExtendedCommit(). 1062 func (ec *ExtendedCommit) ToExtendedVoteSet(chainID string, vals *ValidatorSet) *VoteSet { 1063 voteSet := NewExtendedVoteSet(chainID, ec.Height, ec.Round, cmtproto.PrecommitType, vals) 1064 ec.addSigsToVoteSet(voteSet) 1065 return voteSet 1066 } 1067 1068 // addSigsToVoteSet adds all of the signature to voteSet. 1069 func (ec *ExtendedCommit) addSigsToVoteSet(voteSet *VoteSet) { 1070 for idx, ecs := range ec.ExtendedSignatures { 1071 if ecs.BlockIDFlag == BlockIDFlagAbsent { 1072 continue // OK, some precommits can be missing. 1073 } 1074 vote := ec.GetExtendedVote(int32(idx)) 1075 if err := vote.ValidateBasic(); err != nil { 1076 panic(fmt.Errorf("failed to validate vote reconstructed from LastCommit: %w", err)) 1077 } 1078 added, err := voteSet.AddVote(vote) 1079 if !added || err != nil { 1080 panic(fmt.Errorf("failed to reconstruct vote set from extended commit: %w", err)) 1081 } 1082 } 1083 } 1084 1085 // ToVoteSet constructs a VoteSet from the Commit and validator set. 1086 // Panics if signatures from the commit can't be added to the voteset. 1087 // Inverse of VoteSet.MakeCommit(). 1088 func (commit *Commit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet { 1089 voteSet := NewVoteSet(chainID, commit.Height, commit.Round, cmtproto.PrecommitType, vals) 1090 for idx, cs := range commit.Signatures { 1091 if cs.BlockIDFlag == BlockIDFlagAbsent { 1092 continue // OK, some precommits can be missing. 1093 } 1094 vote := commit.GetVote(int32(idx)) 1095 if err := vote.ValidateBasic(); err != nil { 1096 panic(fmt.Errorf("failed to validate vote reconstructed from commit: %w", err)) 1097 } 1098 added, err := voteSet.AddVote(vote) 1099 if !added || err != nil { 1100 panic(fmt.Errorf("failed to reconstruct vote set from commit: %w", err)) 1101 } 1102 } 1103 return voteSet 1104 } 1105 1106 // EnsureExtensions validates that a vote extensions signature is present for 1107 // every ExtendedCommitSig in the ExtendedCommit. 1108 func (ec *ExtendedCommit) EnsureExtensions(extEnabled bool) error { 1109 for _, ecs := range ec.ExtendedSignatures { 1110 if err := ecs.EnsureExtension(extEnabled); err != nil { 1111 return err 1112 } 1113 } 1114 return nil 1115 } 1116 1117 // ToCommit converts an ExtendedCommit to a Commit by removing all vote 1118 // extension-related fields. 1119 func (ec *ExtendedCommit) ToCommit() *Commit { 1120 cs := make([]CommitSig, len(ec.ExtendedSignatures)) 1121 for idx, ecs := range ec.ExtendedSignatures { 1122 cs[idx] = ecs.CommitSig 1123 } 1124 return &Commit{ 1125 Height: ec.Height, 1126 Round: ec.Round, 1127 BlockID: ec.BlockID, 1128 Signatures: cs, 1129 } 1130 } 1131 1132 // GetExtendedVote converts the ExtendedCommitSig for the given validator 1133 // index to a Vote with a vote extensions. 1134 // It panics if valIndex is out of range. 1135 func (ec *ExtendedCommit) GetExtendedVote(valIndex int32) *Vote { 1136 ecs := ec.ExtendedSignatures[valIndex] 1137 return &Vote{ 1138 Type: cmtproto.PrecommitType, 1139 Height: ec.Height, 1140 Round: ec.Round, 1141 BlockID: ecs.BlockID(ec.BlockID), 1142 Timestamp: ecs.Timestamp, 1143 ValidatorAddress: ecs.ValidatorAddress, 1144 ValidatorIndex: valIndex, 1145 Signature: ecs.Signature, 1146 Extension: ecs.Extension, 1147 ExtensionSignature: ecs.ExtensionSignature, 1148 } 1149 } 1150 1151 // Type returns the vote type of the extended commit, which is always 1152 // VoteTypePrecommit 1153 // Implements VoteSetReader. 1154 func (ec *ExtendedCommit) Type() byte { return byte(cmtproto.PrecommitType) } 1155 1156 // GetHeight returns height of the extended commit. 1157 // Implements VoteSetReader. 1158 func (ec *ExtendedCommit) GetHeight() int64 { return ec.Height } 1159 1160 // GetRound returns height of the extended commit. 1161 // Implements VoteSetReader. 1162 func (ec *ExtendedCommit) GetRound() int32 { return ec.Round } 1163 1164 // Size returns the number of signatures in the extended commit. 1165 // Implements VoteSetReader. 1166 func (ec *ExtendedCommit) Size() int { 1167 if ec == nil { 1168 return 0 1169 } 1170 return len(ec.ExtendedSignatures) 1171 } 1172 1173 // BitArray returns a BitArray of which validators voted for BlockID or nil in 1174 // this extended commit. 1175 // Implements VoteSetReader. 1176 func (ec *ExtendedCommit) BitArray() *bits.BitArray { 1177 if ec.bitArray == nil { 1178 ec.bitArray = bits.NewBitArray(len(ec.ExtendedSignatures)) 1179 for i, extCommitSig := range ec.ExtendedSignatures { 1180 // TODO: need to check the BlockID otherwise we could be counting conflicts, 1181 // not just the one with +2/3 ! 1182 ec.bitArray.SetIndex(i, extCommitSig.BlockIDFlag != BlockIDFlagAbsent) 1183 } 1184 } 1185 return ec.bitArray 1186 } 1187 1188 // GetByIndex returns the vote corresponding to a given validator index. 1189 // Panics if `index >= extCommit.Size()`. 1190 // Implements VoteSetReader. 1191 func (ec *ExtendedCommit) GetByIndex(valIdx int32) *Vote { 1192 return ec.GetExtendedVote(valIdx) 1193 } 1194 1195 // IsCommit returns true if there is at least one signature. 1196 // Implements VoteSetReader. 1197 func (ec *ExtendedCommit) IsCommit() bool { 1198 return len(ec.ExtendedSignatures) != 0 1199 } 1200 1201 // ValidateBasic checks whether the extended commit is well-formed. Does not 1202 // actually check the cryptographic signatures. 1203 func (ec *ExtendedCommit) ValidateBasic() error { 1204 if ec.Height < 0 { 1205 return errors.New("negative Height") 1206 } 1207 if ec.Round < 0 { 1208 return errors.New("negative Round") 1209 } 1210 1211 if ec.Height >= 1 { 1212 if ec.BlockID.IsZero() { 1213 return errors.New("extended commit cannot be for nil block") 1214 } 1215 1216 if len(ec.ExtendedSignatures) == 0 { 1217 return errors.New("no signatures in commit") 1218 } 1219 for i, extCommitSig := range ec.ExtendedSignatures { 1220 if err := extCommitSig.ValidateBasic(); err != nil { 1221 return fmt.Errorf("wrong ExtendedCommitSig #%d: %v", i, err) 1222 } 1223 } 1224 } 1225 return nil 1226 } 1227 1228 // ToProto converts ExtendedCommit to protobuf 1229 func (ec *ExtendedCommit) ToProto() *cmtproto.ExtendedCommit { 1230 if ec == nil { 1231 return nil 1232 } 1233 1234 c := new(cmtproto.ExtendedCommit) 1235 sigs := make([]cmtproto.ExtendedCommitSig, len(ec.ExtendedSignatures)) 1236 for i := range ec.ExtendedSignatures { 1237 sigs[i] = *ec.ExtendedSignatures[i].ToProto() 1238 } 1239 c.ExtendedSignatures = sigs 1240 1241 c.Height = ec.Height 1242 c.Round = ec.Round 1243 c.BlockID = ec.BlockID.ToProto() 1244 1245 return c 1246 } 1247 1248 // ExtendedCommitFromProto constructs an ExtendedCommit from the given Protobuf 1249 // representation. It returns an error if the extended commit is invalid. 1250 func ExtendedCommitFromProto(ecp *cmtproto.ExtendedCommit) (*ExtendedCommit, error) { 1251 if ecp == nil { 1252 return nil, errors.New("nil ExtendedCommit") 1253 } 1254 1255 extCommit := new(ExtendedCommit) 1256 1257 bi, err := BlockIDFromProto(&ecp.BlockID) 1258 if err != nil { 1259 return nil, err 1260 } 1261 1262 sigs := make([]ExtendedCommitSig, len(ecp.ExtendedSignatures)) 1263 for i := range ecp.ExtendedSignatures { 1264 if err := sigs[i].FromProto(ecp.ExtendedSignatures[i]); err != nil { 1265 return nil, err 1266 } 1267 } 1268 extCommit.ExtendedSignatures = sigs 1269 extCommit.Height = ecp.Height 1270 extCommit.Round = ecp.Round 1271 extCommit.BlockID = *bi 1272 1273 return extCommit, extCommit.ValidateBasic() 1274 } 1275 1276 //------------------------------------- 1277 1278 // Data contains the set of transactions included in the block 1279 type Data struct { 1280 1281 // Txs that will be applied by state @ block.Height+1. 1282 // NOTE: not all txs here are valid. We're just agreeing on the order first. 1283 // This means that block.AppHash does not include these txs. 1284 Txs Txs `json:"txs"` 1285 1286 // Volatile 1287 hash cmtbytes.HexBytes 1288 } 1289 1290 // Hash returns the hash of the data 1291 func (data *Data) Hash() cmtbytes.HexBytes { 1292 if data == nil { 1293 return (Txs{}).Hash() 1294 } 1295 if data.hash == nil { 1296 data.hash = data.Txs.Hash() // NOTE: leaves of merkle tree are TxIDs 1297 } 1298 return data.hash 1299 } 1300 1301 // StringIndented returns an indented string representation of the transactions. 1302 func (data *Data) StringIndented(indent string) string { 1303 if data == nil { 1304 return "nil-Data" 1305 } 1306 txStrings := make([]string, cmtmath.MinInt(len(data.Txs), 21)) 1307 for i, tx := range data.Txs { 1308 if i == 20 { 1309 txStrings[i] = fmt.Sprintf("... (%v total)", len(data.Txs)) 1310 break 1311 } 1312 txStrings[i] = fmt.Sprintf("%X (%d bytes)", tx.Hash(), len(tx)) 1313 } 1314 return fmt.Sprintf(`Data{ 1315 %s %v 1316 %s}#%v`, 1317 indent, strings.Join(txStrings, "\n"+indent+" "), 1318 indent, data.hash) 1319 } 1320 1321 // ToProto converts Data to protobuf 1322 func (data *Data) ToProto() cmtproto.Data { 1323 tp := new(cmtproto.Data) 1324 1325 if len(data.Txs) > 0 { 1326 txBzs := make([][]byte, len(data.Txs)) 1327 for i := range data.Txs { 1328 txBzs[i] = data.Txs[i] 1329 } 1330 tp.Txs = txBzs 1331 } 1332 1333 return *tp 1334 } 1335 1336 // DataFromProto takes a protobuf representation of Data & 1337 // returns the native type. 1338 func DataFromProto(dp *cmtproto.Data) (Data, error) { 1339 if dp == nil { 1340 return Data{}, errors.New("nil data") 1341 } 1342 data := new(Data) 1343 1344 if len(dp.Txs) > 0 { 1345 txBzs := make(Txs, len(dp.Txs)) 1346 for i := range dp.Txs { 1347 txBzs[i] = Tx(dp.Txs[i]) 1348 } 1349 data.Txs = txBzs 1350 } else { 1351 data.Txs = Txs{} 1352 } 1353 1354 return *data, nil 1355 } 1356 1357 //----------------------------------------------------------------------------- 1358 1359 // EvidenceData contains any evidence of malicious wrong-doing by validators 1360 type EvidenceData struct { 1361 Evidence EvidenceList `json:"evidence"` 1362 1363 // Volatile. Used as cache 1364 hash cmtbytes.HexBytes 1365 byteSize int64 1366 } 1367 1368 // Hash returns the hash of the data. 1369 func (data *EvidenceData) Hash() cmtbytes.HexBytes { 1370 if data.hash == nil { 1371 data.hash = data.Evidence.Hash() 1372 } 1373 return data.hash 1374 } 1375 1376 // ByteSize returns the total byte size of all the evidence 1377 func (data *EvidenceData) ByteSize() int64 { 1378 if data.byteSize == 0 && len(data.Evidence) != 0 { 1379 pb, err := data.ToProto() 1380 if err != nil { 1381 panic(err) 1382 } 1383 data.byteSize = int64(pb.Size()) 1384 } 1385 return data.byteSize 1386 } 1387 1388 // StringIndented returns a string representation of the evidence. 1389 func (data *EvidenceData) StringIndented(indent string) string { 1390 if data == nil { 1391 return "nil-Evidence" 1392 } 1393 evStrings := make([]string, cmtmath.MinInt(len(data.Evidence), 21)) 1394 for i, ev := range data.Evidence { 1395 if i == 20 { 1396 evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidence)) 1397 break 1398 } 1399 evStrings[i] = fmt.Sprintf("Evidence:%v", ev) 1400 } 1401 return fmt.Sprintf(`EvidenceData{ 1402 %s %v 1403 %s}#%v`, 1404 indent, strings.Join(evStrings, "\n"+indent+" "), 1405 indent, data.hash) 1406 } 1407 1408 // ToProto converts EvidenceData to protobuf 1409 func (data *EvidenceData) ToProto() (*cmtproto.EvidenceList, error) { 1410 if data == nil { 1411 return nil, errors.New("nil evidence data") 1412 } 1413 1414 evi := new(cmtproto.EvidenceList) 1415 eviBzs := make([]cmtproto.Evidence, len(data.Evidence)) 1416 for i := range data.Evidence { 1417 protoEvi, err := EvidenceToProto(data.Evidence[i]) 1418 if err != nil { 1419 return nil, err 1420 } 1421 eviBzs[i] = *protoEvi 1422 } 1423 evi.Evidence = eviBzs 1424 1425 return evi, nil 1426 } 1427 1428 // FromProto sets a protobuf EvidenceData to the given pointer. 1429 func (data *EvidenceData) FromProto(eviData *cmtproto.EvidenceList) error { 1430 if eviData == nil { 1431 return errors.New("nil evidenceData") 1432 } 1433 1434 eviBzs := make(EvidenceList, len(eviData.Evidence)) 1435 for i := range eviData.Evidence { 1436 evi, err := EvidenceFromProto(&eviData.Evidence[i]) 1437 if err != nil { 1438 return err 1439 } 1440 eviBzs[i] = evi 1441 } 1442 data.Evidence = eviBzs 1443 data.byteSize = int64(eviData.Size()) 1444 1445 return nil 1446 } 1447 1448 //-------------------------------------------------------------------------------- 1449 1450 // BlockID 1451 type BlockID struct { 1452 Hash cmtbytes.HexBytes `json:"hash"` 1453 PartSetHeader PartSetHeader `json:"parts"` 1454 } 1455 1456 // Equals returns true if the BlockID matches the given BlockID 1457 func (blockID BlockID) Equals(other BlockID) bool { 1458 return bytes.Equal(blockID.Hash, other.Hash) && 1459 blockID.PartSetHeader.Equals(other.PartSetHeader) 1460 } 1461 1462 // Key returns a machine-readable string representation of the BlockID 1463 func (blockID BlockID) Key() string { 1464 pbph := blockID.PartSetHeader.ToProto() 1465 bz, err := pbph.Marshal() 1466 if err != nil { 1467 panic(err) 1468 } 1469 1470 return fmt.Sprint(string(blockID.Hash), string(bz)) 1471 } 1472 1473 // ValidateBasic performs basic validation. 1474 func (blockID BlockID) ValidateBasic() error { 1475 // Hash can be empty in case of POLBlockID in Proposal. 1476 if err := ValidateHash(blockID.Hash); err != nil { 1477 return fmt.Errorf("wrong Hash") 1478 } 1479 if err := blockID.PartSetHeader.ValidateBasic(); err != nil { 1480 return fmt.Errorf("wrong PartSetHeader: %v", err) 1481 } 1482 return nil 1483 } 1484 1485 // IsZero returns true if this is the BlockID of a nil block. 1486 func (blockID BlockID) IsZero() bool { 1487 return len(blockID.Hash) == 0 && 1488 blockID.PartSetHeader.IsZero() 1489 } 1490 1491 // IsComplete returns true if this is a valid BlockID of a non-nil block. 1492 func (blockID BlockID) IsComplete() bool { 1493 return len(blockID.Hash) == tmhash.Size && 1494 blockID.PartSetHeader.Total > 0 && 1495 len(blockID.PartSetHeader.Hash) == tmhash.Size 1496 } 1497 1498 // String returns a human readable string representation of the BlockID. 1499 // 1500 // 1. hash 1501 // 2. part set header 1502 // 1503 // See PartSetHeader#String 1504 func (blockID BlockID) String() string { 1505 return fmt.Sprintf(`%v:%v`, blockID.Hash, blockID.PartSetHeader) 1506 } 1507 1508 // ToProto converts BlockID to protobuf 1509 func (blockID *BlockID) ToProto() cmtproto.BlockID { 1510 if blockID == nil { 1511 return cmtproto.BlockID{} 1512 } 1513 1514 return cmtproto.BlockID{ 1515 Hash: blockID.Hash, 1516 PartSetHeader: blockID.PartSetHeader.ToProto(), 1517 } 1518 } 1519 1520 // FromProto sets a protobuf BlockID to the given pointer. 1521 // It returns an error if the block id is invalid. 1522 func BlockIDFromProto(bID *cmtproto.BlockID) (*BlockID, error) { 1523 if bID == nil { 1524 return nil, errors.New("nil BlockID") 1525 } 1526 1527 blockID := new(BlockID) 1528 ph, err := PartSetHeaderFromProto(&bID.PartSetHeader) 1529 if err != nil { 1530 return nil, err 1531 } 1532 1533 blockID.PartSetHeader = *ph 1534 blockID.Hash = bID.Hash 1535 1536 return blockID, blockID.ValidateBasic() 1537 } 1538 1539 // ProtoBlockIDIsNil is similar to the IsNil function on BlockID, but for the 1540 // Protobuf representation. 1541 func ProtoBlockIDIsNil(bID *cmtproto.BlockID) bool { 1542 return len(bID.Hash) == 0 && ProtoPartSetHeaderIsZero(&bID.PartSetHeader) 1543 }