OSDN Git Service

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