github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/bc/types/block.go (about)

     1  package types
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/bytom/bytom/encoding/blockchain"
     9  	"github.com/bytom/bytom/encoding/bufpool"
    10  	"github.com/bytom/bytom/errors"
    11  )
    12  
    13  // serflag variables, start with 1
    14  const (
    15  	_ = iota
    16  	SerBlockHeader
    17  	SerBlockTransactions
    18  	SerBlockFull
    19  )
    20  
    21  // Block describes a complete block, including its header and the transactions
    22  // it contains.
    23  type Block struct {
    24  	BlockHeader
    25  	Transactions []*Tx
    26  }
    27  
    28  // MarshalText fulfills the json.Marshaler interface. This guarantees that
    29  // blocks will get deserialized correctly when being parsed from HTTP requests.
    30  func (b *Block) MarshalText() ([]byte, error) {
    31  	buf := bufpool.Get()
    32  	defer bufpool.Put(buf)
    33  
    34  	if _, err := b.WriteTo(buf); err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	enc := make([]byte, hex.EncodedLen(buf.Len()))
    39  	hex.Encode(enc, buf.Bytes())
    40  	return enc, nil
    41  }
    42  
    43  // UnmarshalText fulfills the encoding.TextUnmarshaler interface.
    44  func (b *Block) UnmarshalText(text []byte) error {
    45  	decoded := make([]byte, hex.DecodedLen(len(text)))
    46  	if _, err := hex.Decode(decoded, text); err != nil {
    47  		return err
    48  	}
    49  
    50  	r := blockchain.NewReader(decoded)
    51  	if err := b.readFrom(r); err != nil {
    52  		return err
    53  	}
    54  
    55  	if trailing := r.Len(); trailing > 0 {
    56  		return fmt.Errorf("trailing garbage (%d bytes)", trailing)
    57  	}
    58  	return nil
    59  }
    60  
    61  func (b *Block) readFrom(r *blockchain.Reader) error {
    62  	serflags, err := b.BlockHeader.readFrom(r)
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	if serflags == SerBlockHeader {
    68  		return nil
    69  	}
    70  
    71  	n, err := blockchain.ReadVarint31(r)
    72  	if err != nil {
    73  		return errors.Wrap(err, "reading number of transactions")
    74  	}
    75  
    76  	for ; n > 0; n-- {
    77  		data := TxData{}
    78  		if err = data.readFrom(r); err != nil {
    79  			return errors.Wrapf(err, "reading transaction %d", len(b.Transactions))
    80  		}
    81  
    82  		b.Transactions = append(b.Transactions, NewTx(data))
    83  	}
    84  	return nil
    85  }
    86  
    87  // WriteTo will write block to input io.Writer
    88  func (b *Block) WriteTo(w io.Writer) (int64, error) {
    89  	ew := errors.NewWriter(w)
    90  	if err := b.writeTo(ew, SerBlockFull); err != nil {
    91  		return 0, err
    92  	}
    93  	return ew.Written(), ew.Err()
    94  }
    95  
    96  func (b *Block) writeTo(w io.Writer, serflags uint8) error {
    97  	if err := b.BlockHeader.writeTo(w, serflags); err != nil {
    98  		return err
    99  	}
   100  
   101  	if serflags == SerBlockHeader {
   102  		return nil
   103  	}
   104  
   105  	if _, err := blockchain.WriteVarint31(w, uint64(len(b.Transactions))); err != nil {
   106  		return err
   107  	}
   108  
   109  	for _, tx := range b.Transactions {
   110  		if _, err := tx.WriteTo(w); err != nil {
   111  			return err
   112  		}
   113  	}
   114  	return nil
   115  }