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