github.com/Gessiux/neatchain@v1.3.1/chain/consensus/neatcon/types/block.go (about)

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