1 package chainrpc
2 3 import (
4 "bytes"
5 "encoding/binary"
6 "encoding/hex"
7 "fmt"
8 "math/big"
9 "math/rand"
10 "time"
11 12 "github.com/p9c/p9/pkg/bits"
13 block2 "github.com/p9c/p9/pkg/block"
14 "github.com/p9c/p9/pkg/fork"
15 16 "github.com/p9c/p9/pkg/qu"
17 18 "github.com/conformal/fastsha256"
19 20 "github.com/p9c/p9/pkg/blockchain"
21 "github.com/p9c/p9/pkg/btcjson"
22 "github.com/p9c/p9/pkg/chainhash"
23 "github.com/p9c/p9/pkg/wire"
24 )
25 26 // Uint256Size is the number of bytes needed to represent an unsigned 256-bit integer.
27 const Uint256Size = 32
28 29 // GetworkDataLen is the length of the data field of the getwork RPC.
30 //
31 // It consists of the serialized block header plus the internal sha256 padding. The internal sha256 padding consists of
32 // a single 1 bit followed by enough zeros to pad the message out to 56 bytes followed by length of the message in bits
33 // encoded as a big-endian uint64 (8 bytes). Thus, the resulting length is a multiple of the sha256 block size (64
34 // bytes).
35 var GetworkDataLen = (1 + ((wire.MaxBlockHeaderPayload + 8) / fastsha256.
36 BlockSize)) * fastsha256.BlockSize
37 38 // Hash1Len is the length of the hash1 field of the getwork RPC.
39 //
40 // It consists of a zero hash plus the internal sha256 padding. See the getworkDataLen comment for details about the
41 // internal sha256 padding format.
42 var Hash1Len = (1 + ((chainhash.HashSize + 8) / fastsha256.
43 BlockSize)) * fastsha256.BlockSize
44 45 // BigToLEUint256 returns the passed big integer as an unsigned 256-bit integer encoded as little-endian bytes.
46 //
47 // Numbers which are larger than the max unsigned 256-bit integer are truncated.
48 func BigToLEUint256(n *big.Int) [Uint256Size]byte {
49 // Pad or truncate the big-endian big int to correct number of bytes.
50 nBytes := n.Bytes()
51 nlen := len(nBytes)
52 pad := 0
53 start := 0
54 if nlen <= Uint256Size {
55 pad = Uint256Size - nlen
56 } else {
57 start = nlen - Uint256Size
58 }
59 var buf [Uint256Size]byte
60 copy(buf[pad:], nBytes[start:])
61 // Reverse the bytes to little endian and return them.
62 for i := 0; i < Uint256Size/2; i++ {
63 buf[i], buf[Uint256Size-1-i] = buf[Uint256Size-1-i], buf[i]
64 }
65 return buf
66 }
67 68 // HandleGetWork handles the getwork call
69 func HandleGetWork(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
70 c := cmd.(*btcjson.GetWorkCmd)
71 if len(s.StateCfg.ActiveMiningAddrs) == 0 {
72 return nil, &btcjson.RPCError{
73 Code: btcjson.ErrRPCInternal.Code,
74 Message: "No payment addresses specified via --miningaddr",
75 }
76 }
77 netwk := (s.Config.Network.V())[0]
78 if !((netwk == 'r') || (netwk == 's')) &&
79 s.Cfg.ConnMgr.ConnectedCount() == 0 {
80 return nil, &btcjson.RPCError{
81 Code: btcjson.ErrRPCClientNotConnected,
82 Message: "Pod is not connected to network",
83 }
84 }
85 // No point in generating or accepting work before the chain is synced.
86 latestHeight := s.Cfg.Chain.BestSnapshot().Height
87 if latestHeight != 0 && !s.Cfg.SyncMgr.IsCurrent() {
88 return nil, &btcjson.RPCError{
89 Code: btcjson.ErrRPCClientInInitialDownload,
90 Message: "Pod is not yet synchronised...",
91 }
92 }
93 state := s.GBTWorkState
94 state.Lock()
95 defer state.Unlock()
96 if c.Data != nil {
97 return HandleGetWorkSubmission(s, *c.Data)
98 }
99 // Choose a payment address at random.
100 rand.Seed(time.Now().UnixNano())
101 payToAddr := s.StateCfg.ActiveMiningAddrs[rand.Intn(len(s.StateCfg.ActiveMiningAddrs))]
102 lastTxUpdate := s.GBTWorkState.LastTxUpdate
103 latestHash := &s.Cfg.Chain.BestSnapshot().Hash
104 generator := s.Cfg.Generator
105 if state.Template == nil {
106 var e error
107 state.Template, e = generator.NewBlockTemplate(payToAddr, s.Cfg.Algo)
108 if e != nil {
109 return nil, e
110 }
111 }
112 msgBlock := state.Template.Block
113 if msgBlock == nil || state.prevHash == nil ||
114 !state.prevHash.IsEqual(latestHash) ||
115 (state.LastTxUpdate != lastTxUpdate &&
116 time.Now().After(state.LastGenerated.Add(time.Minute))) {
117 // Reset the extra nonce and clear all cached template variations if the best block changed.
118 if state.prevHash != nil && !state.prevHash.IsEqual(latestHash) {
119 e := state.UpdateBlockTemplate(s, false)
120 if e != nil {
121 W.Ln("failed to update block template", e)
122 }
123 }
124 // Reset the previous best hash the block template was generated against so any errors below cause the next
125 // invocation to try again.
126 state.prevHash = nil
127 var e error
128 state.Template, e = generator.NewBlockTemplate(payToAddr, s.Cfg.Algo)
129 if e != nil {
130 errStr := fmt.Sprintf("Failed to create new block template: %v", e)
131 E.Ln(errStr)
132 return nil, &btcjson.RPCError{
133 Code: btcjson.ErrRPCInternal.Code,
134 Message: errStr,
135 }
136 }
137 msgBlock = state.Template.Block
138 // Update work state to ensure another block template isn't generated until needed.
139 state.Template.Block = msgBlock
140 state.LastGenerated = time.Now()
141 state.LastTxUpdate = lastTxUpdate
142 state.prevHash = latestHash
143 D.C(
144 func() string {
145 return fmt.Sprintf(
146 "generated block template (timestamp %v, target %064x, "+
147 "merkle root %s, signature script %x)",
148 msgBlock.Header.Timestamp, bits.CompactToBig(
149 msgBlock.Header.
150 Bits,
151 ), msgBlock.Header.MerkleRoot,
152 msgBlock.Transactions[0].TxIn[0].SignatureScript,
153 )
154 },
155 )
156 } else {
157 // At this point, there is a saved block template and a new request for work was made but either the available
158 // transactions haven't change or it hasn't been long enough to trigger a new block template to be generated.
159 //
160 // So, update the existing block template and track the variations so each variation can be regenerated if a
161 // caller finds an answer and makes a submission against it. Update the time of the block template to the
162 // current time while accounting for the median time of the past several blocks per the chain consensus rules.
163 e := generator.UpdateBlockTime(0, msgBlock)
164 if e != nil {
165 W.Ln("failed to update block time", e)
166 }
167 // Increment the extra nonce and update the block template with the new value by regenerating the coinbase
168 // script and setting the merkle root to the new value.
169 D.F(
170 "updated block template (timestamp %v, target %064x, "+
171 "merkle root %s, signature script %x)",
172 msgBlock.Header.Timestamp, bits.CompactToBig(msgBlock.Header.Bits),
173 msgBlock.Header.MerkleRoot, msgBlock.Transactions[0].TxIn[0].
174 SignatureScript,
175 )
176 }
177 // In order to efficiently store the variations of block templates that have been provided to callers save a pointer
178 // to the block as well as the modified signature script keyed by the merkle root. This information, along with the
179 // data that is included in a work submission, is used to rebuild the block before checking the submitted solution.
180 /*
181 coinbaseTx := msgBlock.Transactions[0]
182 state.blockInfo[msgBlock.Header.MerkleRoot] = &workStateBlockInfo{
183 msgBlock: msgBlock,
184 signatureScript: coinbaseTx.TxIn[0].SignatureScript,
185 }
186 */
187 // Serialize the block header into a buffer large enough to hold the the block header and the internal sha256
188 // padding that is added and returned as part of the data below.
189 data := make([]byte, 0, GetworkDataLen)
190 buf := bytes.NewBuffer(data)
191 e := msgBlock.Header.Serialize(buf)
192 if e != nil {
193 errStr := fmt.Sprintf("Failed to serialize data: %v", e)
194 W.Ln(errStr)
195 return nil, &btcjson.RPCError{
196 Code: btcjson.ErrRPCInternal.Code,
197 Message: errStr,
198 }
199 }
200 // Calculate the midstate for the block header. The midstate here is the internal state of the sha256 algorithm for
201 // the first chunk of the block header (sha256 operates on 64-byte chunks) which is before the nonce.
202 //
203 // This allows sophisticated callers to avoid hashing the first chunk over and over while iterating the nonce range.
204 data = data[:buf.Len()]
205 midstate := fastsha256.MidState256(data)
206 // Expand the data slice to include the full data buffer and apply the internal sha256 padding which consists of a
207 // single 1 bit followed by enough zeros to pad the message out to 56 bytes followed by the length of the message in
208 // bits encoded as a big-endian uint64 (8 bytes).
209 //
210 // Thus, the resulting length is a multiple of the sha256 block size (64 bytes). This makes the data ready for
211 // sophisticated caller to make use of only the second chunk along with the midstate for the first chunk.
212 data = data[:GetworkDataLen]
213 data[wire.MaxBlockHeaderPayload] = 0x80
214 binary.BigEndian.PutUint64(
215 data[len(data)-8:],
216 wire.MaxBlockHeaderPayload*8,
217 )
218 // Create the hash1 field which is a zero hash along with the internal sha256 padding as described above. This field
219 // is really quite useless, but it is required for compatibility with the reference implementation.
220 var hash1 = make([]byte, Hash1Len)
221 hash1[chainhash.HashSize] = 0x80
222 binary.BigEndian.PutUint64(hash1[len(hash1)-8:], chainhash.HashSize*8)
223 // The final result reverses the each of the fields to little endian. In particular, the data, hash1, and midstate
224 // fields are treated as arrays of uint32s (per the internal sha256 hashing state) which are in big endian, and thus
225 // each 4 bytes is byte swapped.
226 //
227 // The target is also in big endian, but it is treated as a uint256 and byte swapped to little endian accordingly.
228 //
229 // The fact the fields are reversed in this way is rather odd and likely an artifact of some legacy internal state
230 // in the reference implementation, but it is required for compatibility.
231 ReverseUint32Array(data)
232 ReverseUint32Array(hash1)
233 ReverseUint32Array(midstate[:])
234 target := BigToLEUint256(bits.CompactToBig(msgBlock.Header.Bits))
235 reply := &btcjson.GetWorkResult{
236 Data: hex.EncodeToString(data),
237 Hash1: hex.EncodeToString(hash1),
238 Midstate: hex.EncodeToString(midstate[:]),
239 Target: hex.EncodeToString(target[:]),
240 }
241 return reply, nil
242 }
243 244 // HandleGetWorkSubmission is a helper for handleGetWork which deals with the calling submitting work to be verified and
245 // processed.
246 //
247 // This function MUST be called with the RPC workstate locked.
248 func HandleGetWorkSubmission(s *Server, hexData string) (interface{}, error) {
249 // Ensure the provided data is sane.
250 if len(hexData)%2 != 0 {
251 hexData = "0" + hexData
252 }
253 data, e := hex.DecodeString(hexData)
254 if e != nil {
255 return nil, &btcjson.RPCError{
256 Code: btcjson.ErrRPCInvalidParameter,
257 Message: fmt.Sprintf(
258 "argument must be "+
259 "hexadecimal string (not %q)", hexData,
260 ),
261 }
262 }
263 if len(data) != GetworkDataLen {
264 return false, &btcjson.RPCError{
265 Code: btcjson.ErrRPCInvalidParameter,
266 Message: fmt.Sprintf(
267 "argument must be "+
268 "%d bytes (not %d)", GetworkDataLen,
269 len(data),
270 ),
271 }
272 }
273 // Reverse the data as if it were an array of 32-bit unsigned integers. The fact the getwork request and submission
274 // data is reversed in this way is rather odd and likely an artifact of some legacy internal state in the reference
275 // implementation, but it is required for compatibility.
276 ReverseUint32Array(data)
277 // Deserialize the block header from the data.
278 var submittedHeader wire.BlockHeader
279 bhBuf := bytes.NewBuffer(data[0:wire.MaxBlockHeaderPayload])
280 e = submittedHeader.Deserialize(bhBuf)
281 if e != nil {
282 return false, &btcjson.RPCError{
283 Code: btcjson.ErrRPCInvalidParameter,
284 Message: fmt.Sprintf(
285 "argument does not "+
286 "contain a valid block header: %v", e,
287 ),
288 }
289 }
290 // Look up the full block for the provided data based on the merkle root.
291 //
292 // Return false to indicate the solve failed if it's not available.
293 state := s.GBTWorkState
294 295 if state.Template.Block.Header.MerkleRoot.String() == "" {
296 D.Ln(
297 "Block submitted via getwork has no matching template for merkle root",
298 submittedHeader.MerkleRoot,
299 )
300 return false, nil
301 }
302 // Reconstruct the block using the submitted header stored block info.
303 msgBlock := state.Template.Block
304 block := block2.NewBlock(msgBlock)
305 msgBlock.Header.Timestamp = submittedHeader.Timestamp
306 msgBlock.Header.Nonce = submittedHeader.Nonce
307 msgBlock.Transactions[0].TxIn[0].SignatureScript = state.Template.Block.
308 Transactions[0].TxIn[0].SignatureScript
309 merkles := blockchain.BuildMerkleTreeStore(block.Transactions(), false)
310 msgBlock.Header.MerkleRoot = *merkles.GetRoot()
311 // Ensure the submitted block hash is less than the target difficulty.
312 pl := fork.GetMinDiff(s.Cfg.Algo, s.Cfg.Chain.BestSnapshot().Height)
313 e = blockchain.CheckProofOfWork(block, pl, s.Cfg.Chain.BestSnapshot().Height)
314 if e != nil {
315 // Anything other than a rule violation is an unexpected error, so return that error as an internal error.
316 if _, ok := e.(blockchain.RuleError); !ok {
317 return nil, &btcjson.RPCError{
318 Code: btcjson.ErrRPCInternal.Code,
319 Message: fmt.Sprintf(
320 "Unexpected error while checking proof"+
321 " of work: %v", e,
322 ),
323 }
324 }
325 D.Ln("block submitted via getwork does not meet the required proof of work:", e)
326 return false, nil
327 }
328 latestHash := &s.Cfg.Chain.BestSnapshot().Hash
329 if !msgBlock.Header.PrevBlock.IsEqual(latestHash) {
330 D.F("block submitted via getwork with previous block %s is stale", msgBlock.Header.PrevBlock)
331 return false, nil
332 }
333 // Process this block using the same rules as blocks coming from other nodes. This will in turn relay it to the
334 // network like normal.
335 _, isOrphan, e := s.Cfg.Chain.ProcessBlock(
336 0, block, 0,
337 s.Cfg.Chain.BestSnapshot().Height,
338 )
339 if e != nil || isOrphan {
340 // Anything other than a rule violation is an unexpected error, so return that error as an internal error.
341 if _, ok := e.(blockchain.RuleError); !ok {
342 return nil, &btcjson.RPCError{
343 Code: btcjson.ErrRPCInternal.Code,
344 Message: fmt.Sprintf("Unexpected error while processing block: %v", e),
345 }
346 }
347 I.Ln("block submitted via getwork rejected:", e)
348 return false, nil
349 }
350 // The block was accepted.
351 blockSha := block.Hash()
352 I.Ln("block submitted via getwork accepted:", blockSha)
353 return true, nil
354 }
355 356 // ReverseUint32Array treats the passed bytes as a series of uint32s and reverses the byte order of each uint32.
357 //
358 // The passed byte slice must be a multiple of 4 for a correct result.
359 //
360 // The passed bytes slice is modified.
361 func ReverseUint32Array(b []byte) {
362 bLen := len(b)
363 for i := 0; i < bLen; i += 4 {
364 b[i], b[i+3] = b[i+3], b[i]
365 b[i+1], b[i+2] = b[i+2], b[i+1]
366 }
367 }
368