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