OSDN Git Service

new repo
[bytom/vapor.git] / protocol / bc / types / block_header.go
1 package types
2
3 import (
4         "encoding/hex"
5         "fmt"
6         "io"
7         "time"
8
9         "github.com/vapor/encoding/blockchain"
10         "github.com/vapor/encoding/bufpool"
11         "github.com/vapor/errors"
12         "github.com/vapor/protocol/bc"
13 )
14
15 type Proof struct {
16         Sign           []byte
17         ControlProgram []byte
18 }
19
20 func (p *Proof) readFrom(r *blockchain.Reader) (err error) {
21         if p.Sign, err = blockchain.ReadVarstr31(r); err != nil {
22                 return err
23         }
24         if p.ControlProgram, err = blockchain.ReadVarstr31(r); err != nil {
25                 return err
26         }
27         return nil
28 }
29
30 func (p *Proof) writeTo(w io.Writer) error {
31         if _, err := blockchain.WriteVarstr31(w, p.Sign); err != nil {
32                 return err
33         }
34
35         if _, err := blockchain.WriteVarstr31(w, p.ControlProgram); err != nil {
36                 return err
37         }
38         return nil
39 }
40
41 // BlockHeader defines information about a block and is used in the Bytom
42 type BlockHeader struct {
43         Version           uint64  // The version of the block.
44         Height            uint64  // The height of the block.
45         PreviousBlockHash bc.Hash // The hash of the previous block.
46         Timestamp         uint64  // The time of the block in seconds.
47         Proof             Proof
48         BlockCommitment
49 }
50
51 // Time returns the time represented by the Timestamp in block header.
52 func (bh *BlockHeader) Time() time.Time {
53         return time.Unix(int64(bh.Timestamp), 0).UTC()
54 }
55
56 // Hash returns complete hash of the block header.
57 func (bh *BlockHeader) Hash() bc.Hash {
58         h, _ := mapBlockHeader(bh)
59         return h
60 }
61
62 // MarshalText fulfills the json.Marshaler interface. This guarantees that
63 // block headers will get deserialized correctly when being parsed from HTTP
64 // requests.
65 func (bh *BlockHeader) MarshalText() ([]byte, error) {
66         buf := bufpool.Get()
67         defer bufpool.Put(buf)
68
69         if _, err := bh.WriteTo(buf); err != nil {
70                 return nil, err
71         }
72
73         enc := make([]byte, hex.EncodedLen(buf.Len()))
74         hex.Encode(enc, buf.Bytes())
75         return enc, nil
76 }
77
78 // UnmarshalText fulfills the encoding.TextUnmarshaler interface.
79 func (bh *BlockHeader) UnmarshalText(text []byte) error {
80         decoded := make([]byte, hex.DecodedLen(len(text)))
81         if _, err := hex.Decode(decoded, text); err != nil {
82                 return err
83         }
84
85         _, err := bh.readFrom(blockchain.NewReader(decoded))
86         return err
87 }
88
89 func (bh *BlockHeader) readFrom(r *blockchain.Reader) (serflag uint8, err error) {
90         var serflags [1]byte
91         io.ReadFull(r, serflags[:])
92         serflag = serflags[0]
93         switch serflag {
94         case SerBlockHeader, SerBlockFull:
95         default:
96                 return 0, fmt.Errorf("unsupported serialization flags 0x%x", serflags)
97         }
98
99         if bh.Version, err = blockchain.ReadVarint63(r); err != nil {
100                 return 0, err
101         }
102         if bh.Height, err = blockchain.ReadVarint63(r); err != nil {
103                 return 0, err
104         }
105         if _, err = bh.PreviousBlockHash.ReadFrom(r); err != nil {
106                 return 0, err
107         }
108         if bh.Timestamp, err = blockchain.ReadVarint63(r); err != nil {
109                 return 0, err
110         }
111         if _, err = blockchain.ReadExtensibleString(r, bh.BlockCommitment.readFrom); err != nil {
112                 return 0, err
113         }
114         if _, err = blockchain.ReadExtensibleString(r, bh.Proof.readFrom); err != nil {
115                 return 0, err
116         }
117         return
118 }
119
120 // WriteTo writes the block header to the input io.Writer
121 func (bh *BlockHeader) WriteTo(w io.Writer) (int64, error) {
122         ew := errors.NewWriter(w)
123         if err := bh.writeTo(ew, SerBlockHeader); err != nil {
124                 return 0, err
125         }
126         return ew.Written(), ew.Err()
127 }
128
129 func (bh *BlockHeader) writeTo(w io.Writer, serflags uint8) (err error) {
130         w.Write([]byte{serflags})
131         if _, err = blockchain.WriteVarint63(w, bh.Version); err != nil {
132                 return err
133         }
134         if _, err = blockchain.WriteVarint63(w, bh.Height); err != nil {
135                 return err
136         }
137         if _, err = bh.PreviousBlockHash.WriteTo(w); err != nil {
138                 return err
139         }
140         if _, err = blockchain.WriteVarint63(w, bh.Timestamp); err != nil {
141                 return err
142         }
143         if _, err = blockchain.WriteExtensibleString(w, nil, bh.BlockCommitment.writeTo); err != nil {
144                 return err
145         }
146         if _, err = blockchain.WriteExtensibleString(w, nil, bh.Proof.writeTo); err != nil {
147                 return err
148         }
149         return nil
150 }