You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.0 KiB

  1. package blocks
  2. import (
  3. "bytes"
  4. "errors"
  5. "sync"
  6. )
  7. // Helper for keeping track of block parts.
  8. type BlockPartSet struct {
  9. mtx sync.Mutex
  10. signer *Account
  11. height uint32
  12. round uint16 // Not used
  13. total uint16
  14. numParts uint16
  15. parts []*BlockPart
  16. _block *Block // cache
  17. }
  18. var (
  19. ErrInvalidBlockPartSignature = errors.New("Invalid block part signature") // Peer gave us a fake part
  20. ErrInvalidBlockPartConflict = errors.New("Invalid block part conflict") // Signer signed conflicting parts
  21. )
  22. // Signer may be nil if signer is unknown beforehand.
  23. func NewBlockPartSet(height uint32, round uint16, signer *Account) *BlockPartSet {
  24. return &BlockPartSet{
  25. signer: signer,
  26. height: height,
  27. round: round,
  28. }
  29. }
  30. // In the case where the signer wasn't known prior to NewBlockPartSet(),
  31. // user should call SetSigner() prior to AddBlockPart().
  32. func (bps *BlockPartSet) SetSigner(signer *Account) {
  33. bps.mtx.Lock()
  34. defer bps.mtx.Unlock()
  35. if bps.signer != nil {
  36. panic("BlockPartSet signer already set.")
  37. }
  38. bps.signer = signer
  39. }
  40. func (bps *BlockPartSet) BlockParts() []*BlockPart {
  41. bps.mtx.Lock()
  42. defer bps.mtx.Unlock()
  43. return bps.parts
  44. }
  45. func (bps *BlockPartSet) BitArray() []byte {
  46. bps.mtx.Lock()
  47. defer bps.mtx.Unlock()
  48. if bps.parts == nil {
  49. return nil
  50. }
  51. bitArray := make([]byte, (len(bps.parts)+7)/8)
  52. for i, part := range bps.parts {
  53. if part != nil {
  54. bitArray[i/8] |= 1 << uint(i%8)
  55. }
  56. }
  57. return bitArray
  58. }
  59. // If the part isn't valid, returns an error.
  60. // err can be ErrInvalidBlockPart[Conflict|Signature]
  61. func (bps *BlockPartSet) AddBlockPart(part *BlockPart) (added bool, err error) {
  62. bps.mtx.Lock()
  63. defer bps.mtx.Unlock()
  64. // If part is invalid, return an error.
  65. err = part.ValidateWithSigner(bps.signer)
  66. if err != nil {
  67. return false, err
  68. }
  69. if bps.parts == nil {
  70. // First received part for this round.
  71. bps.parts = make([]*BlockPart, part.Total)
  72. bps.total = uint16(part.Total)
  73. bps.parts[int(part.Index)] = part
  74. bps.numParts++
  75. return true, nil
  76. } else {
  77. // Check part.Index and part.Total
  78. if uint16(part.Index) >= bps.total {
  79. return false, ErrInvalidBlockPartConflict
  80. }
  81. if uint16(part.Total) != bps.total {
  82. return false, ErrInvalidBlockPartConflict
  83. }
  84. // Check for existing parts.
  85. existing := bps.parts[part.Index]
  86. if existing != nil {
  87. if existing.Bytes.Equals(part.Bytes) {
  88. // Ignore duplicate
  89. return false, nil
  90. } else {
  91. return false, ErrInvalidBlockPartConflict
  92. }
  93. } else {
  94. bps.parts[int(part.Index)] = part
  95. bps.numParts++
  96. return true, nil
  97. }
  98. }
  99. }
  100. func (bps *BlockPartSet) IsComplete() bool {
  101. bps.mtx.Lock()
  102. defer bps.mtx.Unlock()
  103. return bps.total > 0 && bps.total == bps.numParts
  104. }
  105. func (bps *BlockPartSet) Block() *Block {
  106. if !bps.IsComplete() {
  107. return nil
  108. }
  109. bps.mtx.Lock()
  110. defer bps.mtx.Unlock()
  111. if bps._block == nil {
  112. blockBytes := []byte{}
  113. for _, part := range bps.parts {
  114. blockBytes = append(blockBytes, part.Bytes...)
  115. }
  116. block := ReadBlock(bytes.NewReader(blockBytes))
  117. bps._block = block
  118. }
  119. return bps._block
  120. }