OSDN Git Service

new repo
[bytom/vapor.git] / protocol / bc / types / block.go
1 package types
2
3 import (
4         "encoding/hex"
5         "fmt"
6         "io"
7
8         "github.com/vapor/encoding/blockchain"
9         "github.com/vapor/encoding/bufpool"
10         "github.com/vapor/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 }