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