github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/consensus/ipbft/types/block.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "time" 9 10 . "github.com/intfoundation/go-common" 11 "github.com/intfoundation/go-crypto" 12 "github.com/intfoundation/go-merkle" 13 "github.com/intfoundation/go-wire" 14 "github.com/intfoundation/intchain/core/state" 15 "github.com/intfoundation/intchain/core/types" 16 "github.com/intfoundation/intchain/log" 17 "github.com/intfoundation/intchain/rlp" 18 ) 19 20 const MaxBlockSize = 22020096 // 21MB TODO make it configurable 21 22 // IntermediateBlockResult represents intermediate block execute result. 23 type IntermediateBlockResult struct { 24 Block *types.Block 25 // followed by block execute result 26 State *state.StateDB 27 Receipts types.Receipts 28 Ops *types.PendingOps 29 } 30 31 type TdmBlock struct { 32 Block *types.Block `json:"block"` 33 TdmExtra *TendermintExtra `json:"tdmexdata"` 34 TX3ProofData []*types.TX3ProofData `json:"tx3proofdata"` 35 IntermediateResult *IntermediateBlockResult `json:"-"` 36 } 37 38 func MakeBlock(height uint64, chainID string, commit *Commit, 39 block *types.Block, valHash []byte, epochNumber uint64, epochBytes []byte, tx3ProofData []*types.TX3ProofData, partSize int) (*TdmBlock, *PartSet) { 40 TdmExtra := &TendermintExtra{ 41 ChainID: chainID, 42 Height: uint64(height), 43 Time: time.Now(), 44 EpochNumber: epochNumber, 45 ValidatorsHash: valHash, 46 SeenCommit: commit, 47 EpochBytes: epochBytes, 48 } 49 50 tdmBlock := &TdmBlock{ 51 Block: block, 52 TdmExtra: TdmExtra, 53 TX3ProofData: tx3ProofData, 54 } 55 return tdmBlock, tdmBlock.MakePartSet(partSize) 56 } 57 58 // Basic validation that doesn't involve state data. 59 func (b *TdmBlock) ValidateBasic(tdmExtra *TendermintExtra) error { 60 61 if b.TdmExtra.ChainID != tdmExtra.ChainID { 62 return errors.New(Fmt("Wrong Block.Header.ChainID. Expected %v, got %v", tdmExtra.ChainID, b.TdmExtra.ChainID)) 63 } 64 if b.TdmExtra.Height != tdmExtra.Height+1 { 65 return errors.New(Fmt("Wrong Block.Header.Height. Expected %v, got %v", tdmExtra.Height+1, b.TdmExtra.Height)) 66 } 67 68 /* 69 if !b.TdmExtra.BlockID.Equals(blockID) { 70 return errors.New(Fmt("Wrong Block.Header.LastBlockID. Expected %v, got %v", blockID, b.TdmExtra.BlockID)) 71 } 72 if !bytes.Equal(b.TdmExtra.SeenCommitHash, b.TdmExtra.SeenCommit.Hash()) { 73 return errors.New(Fmt("Wrong Block.Header.LastCommitHash. Expected %X, got %X", b.TdmExtra.SeenCommitHash, b.TdmExtra.SeenCommit.Hash())) 74 } 75 if b.TdmExtra.Height != 1 { 76 if err := b.TdmExtra.SeenCommit.ValidateBasic(); err != nil { 77 return err 78 } 79 } 80 */ 81 return nil 82 } 83 84 func (b *TdmBlock) FillSeenCommitHash() { 85 if b.TdmExtra.SeenCommitHash == nil { 86 b.TdmExtra.SeenCommitHash = b.TdmExtra.SeenCommit.Hash() 87 } 88 } 89 90 // Computes and returns the block hash. 91 // If the block is incomplete, block hash is nil for safety. 92 func (b *TdmBlock) Hash() []byte { 93 // fmt.Println(">>", b.Data) 94 if b == nil || b.TdmExtra.SeenCommit == nil { 95 return nil 96 } 97 b.FillSeenCommitHash() 98 return b.TdmExtra.Hash() 99 } 100 101 func (b *TdmBlock) MakePartSet(partSize int) *PartSet { 102 103 return NewPartSetFromData(b.ToBytes(), partSize) 104 } 105 106 func (b *TdmBlock) ToBytes() []byte { 107 108 type TmpBlock struct { 109 BlockData []byte 110 TdmExtra *TendermintExtra 111 TX3ProofData []*types.TX3ProofData 112 } 113 114 bs, err := rlp.EncodeToBytes(b.Block) 115 if err != nil { 116 log.Warnf("TdmBlock.toBytes error\n") 117 } 118 bb := &TmpBlock{ 119 BlockData: bs, 120 TdmExtra: b.TdmExtra, 121 TX3ProofData: b.TX3ProofData, 122 } 123 124 ret := wire.BinaryBytes(bb) 125 return ret 126 } 127 128 func (b *TdmBlock) FromBytes(reader io.Reader) (*TdmBlock, error) { 129 130 type TmpBlock struct { 131 BlockData []byte 132 TdmExtra *TendermintExtra 133 TX3ProofData []*types.TX3ProofData 134 } 135 136 var n int 137 var err error 138 bb := wire.ReadBinary(&TmpBlock{}, reader, MaxBlockSize, &n, &err).(*TmpBlock) 139 if err != nil { 140 log.Warnf("TdmBlock.FromBytes 0 error: %v\n", err) 141 return nil, err 142 } 143 144 var block types.Block 145 err = rlp.DecodeBytes(bb.BlockData, &block) 146 if err != nil { 147 log.Warnf("TdmBlock.FromBytes 1 error: %v\n", err) 148 return nil, err 149 } 150 151 tdmBlock := &TdmBlock{ 152 Block: &block, 153 TdmExtra: bb.TdmExtra, 154 TX3ProofData: bb.TX3ProofData, 155 } 156 157 log.Debugf("TdmBlock.FromBytes 2 with: %v\n", tdmBlock) 158 return tdmBlock, nil 159 } 160 161 // Convenience. 162 // A nil block never hashes to anything. 163 // Nothing hashes to a nil hash. 164 func (b *TdmBlock) HashesTo(hash []byte) bool { 165 if len(hash) == 0 { 166 return false 167 } 168 if b == nil { 169 return false 170 } 171 return bytes.Equal(b.Hash(), hash) 172 } 173 174 func (b *TdmBlock) String() string { 175 return b.StringIndented("") 176 } 177 178 func (b *TdmBlock) StringIndented(indent string) string { 179 if b == nil { 180 return "nil-Block" 181 } 182 183 return fmt.Sprintf(`Block{ 184 %s %v 185 %s %v 186 %s %v 187 %s}#%X`, 188 indent, b.Block.String(), 189 indent, b.TdmExtra, 190 indent, b.TdmExtra.SeenCommit.StringIndented(indent+""), 191 indent, b.Hash()) 192 } 193 194 func (b *TdmBlock) StringShort() string { 195 if b == nil { 196 return "nil-Block" 197 } else { 198 return fmt.Sprintf("Block#%X", b.Hash()) 199 } 200 } 201 202 //------------------------------------- 203 204 // NOTE: Commit is empty for height 1, but never nil. 205 type Commit struct { 206 // NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order. 207 // Any peer with a block can gossip precommits by index with a peer without recalculating the 208 // active ValidatorSet. 209 BlockID BlockID `json:"blockID"` 210 Height uint64 `json:"height"` 211 Round int `json:"round"` 212 213 // BLS signature aggregation to be added here 214 SignAggr crypto.BLSSignature `json:"SignAggr"` 215 BitArray *BitArray 216 217 // Volatile 218 hash []byte 219 } 220 221 func (commit *Commit) Type() byte { 222 return VoteTypePrecommit 223 } 224 225 func (commit *Commit) Size() int { 226 return (int)(commit.BitArray.Size()) 227 } 228 229 func (commit *Commit) NumCommits() int { 230 return (int)(commit.BitArray.NumBitsSet()) 231 } 232 233 func (commit *Commit) ValidateBasic() error { 234 if commit.BlockID.IsZero() { 235 return errors.New("Commit cannot be for nil block") 236 } 237 /* 238 if commit.Type() != VoteTypePrecommit { 239 return fmt.Errorf("Invalid commit type. Expected VoteTypePrecommit, got %v", 240 precommit.Type) 241 } 242 243 // shall we validate the signature aggregation? 244 */ 245 246 return nil 247 } 248 249 func (commit *Commit) Hash() []byte { 250 if commit.hash == nil { 251 hash := merkle.SimpleHashFromBinary(*commit) 252 commit.hash = hash 253 } 254 return commit.hash 255 } 256 257 func (commit *Commit) StringIndented(indent string) string { 258 if commit == nil { 259 return "nil-Commit" 260 } 261 return fmt.Sprintf(`Commit{ 262 %s BlockID: %v 263 %s Height: %v 264 %s Round: %v 265 %s Type: %v 266 %s BitArray: %v 267 %s}#%X`, 268 indent, commit.BlockID, 269 indent, commit.Height, 270 indent, commit.Round, 271 indent, commit.Type(), 272 indent, commit.BitArray.String(), 273 indent, commit.hash) 274 } 275 276 //-------------------------------------------------------------------------------- 277 278 type BlockID struct { 279 Hash []byte `json:"hash"` 280 PartsHeader PartSetHeader `json:"parts"` 281 } 282 283 func (blockID BlockID) IsZero() bool { 284 return len(blockID.Hash) == 0 && blockID.PartsHeader.IsZero() 285 } 286 287 func (blockID BlockID) Equals(other BlockID) bool { 288 return bytes.Equal(blockID.Hash, other.Hash) && 289 blockID.PartsHeader.Equals(other.PartsHeader) 290 } 291 292 func (blockID BlockID) Key() string { 293 return string(blockID.Hash) + string(wire.BinaryBytes(blockID.PartsHeader)) 294 } 295 296 func (blockID BlockID) WriteSignBytes(w io.Writer, n *int, err *error) { 297 if blockID.IsZero() { 298 wire.WriteTo([]byte("null"), w, n, err) 299 } else { 300 wire.WriteJSON(CanonicalBlockID(blockID), w, n, err) 301 } 302 303 } 304 305 func (blockID BlockID) String() string { 306 return fmt.Sprintf(`%X:%v`, blockID.Hash, blockID.PartsHeader) 307 }