OSDN Git Service

671084d7b30ac50fb98b917dbbc8cd24eac81476
[bytom/vapor.git] / api / miner.go
1 package api
2
3 import (
4         "context"
5         "strconv"
6
7         chainjson "github.com/vapor/encoding/json"
8         "github.com/vapor/errors"
9         "github.com/vapor/protocol/bc"
10         "github.com/vapor/protocol/bc/types"
11 )
12
13 // BlockHeaderJSON struct provides support for get work in json format, when it also follows
14 // BlockHeader structure
15 type BlockHeaderJSON struct {
16         Version           uint64                 `json:"version"`             // The version of the block.
17         Height            uint64                 `json:"height"`              // The height of the block.
18         PreviousBlockHash bc.Hash                `json:"previous_block_hash"` // The hash of the previous block.
19         Timestamp         uint64                 `json:"timestamp"`           // The time of the block in seconds.
20         Nonce             uint64                 `json:"nonce"`               // Nonce used to generate the block.
21         Bits              uint64                 `json:"bits"`                // Difficulty target for the block.
22         BlockCommitment   *types.BlockCommitment `json:"block_commitment"`    // Block commitment
23 }
24
25 type CoinbaseArbitrary struct {
26         Arbitrary chainjson.HexBytes `json:"arbitrary"`
27 }
28
29 func (a *API) getCoinbaseArbitrary() Response {
30         arbitrary := a.wallet.AccountMgr.GetCoinbaseArbitrary()
31         resp := &CoinbaseArbitrary{
32                 Arbitrary: arbitrary,
33         }
34         return NewSuccessResponse(resp)
35 }
36
37 // setCoinbaseArbitrary add arbitary data to the reserved coinbase data.
38 // check function createCoinbaseTx in mining/mining.go for detail.
39 // arbitraryLenLimit is 107 and can be calculated by:
40 //      maxHeight := ^uint64(0)
41 //      reserved := append([]byte{0x00}, []byte(strconv.FormatUint(maxHeight, 10))...)
42 //      arbitraryLenLimit := consensus.CoinbaseArbitrarySizeLimit - len(reserved)
43 func (a *API) setCoinbaseArbitrary(ctx context.Context, req CoinbaseArbitrary) Response {
44         arbitraryLenLimit := 107
45         if len(req.Arbitrary) > arbitraryLenLimit {
46                 err := errors.New("Arbitrary exceeds limit: " + strconv.FormatUint(uint64(arbitraryLenLimit), 10))
47                 return NewErrorResponse(err)
48         }
49         a.wallet.AccountMgr.SetCoinbaseArbitrary(req.Arbitrary)
50         return a.getCoinbaseArbitrary()
51 }
52
53 // getWork gets work in compressed protobuf format
54 func (a *API) getWork() Response {
55         work, err := a.GetWork()
56         if err != nil {
57                 return NewErrorResponse(err)
58         }
59         return NewSuccessResponse(work)
60 }
61
62 // getWorkJSON gets work in json format
63 func (a *API) getWorkJSON() Response {
64         work, err := a.GetWorkJSON()
65         if err != nil {
66                 return NewErrorResponse(err)
67         }
68         return NewSuccessResponse(work)
69 }
70
71 // SubmitBlockReq is req struct for submit-block API
72 type SubmitBlockReq struct {
73         Block *types.Block `json:"raw_block"`
74 }
75
76 // submitBlock trys to submit a raw block to the chain
77 func (a *API) submitBlock(ctx context.Context, req *SubmitBlockReq) Response {
78         isOrphan, err := a.chain.ProcessBlock(req.Block)
79         if err != nil {
80                 return NewErrorResponse(err)
81         }
82         if isOrphan {
83                 return NewErrorResponse(errors.New("block submitted is orphan"))
84         }
85
86         blockHash := req.Block.BlockHeader.Hash()
87         a.newBlockCh <- &blockHash
88         return NewSuccessResponse(true)
89 }
90
91 // SubmitWorkReq is req struct for submit-work API
92 type SubmitWorkReq struct {
93         BlockHeader *types.BlockHeader `json:"block_header"`
94 }
95
96 // submitWork submits work in compressed protobuf format
97 func (a *API) submitWork(ctx context.Context, req *SubmitWorkReq) Response {
98         if err := a.SubmitWork(req.BlockHeader); err != nil {
99                 return NewErrorResponse(err)
100         }
101         return NewSuccessResponse(true)
102 }
103
104 // SubmitWorkJSONReq is req struct for submit-work-json API
105 type SubmitWorkJSONReq struct {
106         BlockHeader *BlockHeaderJSON `json:"block_header"`
107 }
108
109 // submitWorkJSON submits work in json format
110 func (a *API) submitWorkJSON(ctx context.Context, req *SubmitWorkJSONReq) Response {
111         bh := &types.BlockHeader{
112                 Version:           req.BlockHeader.Version,
113                 Height:            req.BlockHeader.Height,
114                 PreviousBlockHash: req.BlockHeader.PreviousBlockHash,
115                 Timestamp:         req.BlockHeader.Timestamp,
116                 //Nonce:             req.BlockHeader.Nonce,
117                 //Bits:              req.BlockHeader.Bits,
118                 BlockCommitment: *req.BlockHeader.BlockCommitment,
119         }
120
121         if err := a.SubmitWork(bh); err != nil {
122                 return NewErrorResponse(err)
123         }
124         return NewSuccessResponse(true)
125 }
126
127 // GetWorkResp is resp struct for get-work API
128 type GetWorkResp struct {
129         BlockHeader *types.BlockHeader `json:"block_header"`
130         Seed        *bc.Hash           `json:"seed"`
131 }
132
133 // GetWork gets work in compressed protobuf format
134 func (a *API) GetWork() (*GetWorkResp, error) {
135         bh, err := a.miningPool.GetWork()
136         if err != nil {
137                 return nil, err
138         }
139
140         seed, err := a.chain.CalcNextSeed(&bh.PreviousBlockHash)
141         if err != nil {
142                 return nil, err
143         }
144
145         return &GetWorkResp{
146                 BlockHeader: bh,
147                 Seed:        seed,
148         }, nil
149 }
150
151 // GetWorkJSONResp is resp struct for get-work-json API
152 type GetWorkJSONResp struct {
153         BlockHeader *BlockHeaderJSON `json:"block_header"`
154         Seed        *bc.Hash         `json:"seed"`
155 }
156
157 // GetWorkJSON gets work in json format
158 func (a *API) GetWorkJSON() (*GetWorkJSONResp, error) {
159         bh, err := a.miningPool.GetWork()
160         if err != nil {
161                 return nil, err
162         }
163
164         seed, err := a.chain.CalcNextSeed(&bh.PreviousBlockHash)
165         if err != nil {
166                 return nil, err
167         }
168
169         return &GetWorkJSONResp{
170                 BlockHeader: &BlockHeaderJSON{
171                         Version:           bh.Version,
172                         Height:            bh.Height,
173                         PreviousBlockHash: bh.PreviousBlockHash,
174                         Timestamp:         bh.Timestamp,
175                         //                      Nonce:             bh.Nonce,
176                         //                      Bits:              bh.Bits,
177                         BlockCommitment: &bh.BlockCommitment,
178                 },
179                 Seed: seed,
180         }, nil
181 }
182
183 // SubmitWork tries to submit work to the chain
184 func (a *API) SubmitWork(bh *types.BlockHeader) error {
185         return a.miningPool.SubmitWork(bh)
186 }
187
188 func (a *API) setMining(in struct {
189         IsMining bool `json:"is_mining"`
190 }) Response {
191         if in.IsMining {
192                 if _, err := a.wallet.AccountMgr.GetMiningAddress(); err != nil {
193                         return NewErrorResponse(errors.New("Mining address does not exist"))
194                 }
195                 return a.startMining()
196         }
197         return a.stopMining()
198 }
199
200 func (a *API) startMining() Response {
201         a.cpuMiner.Start()
202         if !a.IsMining() {
203                 return NewErrorResponse(errors.New("Failed to start mining"))
204         }
205         return NewSuccessResponse("")
206 }
207
208 func (a *API) stopMining() Response {
209         a.cpuMiner.Stop()
210         if a.IsMining() {
211                 return NewErrorResponse(errors.New("Failed to stop mining"))
212         }
213         return NewSuccessResponse("")
214 }