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  }