handlers.go raw
1 package chainrpc
2
3 import (
4 "bytes"
5 "encoding/base64"
6 "encoding/hex"
7 "errors"
8 "fmt"
9 "github.com/p9c/p9/pkg/amt"
10 block2 "github.com/p9c/p9/pkg/block"
11 "github.com/p9c/p9/pkg/btcaddr"
12 "github.com/p9c/p9/pkg/fork"
13 "github.com/p9c/p9/pkg/log"
14 "math/big"
15 "net"
16 "strconv"
17 "strings"
18 "time"
19
20 "github.com/p9c/p9/pkg/qu"
21
22 "github.com/p9c/p9/pkg/blockchain"
23 "github.com/p9c/p9/pkg/btcjson"
24 "github.com/p9c/p9/pkg/chainhash"
25 "github.com/p9c/p9/pkg/database"
26 "github.com/p9c/p9/pkg/ecc"
27 "github.com/p9c/p9/pkg/interrupt"
28 "github.com/p9c/p9/pkg/mempool"
29 "github.com/p9c/p9/pkg/txscript"
30 "github.com/p9c/p9/pkg/util"
31 "github.com/p9c/p9/pkg/wire"
32 )
33
34 // HandleAddNode handles addnode commands.
35 func HandleAddNode(s *Server, cmd interface{}, closeChan qu.C) (ifc interface{}, e error) {
36 var msg string
37 c, ok := cmd.(*btcjson.AddNodeCmd)
38 if !ok {
39 var h string
40 h, e = s.HelpCacher.RPCMethodHelp("addnode")
41 D.Ln(h, e)
42 if e != nil {
43 msg = e.Error() + "\n\n"
44 }
45 msg += h
46 return nil, &btcjson.RPCError{
47 Code: btcjson.ErrRPCInvalidParameter,
48 Message: msg,
49 // "invalid subcommand for addnode",
50 }
51 }
52 addr := NormalizeAddress(c.Addr, s.Cfg.ChainParams.DefaultPort)
53 switch c.SubCmd {
54 case "add":
55 e = s.Cfg.ConnMgr.Connect(addr, true)
56 case "remove":
57 e = s.Cfg.ConnMgr.RemoveByAddr(addr)
58 case "onetry":
59 e = s.Cfg.ConnMgr.Connect(addr, false)
60 default:
61 return nil, &btcjson.RPCError{
62 Code: btcjson.ErrRPCInvalidParameter,
63 Message: "invalid subcommand for addnode",
64 }
65 }
66 if e != nil {
67 E.Ln(e)
68 return nil, &btcjson.RPCError{
69 Code: btcjson.ErrRPCInvalidParameter,
70 Message: e.Error(),
71 }
72 }
73 // no data returned unless an error.
74 return nil, nil
75 }
76
77 // HandleAskWallet is the handler for commands that are recognized as valid, but are unable to answer correctly since it
78 // involves wallet state.
79 func HandleAskWallet(
80 s *Server,
81 cmd interface{},
82 closeChan qu.C,
83 ) (interface{}, error) {
84 return nil, ErrRPCNoWallet
85 }
86
87 // HandleCreateRawTransaction handles createrawtransaction commands.
88 func HandleCreateRawTransaction(
89 s *Server,
90 cmd interface{},
91 closeChan qu.C,
92 ) (interface{}, error) {
93 var msg string
94 var e error
95 c, ok := cmd.(*btcjson.CreateRawTransactionCmd)
96 if !ok {
97 var h string
98 h, e = s.HelpCacher.RPCMethodHelp("createrawtransaction")
99 D.Ln(h, e)
100 if e != nil {
101 msg = e.Error() + "\n\n"
102 }
103 msg += h
104 return nil, &btcjson.RPCError{
105 Code: btcjson.ErrRPCInvalidParameter,
106 Message: msg,
107 // "invalid subcommand for addnode",
108 }
109 }
110 // Validate the locktime, if given.
111 if c.LockTime != nil &&
112 (*c.LockTime < 0 || *c.LockTime > int64(wire.MaxTxInSequenceNum)) {
113 return nil, &btcjson.RPCError{
114 Code: btcjson.ErrRPCInvalidParameter,
115 Message: "Locktime out of range",
116 }
117 }
118 // Add all transaction inputs to a new transaction after performing some validity checks.
119 mtx := wire.NewMsgTx(wire.TxVersion)
120 for _, input := range c.Inputs {
121 var txHash *chainhash.Hash
122 txHash, e = chainhash.NewHashFromStr(input.Txid)
123 if e != nil {
124 E.Ln(e)
125 return nil, DecodeHexError(input.Txid)
126 }
127 prevOut := wire.NewOutPoint(txHash, input.Vout)
128 txIn := wire.NewTxIn(prevOut, []byte{}, nil)
129 if c.LockTime != nil && *c.LockTime != 0 {
130 txIn.Sequence = wire.MaxTxInSequenceNum - 1
131 }
132 mtx.AddTxIn(txIn)
133 }
134 // Add all transaction outputs to the transaction after performing some validity checks.
135 params := s.Cfg.ChainParams
136 for encodedAddr, amount := range c.Amounts {
137 // Ensure amount is in the valid range for monetary amounts.
138 if amount <= 0 || amount > amt.MaxSatoshi.ToDUO() {
139 return nil, &btcjson.RPCError{
140 Code: btcjson.ErrRPCType,
141 Message: "Invalid amount",
142 }
143 }
144 // Decode the provided address.
145 var addr btcaddr.Address
146 addr, e = btcaddr.Decode(encodedAddr, params)
147 if e != nil {
148 E.Ln(e)
149 return nil, &btcjson.RPCError{
150 Code: btcjson.ErrRPCInvalidAddressOrKey,
151 Message: "Invalid address or key: " + e.Error(),
152 }
153 }
154 // Ensure the address is one of the supported types and that the network encoded with the address matches the
155 // network the Server is currently on.
156 switch addr.(type) {
157 case *btcaddr.PubKeyHash:
158 case *btcaddr.ScriptHash:
159 default:
160 return nil, &btcjson.RPCError{
161 Code: btcjson.ErrRPCInvalidAddressOrKey,
162 Message: "Invalid address or key",
163 }
164 }
165 if !addr.IsForNet(params) {
166 return nil, &btcjson.RPCError{
167 Code: btcjson.ErrRPCInvalidAddressOrKey,
168 Message: "Invalid address: " + encodedAddr +
169 " is for the wrong network",
170 }
171 }
172 // Create a new script which pays to the provided address.
173 var pkScript []byte
174 pkScript, e = txscript.PayToAddrScript(addr)
175 if e != nil {
176 E.Ln(e)
177 context := "Failed to generate pay-to-address script"
178 return nil, InternalRPCError(e.Error(), context)
179 }
180 // Convert the amount to satoshi.
181 var satoshi amt.Amount
182 satoshi, e = amt.NewAmount(amount)
183 if e != nil {
184 E.Ln(e)
185 context := "Failed to convert amount"
186 return nil, InternalRPCError(e.Error(), context)
187 }
188 txOut := wire.NewTxOut(int64(satoshi), pkScript)
189 mtx.AddTxOut(txOut)
190 }
191 // Set the Locktime, if given.
192 if c.LockTime != nil {
193 mtx.LockTime = uint32(*c.LockTime)
194 }
195 // Return the serialized and hex-encoded transaction. Note that this is intentionally not directly returning because
196 // the first return value is a string and it would result in returning an empty string to the client instead of
197 // nothing (nil) in the case of an error.
198 mtxHex, e := MessageToHex(mtx)
199 if e != nil {
200 E.Ln(e)
201 return nil, e
202 }
203 return mtxHex, nil
204 }
205
206 // HandleDecodeRawTransaction handles decoderawtransaction commands.
207 func HandleDecodeRawTransaction(
208 s *Server,
209 cmd interface{},
210 closeChan qu.C,
211 ) (interface{}, error) {
212 var msg string
213 var e error
214 c, ok := cmd.(*btcjson.DecodeRawTransactionCmd)
215 if !ok {
216 var h string
217 h, e = s.HelpCacher.RPCMethodHelp("decoderawtransaction")
218 D.Ln(h, e)
219 if e != nil {
220 msg = e.Error() + "\n\n"
221 }
222 msg += h
223 return nil, &btcjson.RPCError{
224 Code: btcjson.ErrRPCInvalidParameter,
225 Message: msg,
226 // "invalid subcommand for addnode",
227 }
228 }
229 // Deserialize the transaction.
230 hexStr := c.HexTx
231 if len(hexStr)%2 != 0 {
232 hexStr = "0" + hexStr
233 }
234 serializedTx, e := hex.DecodeString(hexStr)
235 if e != nil {
236 E.Ln(e)
237 return nil, DecodeHexError(hexStr)
238 }
239 var mtx wire.MsgTx
240 e = mtx.Deserialize(bytes.NewReader(serializedTx))
241 if e != nil {
242 E.Ln(e)
243 return nil, &btcjson.RPCError{
244 Code: btcjson.ErrRPCDeserialization,
245 Message: "TX decode failed: " + e.Error(),
246 }
247 }
248 // Create and return the result.
249 txReply := btcjson.TxRawDecodeResult{
250 Txid: mtx.TxHash().String(),
251 Version: mtx.Version,
252 Locktime: mtx.LockTime,
253 Vin: CreateVinList(&mtx),
254 Vout: CreateVoutList(&mtx, s.Cfg.ChainParams, nil),
255 }
256 return txReply, nil
257 }
258
259 // HandleDecodeScript handles decodescript commands.
260 func HandleDecodeScript(
261 s *Server,
262 cmd interface{},
263 closeChan qu.C,
264 ) (interface{}, error) {
265 var msg string
266 var e error
267 c, ok := cmd.(*btcjson.DecodeScriptCmd)
268 if !ok {
269 var h string
270 h, e = s.HelpCacher.RPCMethodHelp("decodescript")
271 D.Ln(h, e)
272 if e != nil {
273 msg = e.Error() + "\n\n"
274 }
275 msg += h
276 return nil, &btcjson.RPCError{
277 Code: btcjson.ErrRPCInvalidParameter,
278 Message: msg,
279 // "invalid subcommand for addnode",
280 }
281 }
282 // Convert the hex script to bytes.
283 hexStr := c.HexScript
284 if len(hexStr)%2 != 0 {
285 hexStr = "0" + hexStr
286 }
287 script, e := hex.DecodeString(hexStr)
288 if e != nil {
289 E.Ln(e)
290 return nil, DecodeHexError(hexStr)
291 }
292 // The disassembled string will contain [error] inline if the script doesn't fully parse, so ignore the error here.
293 disbuf, _ := txscript.DisasmString(script)
294 // Get information about the script. Ignore the error here since an error means the script couldn't parse and there
295 // is no additinal information about it anyways.
296 scriptClass, addrs, reqSigs, _ := txscript.ExtractPkScriptAddrs(
297 script,
298 s.Cfg.ChainParams,
299 )
300 addresses := make([]string, len(addrs))
301 for i, addr := range addrs {
302 addresses[i] = addr.EncodeAddress()
303 }
304 // Convert the script itself to a pay-to-script-hash address.
305 p2sh, e := btcaddr.NewScriptHash(script, s.Cfg.ChainParams)
306 if e != nil {
307 E.Ln(e)
308 context := "Failed to convert script to pay-to-script-hash"
309 return nil, InternalRPCError(e.Error(), context)
310 }
311 // Generate and return the reply.
312 reply := btcjson.DecodeScriptResult{
313 Asm: disbuf,
314 ReqSigs: int32(reqSigs),
315 Type: scriptClass.String(),
316 Addresses: addresses,
317 }
318 if scriptClass != txscript.ScriptHashTy {
319 reply.P2sh = p2sh.EncodeAddress()
320 }
321 return reply, nil
322 }
323
324 // HandleEstimateFee handles estimatefee commands.
325 func HandleEstimateFee(
326 s *Server,
327 cmd interface{},
328 closeChan qu.C,
329 ) (interface{}, error) {
330 var msg string
331 var e error
332 c, ok := cmd.(*btcjson.EstimateFeeCmd)
333 if !ok {
334 var h string
335 h, e = s.HelpCacher.RPCMethodHelp("estimatefee")
336 D.Ln(h, e)
337 if e != nil {
338 msg = e.Error() + "\n\n"
339 }
340 msg += h
341 return nil, &btcjson.RPCError{
342 Code: btcjson.ErrRPCInvalidParameter,
343 Message: msg,
344 // "invalid subcommand for addnode",
345 }
346 }
347 if s.Cfg.FeeEstimator == nil {
348 return nil, errors.New("fee estimation disabled")
349 }
350 if c.NumBlocks <= 0 {
351 return -1.0, errors.New("parameter NumBlocks must be positive")
352 }
353 feeRate, e := s.Cfg.FeeEstimator.EstimateFee(uint32(c.NumBlocks))
354 if e != nil {
355 E.Ln(e)
356 return -1.0, e
357 }
358 // Convert to satoshis per kb.
359 return float64(feeRate), nil
360 }
361
362 // HandleGenerate handles generate commands.
363 func HandleGenerate(
364 s *Server,
365 cmd interface{},
366 closeChan qu.C,
367 ) (interface{}, error) {
368 // Respond with an error if there are no addresses to pay the created blocks to.
369 if len(s.StateCfg.ActiveMiningAddrs) == 0 {
370 return nil, &btcjson.RPCError{
371 Code: btcjson.ErrRPCInternal.Code,
372 Message: "No payment addresses specified via --miningaddr",
373 }
374 }
375 // Respond with an error if there's virtually 0 chance of mining a block with the CPU.
376 if !s.Cfg.ChainParams.GenerateSupported {
377 return nil, &btcjson.RPCError{
378 Code: btcjson.ErrRPCDifficulty,
379 Message: fmt.Sprintf(
380 "No support for `generate` on the current"+
381 " network, %s, as it's unlikely to be possible to mine a block"+
382 " with the CPU.", s.Cfg.ChainParams.Net,
383 ),
384 }
385 }
386 D.Ln("cpu miner stuff is missing here")
387 // Set the algorithm according to the port we were called on
388 // s.Cfg.CPUMiner.SetAlgo(s.Cfg.Algo)
389 // c := cmd.(*btcjson.GenerateCmd)
390 // // Respond with an error if the client is requesting 0 blocks to be
391 // // generated.
392 // if c.NumBlocks == 0 {
393 // return nil, &btcjson.RPCError{
394 // Code: btcjson.ErrRPCInternal.Code,
395 // Message: "Please request a nonzero number of blocks to generate.",
396 // }
397 // }
398 // // Create a reply
399 // reply := make([]string, c.NumBlocks)
400 // blockHashes, e := s.Cfg.CPUMiner.GenerateNBlocks(0, c.NumBlocks,
401 // s.Cfg.Algo)
402 // if e != nil {
403 // L.Script // return nil, &btcjson.RPCError{
404 // Code: btcjson.ErrRPCInternal.Code,
405 // Message: err.ScriptError(),
406 // }
407 // }
408 // // Mine the correct number of blocks, assigning the hex representation of
409 // // the hash of each one to its place in the reply.
410 // for i, hash := range blockHashes {
411 // reply[i] = hash.String()
412 // }
413 // return reply, nil
414 return nil, nil
415 }
416
417 // HandleGetAddedNodeInfo handles getaddednodeinfo commands.
418 func HandleGetAddedNodeInfo(
419 s *Server,
420 cmd interface{},
421 closeChan qu.C,
422 ) (interface{}, error) {
423 var msg string
424 var e error
425 c, ok := cmd.(*btcjson.GetAddedNodeInfoCmd)
426 if !ok {
427 var h string
428 h, e = s.HelpCacher.RPCMethodHelp("getaddednodeinfo")
429 if e != nil {
430 msg = e.Error() + "\n\n"
431 }
432 msg += h
433 return nil, &btcjson.RPCError{
434 Code: btcjson.ErrRPCInvalidParameter,
435 Message: msg,
436 // "invalid subcommand for addnode",
437 }
438 }
439 // Retrieve a list of persistent (added) peers from the Server and filter the list of peers per the specified
440 // address (if any).
441 peers := s.Cfg.ConnMgr.PersistentPeers()
442 if c.Node != nil {
443 node := *c.Node
444 found := false
445 for i, peer := range peers {
446 if peer.ToPeer().Addr() == node {
447 peers = peers[i : i+1]
448 found = true
449 }
450 }
451 if !found {
452 return nil, &btcjson.RPCError{
453 Code: btcjson.ErrRPCClientNodeNotAdded,
454 Message: "Node has not been added",
455 }
456 }
457 }
458 // Without the dns flag, the result is just a slice of the addresses as strings.
459 if !c.DNS {
460 results := make([]string, 0, len(peers))
461 for _, peer := range peers {
462 results = append(results, peer.ToPeer().Addr())
463 }
464 return results, nil
465 }
466 // With the dns flag, the result is an array of JSON objects which include the result of DNS lookups for each peer.
467 results := make([]*btcjson.GetAddedNodeInfoResult, 0, len(peers))
468 for _, rpcPeer := range peers {
469 // Set the "address" of the peer which could be an ip address or a domain name.
470 peer := rpcPeer.ToPeer()
471 var result btcjson.GetAddedNodeInfoResult
472 result.AddedNode = peer.Addr()
473 result.Connected = btcjson.Bool(peer.Connected())
474 // Split the address into host and port portions so we can do a DNS lookup against the host. When no port is
475 // specified in the address, just use the address as the host.
476 var host string
477 host, _, e = net.SplitHostPort(peer.Addr())
478 if e != nil {
479 host = peer.Addr()
480 }
481 var ipList []string
482 switch {
483 case net.ParseIP(host) != nil, strings.HasSuffix(host, ".onion"):
484 ipList = make([]string, 1)
485 ipList[0] = host
486 default:
487 // Do a DNS lookup for the address. If the lookup fails, just use the host.
488 ips, e := Lookup(s.StateCfg)(host)
489 if e != nil {
490 ipList = make([]string, 1)
491 ipList[0] = host
492 break
493 }
494 ipList = make([]string, 0, len(ips))
495 for _, ip := range ips {
496 ipList = append(ipList, ip.String())
497 }
498 }
499 // Add the addresses and connection info to the result.
500 addrs := make([]btcjson.GetAddedNodeInfoResultAddr, 0, len(ipList))
501 for _, ip := range ipList {
502 var addr btcjson.GetAddedNodeInfoResultAddr
503 addr.Address = ip
504 addr.Connected = "false"
505 if ip == host && peer.Connected() {
506 addr.Connected = log.DirectionString(peer.Inbound())
507 }
508 addrs = append(addrs, addr)
509 }
510 result.Addresses = &addrs
511 results = append(results, &result)
512 }
513 return results, nil
514 }
515
516 // HandleGetBestBlock implements the getbestblock command.
517 func HandleGetBestBlock(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
518 // All other "get block" commands give either the height, the hash, or both but require the block SHA. This gets
519 // both for the best block.
520 best := s.Cfg.Chain.BestSnapshot()
521 result := &btcjson.GetBestBlockResult{
522 Hash: best.Hash.String(),
523 Height: best.Height,
524 }
525 return result, nil
526 }
527
528 // HandleGetBestBlockHash implements the getbestblockhash command.
529 func HandleGetBestBlockHash(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
530 best := s.Cfg.Chain.BestSnapshot()
531 return best.Hash.String(), nil
532 }
533
534 // HandleGetBlock implements the getblock command.
535 func HandleGetBlock(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
536 var msg string
537 var e error
538 c, ok := cmd.(*btcjson.GetBlockCmd)
539 if !ok {
540 var h string
541 h, e = s.HelpCacher.RPCMethodHelp("getblock")
542 if e != nil {
543 msg = e.Error() + "\n\n"
544 }
545 msg += h
546 return nil, &btcjson.RPCError{
547 Code: btcjson.ErrRPCInvalidParameter,
548 Message: msg,
549 // "invalid subcommand for addnode",
550 }
551 }
552 // Load the raw block bytes from the database.
553 hash, e := chainhash.NewHashFromStr(c.Hash)
554 if e != nil {
555 return nil, DecodeHexError(c.Hash)
556 }
557 var blkBytes []byte
558 e = s.Cfg.DB.View(
559 func(dbTx database.Tx) (e error) {
560 blkBytes, e = dbTx.FetchBlock(hash)
561 return e
562 },
563 )
564 if e != nil {
565 return nil, &btcjson.RPCError{
566 Code: btcjson.ErrRPCBlockNotFound,
567 Message: "Block not found",
568 }
569 }
570 // When the verbose flag isn't set, simply return the serialized block as a hex-encoded string.
571 if c.Verbose != nil && !*c.Verbose {
572 return hex.EncodeToString(blkBytes), nil
573 }
574 // The verbose flag is set, so generate the JSON object and return it. Deserialize the block.
575 blk, e := block2.NewFromBytes(blkBytes)
576 if e != nil {
577 context := "Failed to deserialize block"
578 return nil, InternalRPCError(e.Error(), context)
579 }
580 // Get the block height from chain.
581 blockHeight, e := s.Cfg.Chain.BlockHeightByHash(hash)
582 if e != nil {
583 context := blockheightfail
584 return nil, InternalRPCError(e.Error(), context)
585 }
586 blk.SetHeight(blockHeight)
587 best := s.Cfg.Chain.BestSnapshot()
588 // Get next block hash unless there are none.
589 var nextHashString string
590 if blockHeight < best.Height {
591 nextHash, e := s.Cfg.Chain.BlockHashByHeight(blockHeight + 1)
592 if e != nil {
593 context := "No next block"
594 return nil, InternalRPCError(e.Error(), context)
595 }
596 nextHashString = nextHash.String()
597 }
598 params := s.Cfg.ChainParams
599 blockHeader := &blk.WireBlock().Header
600 algoname := fork.GetAlgoName(blockHeader.Version, blockHeight)
601 a := fork.GetAlgoVer(algoname, blockHeight)
602 algoid := fork.GetAlgoID(algoname, blockHeight)
603 blockReply := btcjson.GetBlockVerboseResult{
604 Hash: c.Hash,
605 Version: blockHeader.Version,
606 VersionHex: fmt.Sprintf("%08x", blockHeader.Version),
607 PowAlgoID: algoid,
608 PowAlgo: algoname,
609 PowHash: blk.WireBlock().BlockHashWithAlgos(blockHeight).String(),
610 MerkleRoot: blockHeader.MerkleRoot.String(),
611 PreviousHash: blockHeader.PrevBlock.String(),
612 Nonce: blockHeader.Nonce,
613 Time: blockHeader.Timestamp.Unix(),
614 Confirmations: int64(1 + best.Height - blockHeight),
615 Height: int64(blockHeight),
616 TxNum: len(blk.Transactions()),
617 Size: int32(len(blkBytes)),
618 StrippedSize: int32(blk.WireBlock().SerializeSizeStripped()),
619 Weight: int32(blockchain.GetBlockWeight(blk)),
620 Bits: strconv.FormatInt(int64(blockHeader.Bits), 16),
621 Difficulty: GetDifficultyRatio(blockHeader.Bits, params, a),
622 NextHash: nextHashString,
623 }
624 if c.VerboseTx == nil || !*c.VerboseTx {
625 transactions := blk.Transactions()
626 txNames := make([]string, len(transactions))
627 for i, tx := range transactions {
628 txNames[i] = tx.Hash().String()
629 }
630 blockReply.Tx = txNames
631 } else {
632 txns := blk.Transactions()
633 rawTxns := make([]btcjson.TxRawResult, len(txns))
634 for i, tx := range txns {
635 rawTxn, e := CreateTxRawResult(
636 params, tx.MsgTx(),
637 tx.Hash().String(), blockHeader, hash.String(),
638 blockHeight, best.Height,
639 )
640 if e != nil {
641 return nil, e
642 }
643 rawTxns[i] = *rawTxn
644 }
645 blockReply.RawTx = rawTxns
646 }
647 return blockReply, nil
648 }
649
650 // HandleGetBlockChainInfo implements the getblockchaininfo command.
651 func HandleGetBlockChainInfo(
652 s *Server,
653 cmd interface{},
654 closeChan qu.C,
655 ) (interface{}, error) {
656 // Obtain a snapshot of the current best known blockchain state. We'll populate the response to this call primarily
657 // from this snapshot.
658 params := s.Cfg.ChainParams
659 chain := s.Cfg.Chain
660 chainSnapshot := chain.BestSnapshot()
661 chainInfo := &btcjson.GetBlockChainInfoResult{
662 Chain: params.Name,
663 Blocks: chainSnapshot.Height,
664 Headers: chainSnapshot.Height,
665 BestBlockHash: chainSnapshot.Hash.String(),
666 Difficulty: GetDifficultyRatio(chainSnapshot.Bits, params, 2),
667 MedianTime: chainSnapshot.MedianTime.Unix(),
668 Pruned: false,
669 // Bip9SoftForks: make(map[string]*btcjson.Bip9SoftForkDescription),
670 }
671 // Next, populate the response with information describing the current status of soft-forks deployed via the
672 // super-majority block signalling mechanism.
673 // height := chainSnapshot.Height
674 // chainInfo.SoftForks = []*btcjson.SoftForkDescription{
675 // {
676 // ID: "bip34",
677 // Version: 2,
678 // Reject: struct {
679 // Status bool `json:"status"`
680 // }{
681 // Status: height >= params.BIP0034Height,
682 // },
683 // },
684 // {
685 // ID: "bip66",
686 // Version: 3,
687 // Reject: struct {
688 // Status bool `json:"status"`
689 // }{
690 // Status: height >= params.BIP0066Height,
691 // },
692 // },
693 // {
694 // ID: "bip65",
695 // Version: 4,
696 // Reject: struct {
697 // Status bool `json:"status"`
698 // }{
699 // Status: height >= params.BIP0065Height,
700 // },
701 // },
702 // }
703 // // Finally, query the BIP0009 version bits state for all currently defined BIP0009 soft-fork deployments.
704 // for deployment, deploymentDetails := range params.Deployments {
705 // // Map the integer deployment ID into a human readable fork-name.
706 // var forkName string
707 // switch deployment {
708 // case chaincfg.DeploymentTestDummy:
709 // forkName = "dummy"
710 // case chaincfg.DeploymentCSV:
711 // forkName = "csv"
712 // case chaincfg.DeploymentSegwit:
713 // forkName = "segwit"
714 // default:
715 // return nil, &btcjson.RPCError{
716 // Code: btcjson.ErrRPCInternal.Code,
717 // Message: fmt.Sprintf(
718 // "Unknown deployment %v "+
719 // "detected", deployment,
720 // ),
721 // }
722 // }
723 // // Query the chain for the current status of the deployment as identified by its deployment ID.
724 // deploymentStatus, e := chain.ThresholdState(uint32(deployment))
725 // if e != nil {
726 // General // context := "Failed to obtain deployment status"
727 // return nil, InternalRPCError(err.GeneralError(), context)
728 // }
729 // // Attempt to convert the current deployment status into a human readable string. If the status is unrecognized,
730 // // then a non-nil error is returned.
731 // statusString, e := SoftForkStatus(deploymentStatus)
732 // if e != nil {
733 // General // return nil, &btcjson.RPCError{
734 // Code: btcjson.ErrRPCInternal.Code,
735 // Message: fmt.Sprintf(
736 // "unknown deployment status: %v",
737 // deploymentStatus,
738 // ),
739 // }
740 // }
741 // // Finally, populate the soft-fork description with all the information gathered above.
742 // chainInfo.Bip9SoftForks[forkName] = &btcjson.Bip9SoftForkDescription{
743 // Status: strings.ToLower(statusString),
744 // Bit: deploymentDetails.BitNumber,
745 // StartTime: int64(deploymentDetails.StartTime),
746 // Timeout: int64(deploymentDetails.ExpireTime),
747 // }
748 // }
749 return chainInfo, nil
750 }
751
752 // HandleGetBlockCount implements the getblockcount command.
753 func HandleGetBlockCount(
754 s *Server,
755 cmd interface{},
756 closeChan qu.C,
757 ) (interface{}, error) {
758 best := s.Cfg.Chain.BestSnapshot()
759 return int64(best.Height), nil
760 }
761
762 // HandleGetBlockHash implements the getblockhash command.
763 func HandleGetBlockHash(
764 s *Server,
765 cmd interface{},
766 closeChan qu.C,
767 ) (interface{}, error) {
768 var msg string
769 var e error
770 c, ok := cmd.(*btcjson.GetBlockHashCmd)
771 if !ok {
772 var h string
773 h, e = s.HelpCacher.RPCMethodHelp("getblockhash")
774 if e != nil {
775 msg = e.Error() + "\n\n"
776 }
777 msg += h
778 return nil, &btcjson.RPCError{
779 Code: btcjson.ErrRPCInvalidParameter,
780 Message: msg,
781 // "invalid subcommand for addnode",
782 }
783 }
784 hash, e := s.Cfg.Chain.BlockHashByHeight(int32(c.Index))
785 if e != nil {
786 return nil, &btcjson.RPCError{
787 Code: btcjson.ErrRPCOutOfRange,
788 Message: "Block number out of range",
789 }
790 }
791 return hash.String(), nil
792 }
793
794 // HandleGetBlockHeader implements the getblockheader command.
795 func HandleGetBlockHeader(
796 s *Server,
797 cmd interface{},
798 closeChan qu.C,
799 ) (interface{}, error) {
800 var msg string
801 var e error
802 c, ok := cmd.(*btcjson.GetBlockHeaderCmd)
803 if !ok {
804 var h string
805 h, e = s.HelpCacher.RPCMethodHelp("getblockheader")
806 if e != nil {
807 msg = e.Error() + "\n\n"
808 }
809 msg += h
810 return nil, &btcjson.RPCError{
811 Code: btcjson.ErrRPCInvalidParameter,
812 Message: msg,
813 // "invalid subcommand for addnode",
814 }
815 }
816 // Fetch the header from chain.
817 hash, e := chainhash.NewHashFromStr(c.Hash)
818 if e != nil {
819 return nil, DecodeHexError(c.Hash)
820 }
821 blockHeader, e := s.Cfg.Chain.HeaderByHash(hash)
822 if e != nil {
823 return nil, &btcjson.RPCError{
824 Code: btcjson.ErrRPCBlockNotFound,
825 Message: "Block not found",
826 }
827 }
828 // When the verbose flag isn't set, simply return the serialized block header as a hex-encoded string.
829 if c.Verbose != nil && !*c.Verbose {
830 var headerBuf bytes.Buffer
831 e = blockHeader.Serialize(&headerBuf)
832 if e != nil {
833 context := "Failed to serialize block header"
834 return nil, InternalRPCError(e.Error(), context)
835 }
836 return hex.EncodeToString(headerBuf.Bytes()), nil
837 }
838 // The verbose flag is set, so generate the JSON object and return it. Get the block height from chain.
839 blockHeight, e := s.Cfg.Chain.BlockHeightByHash(hash)
840 if e != nil {
841 context := blockheightfail
842 return nil, InternalRPCError(e.Error(), context)
843 }
844 best := s.Cfg.Chain.BestSnapshot()
845 // Get next block hash unless there are none.
846 var nextHashString string
847 if blockHeight < best.Height {
848 nextHash, e := s.Cfg.Chain.BlockHashByHeight(blockHeight + 1)
849 if e != nil {
850 context := "No next block"
851 return nil, InternalRPCError(e.Error(), context)
852 }
853 nextHashString = nextHash.String()
854 }
855 var a int32 = 2
856 if blockHeader.Version == 514 {
857 a = 514
858 }
859 params := s.Cfg.ChainParams
860 blockHeaderReply := btcjson.GetBlockHeaderVerboseResult{
861 Hash: c.Hash,
862 Confirmations: int64(1 + best.Height - blockHeight),
863 Height: blockHeight,
864 Version: blockHeader.Version,
865 VersionHex: fmt.Sprintf("%08x", blockHeader.Version),
866 MerkleRoot: blockHeader.MerkleRoot.String(),
867 NextHash: nextHashString,
868 PreviousHash: blockHeader.PrevBlock.String(),
869 Nonce: uint64(blockHeader.Nonce),
870 Time: blockHeader.Timestamp.Unix(),
871 Bits: strconv.FormatInt(int64(blockHeader.Bits), 16),
872 Difficulty: GetDifficultyRatio(blockHeader.Bits, params, a),
873 }
874 return blockHeaderReply, nil
875 }
876
877 // HandleGetBlockTemplate implements the getblocktemplate command. See https:// en.bitcoin.it/wiki/BIP_0022 and
878 // https://en.bitcoin.it/wiki/BIP_0023 for more details.
879 func HandleGetBlockTemplate(
880 s *Server,
881 cmd interface{},
882 closeChan qu.C,
883 ) (interface{}, error) {
884 var msg string
885 var e error
886 c, ok := cmd.(*btcjson.GetBlockTemplateCmd)
887 if !ok {
888 var h string
889 h, e = s.HelpCacher.RPCMethodHelp("getblocktemplate")
890 if e != nil {
891 msg = e.Error() + "\n\n"
892 }
893 msg += h
894 return nil, &btcjson.RPCError{
895 Code: btcjson.ErrRPCInvalidParameter,
896 Message: msg,
897 // "invalid subcommand for addnode",
898 }
899 }
900 request := c.Request
901 // Set the default mode and override it if supplied.
902 mode := "template"
903 if request != nil && request.Mode != "" {
904 mode = request.Mode
905 }
906 switch mode {
907 case "template":
908 return HandleGetBlockTemplateRequest(s, request, closeChan)
909 case "proposal":
910 return HandleGetBlockTemplateProposal(s, request)
911 }
912 return nil, &btcjson.RPCError{
913 Code: btcjson.ErrRPCInvalidParameter,
914 Message: "Invalid mode",
915 }
916 }
917
918 // HandleGetBlockTemplateLongPoll is a helper for handleGetBlockTemplateRequest which deals with handling long polling
919 // for block templates. When a caller sends a request with a long poll ID that was previously returned, a response is
920 // not sent until the caller should stop working on the previous block template in favor of the new one.
921 //
922 // In particular, this is the case when the old block template is no longer valid due to a solution already being found
923 // and added to the block chain, or new transactions have shown up and some time has passed without finding a solution.
924 // See https://en.bitcoin.it/wiki/ BIP_0022 for more details.
925 func HandleGetBlockTemplateLongPoll(
926 s *Server,
927 longPollID string,
928 useCoinbaseValue bool, closeChan qu.C,
929 ) (interface{}, error) {
930 state := s.GBTWorkState
931 state.Lock()
932 // The state unlock is intentionally not deferred here since it needs to be manually unlocked before waiting for a
933 // notification about block template changes.
934 if e := state.UpdateBlockTemplate(s, useCoinbaseValue); E.Chk(e) {
935 state.Unlock()
936 return nil, e
937 }
938 // Just return the current block template if the long poll ID provided by the caller is invalid.
939 prevHash, lastGenerated, e := DecodeTemplateID(longPollID)
940 var result *btcjson.GetBlockTemplateResult
941 if e != nil {
942 result, e = state.BlockTemplateResult(useCoinbaseValue, nil)
943 if e != nil {
944 state.Unlock()
945 return nil, e
946 }
947 state.Unlock()
948 return result, nil
949 }
950 // Return the block template now if the specific block template/ identified by the long poll ID no longer matches
951 // the current block template as this means the provided template is stale.
952 prevTemplateHash := &state.Template.Block.Header.PrevBlock
953 if !prevHash.IsEqual(prevTemplateHash) ||
954 lastGenerated != state.LastGenerated.Unix() {
955 // Include whether or not it is valid to submit work against the old block template depending on whether or not
956 // a solution has already been found and added to the block chain.
957 submitOld := prevHash.IsEqual(prevTemplateHash)
958 result, e = state.BlockTemplateResult(
959 useCoinbaseValue,
960 &submitOld,
961 )
962 if e != nil {
963 state.Unlock()
964 return nil, e
965 }
966 state.Unlock()
967 return result, nil
968 }
969 // Register the previous hash and last generated time for notifications Get a channel that will be notified when the
970 // template associated with the provided ID is stale and a new block template should be returned to the caller.
971 longPollChan := state.TemplateUpdateChan(prevHash, lastGenerated)
972 state.Unlock()
973 select {
974 // When the client closes before it's time to send a reply, just return now so the goroutine doesn't hang around.
975 case <-closeChan.Wait():
976 return nil, ErrClientQuit
977 // Wait until signal received to send the reply.
978 case <-longPollChan.Wait():
979 // Fallthrough
980 }
981 // Get the lastest block template
982 state.Lock()
983 defer state.Unlock()
984 if e = state.UpdateBlockTemplate(s, useCoinbaseValue); E.Chk(e) {
985 return nil, e
986 }
987 // Include whether or not it is valid to submit work against the old block template depending on whether or not a
988 // solution has already been found and added to the block chain.
989 submitOld := prevHash.IsEqual(&state.Template.Block.Header.PrevBlock)
990 result, e = state.BlockTemplateResult(useCoinbaseValue, &submitOld)
991 if e != nil {
992 return nil, e
993 }
994 return result, nil
995 }
996
997 // HandleGetBlockTemplateProposal is a helper for handleGetBlockTemplate which deals with block proposals. See
998 // https://en.bitcoin.it/wiki/BIP_0023 for more details.
999 func HandleGetBlockTemplateProposal(
1000 s *Server,
1001 request *btcjson.TemplateRequest,
1002 ) (interface{}, error) {
1003 hexData := request.Data
1004 if hexData == "" {
1005 return false, &btcjson.RPCError{
1006 Code: btcjson.ErrRPCType,
1007 Message: fmt.Sprintf("Data must contain the hex-encoded serialized block that is being proposed"),
1008 }
1009 }
1010 // Ensure the provided data is sane and deserialize the proposed block.
1011 if len(hexData)%2 != 0 {
1012 hexData = "0" + hexData
1013 }
1014 dataBytes, e := hex.DecodeString(hexData)
1015 if e != nil {
1016 return false, &btcjson.RPCError{
1017 Code: btcjson.ErrRPCDeserialization,
1018 Message: fmt.Sprintf(
1019 "data must be hexadecimal string (not %q)",
1020 hexData,
1021 ),
1022 }
1023 }
1024 var msgBlock wire.Block
1025 if e := msgBlock.Deserialize(bytes.NewReader(dataBytes)); E.Chk(e) {
1026 return nil, &btcjson.RPCError{
1027 Code: btcjson.ErrRPCDeserialization,
1028 Message: "block decode failed: " + e.Error(),
1029 }
1030 }
1031 block := block2.NewBlock(&msgBlock)
1032 // Ensure the block is building from the expected previous block.
1033 expectedPrevHash := s.Cfg.Chain.BestSnapshot().Hash
1034 prevHash := &block.WireBlock().Header.PrevBlock
1035 if !expectedPrevHash.IsEqual(prevHash) {
1036 return "bad-prevblk", nil
1037 }
1038 if e := s.Cfg.Chain.CheckConnectBlockTemplate(block); E.Chk(e) {
1039 if _, ok := e.(blockchain.RuleError); !ok {
1040 errStr := fmt.Sprintf("failed to process block proposal: %v", e)
1041 E.Ln(errStr)
1042
1043 return nil, &btcjson.RPCError{
1044 Code: btcjson.ErrRPCVerify,
1045 Message: errStr,
1046 }
1047 }
1048 I.Ln("rejected block proposal:", e)
1049
1050 return ChainErrToGBTErrString(e), nil
1051 }
1052 return nil, nil
1053 }
1054
1055 // HandleGetBlockTemplateRequest is a helper for handleGetBlockTemplate which deals with generating and returning block
1056 // templates to the caller. It handles both long poll requests as specified by BIP 0022 as well as regular requests.
1057 //
1058 // In addition, it detects the capabilities reported by the caller in regards to whether or not it supports creating its
1059 // own coinbase (the coinbasetxn and coinbasevalue capabilities) and modifies the returned block template accordingly.
1060 func HandleGetBlockTemplateRequest(
1061 s *Server,
1062 request *btcjson.TemplateRequest,
1063 closeChan qu.C,
1064 ) (interface{}, error) {
1065 // Extract the relevant passed capabilities and restrict the result to either a coinbase value or a coinbase
1066 // transaction object depending on the request. Default to only providing a coinbase value.
1067 useCoinbaseValue := true
1068 if request != nil {
1069 var hasCoinbaseValue, hasCoinbaseTxn bool
1070 for _, capability := range request.Capabilities {
1071 switch capability {
1072 case "coinbasetxn":
1073 hasCoinbaseTxn = true
1074 case "coinbasevalue":
1075 hasCoinbaseValue = true
1076 }
1077 }
1078 if hasCoinbaseTxn && !hasCoinbaseValue {
1079 useCoinbaseValue = false
1080 }
1081 }
1082 // When a coinbase transaction has been requested, respond with an error if there are no addresses to pay the
1083 // created block template to.
1084 if !useCoinbaseValue && len(s.StateCfg.ActiveMiningAddrs) == 0 {
1085 return nil, &btcjson.RPCError{
1086 Code: btcjson.ErrRPCInternal.Code,
1087 Message: "A coinbase transaction has been requested, " +
1088 "but the Server has not been configured with " +
1089 "any payment addresses via --miningaddr",
1090 }
1091 }
1092 // Return an error if there are no peers connected since there is no way to relay a found block or receive
1093 // transactions to work on. However, allow this workState when running in the regression test or simulation test
1094 // mode.
1095 netwk := (s.Config.Network.V())[0]
1096 if !(netwk == 'r' || netwk == 's') &&
1097 s.Cfg.ConnMgr.ConnectedCount() == 0 {
1098 return nil, &btcjson.RPCError{
1099 Code: btcjson.ErrRPCClientNotConnected,
1100 Message: "Pod is not connected to network",
1101 }
1102 }
1103 // No point in generating or accepting work before the chain is synced.
1104 currentHeight := s.Cfg.Chain.BestSnapshot().Height
1105 if currentHeight != 0 && !s.Cfg.SyncMgr.IsCurrent() {
1106 return nil, &btcjson.RPCError{
1107 Code: btcjson.ErrRPCClientInInitialDownload,
1108 Message: "Pod is not yet synchronised...",
1109 }
1110 }
1111 // When a long poll ID was provided, this is a long poll request by the client to be notified when block template
1112 // referenced by the ID should be replaced with a new one.
1113 if request != nil && request.LongPollID != "" {
1114 return HandleGetBlockTemplateLongPoll(
1115 s, request.LongPollID,
1116 useCoinbaseValue, closeChan,
1117 )
1118 }
1119 // Protect concurrent access when updating block templates.
1120 workState := s.GBTWorkState
1121 workState.Lock()
1122 defer workState.Unlock()
1123 // Get and return a block template. A new block template will be generated when the current best block has changed
1124 // or the transactions in the memory pool have been updated and it has been at least five seconds since the last
1125 // template was generated.
1126 //
1127 // Otherwise, the timestamp for the existing block template is updated (and possibly the difficulty on testnet per
1128 // the consesus rules).
1129 if e := workState.UpdateBlockTemplate(s, useCoinbaseValue); E.Chk(e) {
1130 return nil, e
1131 }
1132 return workState.BlockTemplateResult(useCoinbaseValue, nil)
1133 }
1134
1135 // HandleGetCFilter implements the getcfilter command.
1136 func HandleGetCFilter(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1137 if s.Cfg.CfIndex == nil {
1138 return nil, &btcjson.RPCError{
1139 Code: btcjson.ErrRPCNoCFIndex,
1140 Message: "The CF index must be enabled for this command",
1141 }
1142 }
1143 var msg string
1144 var e error
1145 c, ok := cmd.(*btcjson.GetCFilterCmd)
1146 if !ok {
1147 var h string
1148 h, e = s.HelpCacher.RPCMethodHelp("getfilter")
1149 if e != nil {
1150 msg = e.Error() + "\n\n"
1151 }
1152 msg += h
1153 return nil, &btcjson.RPCError{
1154 Code: btcjson.ErrRPCInvalidParameter,
1155 Message: msg,
1156 // "invalid subcommand for addnode",
1157 }
1158 }
1159 hash, e := chainhash.NewHashFromStr(c.Hash)
1160 if e != nil {
1161 return nil, DecodeHexError(c.Hash)
1162 }
1163 filterBytes, e := s.Cfg.CfIndex.FilterByBlockHash(hash, c.FilterType)
1164 if e != nil {
1165 D.F("could not find committed filter for %v: %v", hash, e)
1166
1167 return nil, &btcjson.RPCError{
1168 Code: btcjson.ErrRPCBlockNotFound,
1169 Message: "block not found",
1170 }
1171 }
1172 T.Ln("found committed filter for", hash)
1173 return hex.EncodeToString(filterBytes), nil
1174 }
1175
1176 // HandleGetCFilterHeader implements the getcfilterheader command.
1177 func HandleGetCFilterHeader(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1178 if s.Cfg.CfIndex == nil {
1179 return nil, &btcjson.RPCError{
1180 Code: btcjson.ErrRPCNoCFIndex,
1181 Message: "The CF index must be enabled for this command",
1182 }
1183 }
1184 var msg string
1185 var e error
1186 c, ok := cmd.(*btcjson.GetCFilterHeaderCmd)
1187 if !ok {
1188 var h string
1189 h, e = s.HelpCacher.RPCMethodHelp("getcfilterheader")
1190 if e != nil {
1191 msg = e.Error() + "\n\n"
1192 }
1193 msg += h
1194 return nil, &btcjson.RPCError{
1195 Code: btcjson.ErrRPCInvalidParameter,
1196 Message: msg,
1197 // "invalid subcommand for addnode",
1198 }
1199 }
1200 hash, e := chainhash.NewHashFromStr(c.Hash)
1201 if e != nil {
1202 return nil, DecodeHexError(c.Hash)
1203 }
1204 headerBytes, e := s.Cfg.CfIndex.FilterHeaderByBlockHash(hash, c.FilterType)
1205 if len(headerBytes) > 0 {
1206 D.Ln("found header of committed filter for", hash)
1207
1208 } else {
1209 D.F(
1210 "could not find header of committed filter for %v: %v",
1211 hash,
1212 e,
1213 )
1214
1215 return nil, &btcjson.RPCError{
1216 Code: btcjson.ErrRPCBlockNotFound,
1217 Message: "Block not found",
1218 }
1219 }
1220
1221 e = hash.SetBytes(headerBytes)
1222 if e != nil {
1223 D.Ln(e)
1224
1225 }
1226 return hash.String(), nil
1227 }
1228
1229 // HandleGetConnectionCount implements the getconnectioncount command.
1230 func HandleGetConnectionCount(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1231 return s.Cfg.ConnMgr.ConnectedCount(), nil
1232 }
1233
1234 // HandleGetCurrentNet implements the getcurrentnet command.
1235 func HandleGetCurrentNet(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1236 return s.Cfg.ChainParams.Net, nil
1237 }
1238
1239 // HandleGetDifficulty implements the getdifficulty command.
1240 // TODO: This command should default to the configured algo for cpu mining
1241 // and take an optional parameter to query by algo
1242 func HandleGetDifficulty(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1243 var msg string
1244 var e error
1245 c, ok := cmd.(*btcjson.GetDifficultyCmd)
1246 if !ok {
1247 var h string
1248 h, e = s.HelpCacher.RPCMethodHelp("getdifficulty")
1249 if e != nil {
1250 msg = e.Error() + "\n\n"
1251 }
1252 msg += h
1253 return nil, &btcjson.RPCError{
1254 Code: btcjson.ErrRPCInvalidParameter,
1255 Message: msg,
1256 // "invalid subcommand for addnode",
1257 }
1258 }
1259 best := s.Cfg.Chain.BestSnapshot()
1260 prev, e := s.Cfg.Chain.BlockByHash(&best.Hash)
1261 if e != nil {
1262 E.Ln("ERROR", e)
1263
1264 }
1265 var algo = prev.WireBlock().Header.Version
1266 if algo != 514 {
1267 algo = 2
1268 }
1269 bestbits := best.Bits
1270 if c.Algo == fork.Scrypt && algo != 514 {
1271 algo = 514
1272 for {
1273 if prev.WireBlock().Header.Version != 514 {
1274 ph := prev.WireBlock().Header.PrevBlock
1275 prev, e = s.Cfg.Chain.BlockByHash(&ph)
1276 if e != nil {
1277 E.Ln("ERROR", e)
1278
1279 }
1280 continue
1281 }
1282 bestbits = prev.WireBlock().Header.Bits
1283 break
1284 }
1285 }
1286 if c.Algo == fork.SHA256d && algo != 2 {
1287 algo = 2
1288 for {
1289 if prev.WireBlock().Header.Version == 514 {
1290 ph := prev.WireBlock().Header.PrevBlock
1291 prev, e = s.Cfg.Chain.BlockByHash(&ph)
1292 if e != nil {
1293 E.Ln("ERROR", e)
1294
1295 }
1296 continue
1297 }
1298 bestbits = prev.WireBlock().Header.Bits
1299 break
1300 }
1301 }
1302 return GetDifficultyRatio(bestbits, s.Cfg.ChainParams, algo), nil
1303 }
1304
1305 // HandleGetGenerate implements the getgenerate command.
1306 func HandleGetGenerate(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) { // cpuminer
1307 _, ok := cmd.(*btcjson.GetGenerateCmd)
1308 if ok {
1309 result := *s.Config.Controller
1310 return &result, nil
1311 }
1312 // generating := s.StateCfg.Miner != nil
1313 // if generating {
1314 // D.Ln("miner is running internally")
1315 // } else {
1316 // D.Ln("miner is not running")
1317 // }
1318 // return nil, nil
1319 // return s.Cfg.CPUMiner.IsMining(), nil
1320 return false, errors.New("command was not a btcjson.GetGenerateCmd")
1321 }
1322
1323 // var startTime = time.Now()
1324
1325 // HandleGetHashesPerSec implements the gethashespersec command.
1326 func HandleGetHashesPerSec(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) { // cpuminer
1327 // return int64(s.,
1328 // Cfg.CPUMiner.HashesPerSecond()), nil
1329 // TODO: finish this - needs generator for momentary rate (ewma)
1330 D.Ln("miner hashes per second - multicast thing TODO")
1331 // simple average for now
1332 return int(s.Cfg.Hashrate.Load()), nil
1333 }
1334
1335 // HandleGetHeaders implements the getheaders command.
1336 //
1337 // NOTE: This is a btcsuite extension originally ported from github.com/decred/dcrd.
1338 func HandleGetHeaders(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1339 var msg string
1340 var e error
1341 c, ok := cmd.(*btcjson.GetHeadersCmd)
1342 if !ok {
1343 var h string
1344 h, e = s.HelpCacher.RPCMethodHelp("getheaders")
1345 if e != nil {
1346 msg = e.Error() + "\n\n"
1347 }
1348 msg += h
1349 return nil, &btcjson.RPCError{
1350 Code: btcjson.ErrRPCInvalidParameter,
1351 Message: msg,
1352 // "invalid subcommand for addnode",
1353 }
1354 }
1355 // Fetch the requested headers from chain while respecting the provided block locators and stop hash.
1356 blockLocators := make([]*chainhash.Hash, len(c.BlockLocators))
1357 for i := range c.BlockLocators {
1358 blockLocator, e := chainhash.NewHashFromStr(c.BlockLocators[i])
1359 if e != nil {
1360 return nil, DecodeHexError(c.BlockLocators[i])
1361 }
1362 blockLocators[i] = blockLocator
1363 }
1364 var hashStop chainhash.Hash
1365 if c.HashStop != "" {
1366 e := chainhash.Decode(&hashStop, c.HashStop)
1367 if e != nil {
1368 return nil, DecodeHexError(c.HashStop)
1369 }
1370 }
1371 headers := s.Cfg.SyncMgr.LocateHeaders(blockLocators, &hashStop)
1372 // Return the serialized block headers as hex-encoded strings.
1373 hexBlockHeaders := make([]string, len(headers))
1374 var buf bytes.Buffer
1375 for i, h := range headers {
1376 e := h.Serialize(&buf)
1377 if e != nil {
1378 return nil, InternalRPCError(
1379 e.Error(),
1380 "Failed to serialize block header",
1381 )
1382 }
1383 hexBlockHeaders[i] = hex.EncodeToString(buf.Bytes())
1384 buf.Reset()
1385 }
1386 return hexBlockHeaders, nil
1387 }
1388
1389 // HandleGetInfo implements the getinfo command. We only return the fields that are not related to wallet functionality.
1390 // TODO: simplify this, break it up
1391 func HandleGetInfo(
1392 s *Server,
1393 cmd interface{},
1394 closeChan qu.C,
1395 ) (ret interface{}, e error) {
1396 var Difficulty, dBlake2b, dBlake14lr, dBlake2s, dKeccak, dScrypt, dSHA256D,
1397 dSkein, dStribog, dX11 float64
1398 var lastbitsScrypt, lastbitsSHA256D uint32
1399 best := s.
1400 Cfg.
1401 Chain.
1402 BestSnapshot()
1403 v := s.Cfg.Chain.Index.LookupNode(&best.Hash)
1404 foundcount, height := 0, best.Height
1405 switch fork.GetCurrent(height) {
1406 case 0:
1407 for foundcount < 9 && height > 0 {
1408 switch fork.GetAlgoName(v.Header().Version, height) {
1409 case fork.SHA256d:
1410 if lastbitsSHA256D == 0 {
1411 foundcount++
1412 lastbitsSHA256D = v.Header().Bits
1413 dSHA256D = GetDifficultyRatio(
1414 lastbitsSHA256D,
1415 s.Cfg.ChainParams, v.Header().Version,
1416 )
1417 }
1418 case fork.Scrypt:
1419 if lastbitsScrypt == 0 {
1420 foundcount++
1421 lastbitsScrypt = v.Header().Bits
1422 dScrypt = GetDifficultyRatio(
1423 lastbitsScrypt,
1424 s.Cfg.ChainParams, v.Header().Version,
1425 )
1426 }
1427 default:
1428 }
1429 v = v.RelativeAncestor(1)
1430 height--
1431 }
1432 switch s.Cfg.Algo {
1433 case fork.SHA256d:
1434 Difficulty = dSHA256D
1435 case fork.Scrypt:
1436 Difficulty = dScrypt
1437 default:
1438 }
1439 ret = &btcjson.InfoChainResult0{
1440 // Version: int32(
1441 // version.Tag,
1442 // 1000000*version.AppMajor +
1443 // 10000*version.AppMinor +
1444 // 100*version.AppPatch,
1445 // ),
1446 ProtocolVersion: int32(MaxProtocolVersion),
1447 Blocks: best.Height,
1448 TimeOffset: int64(s.Cfg.TimeSource.Offset().Seconds()),
1449 Connections: s.Cfg.ConnMgr.ConnectedCount(),
1450 Proxy: s.Config.ProxyAddress.V(),
1451 PowAlgoID: fork.GetAlgoID(s.Cfg.Algo, height),
1452 PowAlgo: s.Cfg.Algo,
1453 Difficulty: Difficulty,
1454 DifficultySHA256D: dSHA256D,
1455 DifficultyScrypt: dScrypt,
1456 TestNet: (s.Config.Network.V())[0] == 't',
1457 RelayFee: s.StateCfg.ActiveMinRelayTxFee.ToDUO(),
1458 }
1459 case 1:
1460 foundcount, height := 0, best.Height
1461 for foundcount < 9 &&
1462 height > fork.List[fork.GetCurrent(height)].ActivationHeight-512 {
1463 switch fork.GetAlgoName(v.Header().Version, height) {
1464 case fork.Scrypt:
1465 if lastbitsScrypt == 0 {
1466 foundcount++
1467 lastbitsScrypt = v.Header().Bits
1468 dScrypt = GetDifficultyRatio(
1469 lastbitsScrypt,
1470 s.Cfg.ChainParams, v.Header().Version,
1471 )
1472 }
1473 case fork.SHA256d:
1474 if lastbitsSHA256D == 0 {
1475 foundcount++
1476 lastbitsSHA256D = v.Header().Bits
1477 dSHA256D = GetDifficultyRatio(
1478 lastbitsSHA256D,
1479 s.Cfg.ChainParams, v.Header().Version,
1480 )
1481 }
1482 default:
1483 }
1484 v = v.RelativeAncestor(1)
1485 height--
1486 }
1487 switch s.Cfg.Algo {
1488 case fork.Scrypt:
1489 Difficulty = dScrypt
1490 case fork.SHA256d:
1491 Difficulty = dSHA256D
1492 default:
1493 }
1494 ret = &btcjson.InfoChainResult{
1495 // Version: int32(
1496 // 1000000*version.AppMajor +
1497 // 10000*version.AppMinor +
1498 // 100*version.AppPatch,
1499 // ),
1500 ProtocolVersion: int32(MaxProtocolVersion),
1501 Blocks: best.Height,
1502 TimeOffset: int64(s.Cfg.TimeSource.Offset().Seconds()),
1503 Connections: s.Cfg.ConnMgr.ConnectedCount(),
1504 Proxy: s.Config.ProxyAddress.V(),
1505 PowAlgoID: fork.GetAlgoID(s.Cfg.Algo, height),
1506 PowAlgo: s.Cfg.Algo,
1507 Difficulty: Difficulty,
1508 DifficultyBlake2b: dBlake2b,
1509 DifficultyBlake14lr: dBlake14lr,
1510 DifficultyBlake2s: dBlake2s,
1511 DifficultyKeccak: dKeccak,
1512 DifficultyScrypt: dScrypt,
1513 DifficultySHA256D: dSHA256D,
1514 DifficultySkein: dSkein,
1515 DifficultyStribog: dStribog,
1516 DifficultyX11: dX11,
1517 TestNet: (s.Config.Network.V())[0] == 't',
1518 RelayFee: s.StateCfg.ActiveMinRelayTxFee.ToDUO(),
1519 }
1520 }
1521 return ret, nil
1522 }
1523
1524 // HandleGetMempoolInfo implements the getmempoolinfo command.
1525 func HandleGetMempoolInfo(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1526 mempoolTxns := s.Cfg.TxMemPool.TxDescs()
1527 var numBytes int64
1528 for _, txD := range mempoolTxns {
1529 numBytes += int64(txD.Tx.MsgTx().SerializeSize())
1530 }
1531 ret := &btcjson.GetMempoolInfoResult{
1532 Size: int64(len(mempoolTxns)),
1533 Bytes: numBytes,
1534 }
1535 return ret, nil
1536 }
1537
1538 // HandleGetMiningInfo implements the getmininginfo command. We only return the fields that are not related to wallet
1539 // functionality. This function returns more information than parallelcoind. TODO: simplify this, break it up
1540 func HandleGetMiningInfo(
1541 s *Server, cmd interface{},
1542 closeChan qu.C,
1543 ) (ret interface{}, e error) {
1544 // cpuminer
1545 // Create a default getnetworkhashps command to use defaults and make use of the existing getnetworkhashps handler.
1546 gnhpsCmd := btcjson.NewGetNetworkHashPSCmd(nil, nil)
1547 networkHashesPerSecIface, e := HandleGetNetworkHashPS(s, gnhpsCmd, closeChan)
1548 if e != nil {
1549 return nil, e
1550 }
1551 networkHashesPerSec, ok := networkHashesPerSecIface.(int64)
1552 if !ok {
1553 return nil, &btcjson.RPCError{
1554 Code: btcjson.ErrRPCInternal.Code,
1555 Message: "networkHashesPerSec is not an int64",
1556 }
1557 }
1558 var Difficulty, dScrypt, dSHA256D float64
1559 var lastbitsScrypt, lastbitsSHA256D uint32
1560 best := s.Cfg.Chain.BestSnapshot()
1561 v := s.Cfg.Chain.Index.LookupNode(&best.Hash)
1562 foundCount, height := 0, best.Height
1563 switch fork.GetCurrent(height) {
1564 case 0:
1565 for foundCount < 2 && height > 0 {
1566 switch fork.GetAlgoName(v.Header().Version, height) {
1567 case fork.SHA256d:
1568 if lastbitsSHA256D == 0 {
1569 foundCount++
1570 lastbitsSHA256D = v.Header().Bits
1571 dSHA256D = GetDifficultyRatio(
1572 lastbitsSHA256D,
1573 s.Cfg.ChainParams, v.Header().Version,
1574 )
1575 }
1576 case fork.Scrypt:
1577 if lastbitsScrypt == 0 {
1578 foundCount++
1579 lastbitsScrypt = v.Header().Bits
1580 dScrypt = GetDifficultyRatio(
1581 lastbitsScrypt,
1582 s.Cfg.ChainParams, v.Header().Version,
1583 )
1584 }
1585 default:
1586 }
1587 v = v.RelativeAncestor(1)
1588 height--
1589 }
1590 switch s.Cfg.Algo {
1591 case fork.SHA256d:
1592 Difficulty = dSHA256D
1593 case fork.Scrypt:
1594 Difficulty = dScrypt
1595 default:
1596 }
1597 D.Ln("missing generate stats in here")
1598 ret = &btcjson.GetMiningInfoResult0{
1599 Blocks: int64(best.Height),
1600 CurrentBlockSize: best.BlockSize,
1601 CurrentBlockWeight: best.BlockWeight,
1602 CurrentBlockTx: best.NumTxns,
1603 PowAlgoID: fork.GetAlgoID(s.Cfg.Algo, height),
1604 PowAlgo: s.Cfg.Algo,
1605 Difficulty: Difficulty,
1606 DifficultySHA256D: dSHA256D,
1607 DifficultyScrypt: dScrypt,
1608 // Generate: s.Cfg.CPUMiner.IsMining(),
1609 // GenProcLimit: s.Cfg.CPUMiner.NumWorkers(),
1610 // HashesPerSec: int64(s.Cfg.CPUMiner.HashesPerSecond()),
1611 NetworkHashPS: networkHashesPerSec,
1612 PooledTx: uint64(s.Cfg.TxMemPool.Count()),
1613 TestNet: (s.Config.Network.V())[0] == 't',
1614 }
1615 case 1:
1616 fc, height := 0, best.Height
1617 for fc < 9 && height > fork.List[fork.GetCurrent(height)].ActivationHeight-512 {
1618 switch fork.GetAlgoName(v.Header().Version, height) {
1619 case fork.Scrypt:
1620 if lastbitsScrypt == 0 {
1621 fc++
1622 lastbitsScrypt = v.Header().Bits
1623 dScrypt = GetDifficultyRatio(
1624 lastbitsScrypt,
1625 s.Cfg.ChainParams, v.Header().Version,
1626 )
1627 }
1628 case fork.SHA256d:
1629 if lastbitsSHA256D == 0 {
1630 fc++
1631 lastbitsSHA256D = v.Header().Bits
1632 dSHA256D = GetDifficultyRatio(
1633 lastbitsSHA256D,
1634 s.Cfg.ChainParams, v.Header().Version,
1635 )
1636 }
1637 default:
1638 }
1639 v = v.RelativeAncestor(1)
1640 height--
1641 }
1642 switch s.Cfg.Algo {
1643 case fork.Scrypt:
1644 Difficulty = dScrypt
1645 case fork.SHA256d:
1646 Difficulty = dSHA256D
1647 default:
1648 }
1649 D.Ln("missing cpu miner stuff in here") // cpuminer
1650 ret = &btcjson.GetMiningInfoResult{
1651 Blocks: int64(best.Height),
1652 CurrentBlockSize: best.BlockSize,
1653 CurrentBlockWeight: best.BlockWeight,
1654 CurrentBlockTx: best.NumTxns,
1655 PowAlgoID: fork.GetAlgoID(s.Cfg.Algo, height),
1656 PowAlgo: s.Cfg.Algo,
1657 Difficulty: Difficulty,
1658 DifficultyScrypt: dScrypt,
1659 DifficultySHA256D: dSHA256D,
1660 NetworkHashPS: networkHashesPerSec,
1661 PooledTx: uint64(s.Cfg.TxMemPool.Count()),
1662 TestNet: (s.Config.Network.V())[0] == 't',
1663 }
1664 }
1665 return ret, nil
1666 }
1667
1668 // HandleGetNetTotals implements the getnettotals command.
1669 func HandleGetNetTotals(
1670 s *Server,
1671 cmd interface{},
1672 closeChan qu.C,
1673 ) (interface{}, error) {
1674 totalBytesRecv, totalBytesSent := s.Cfg.ConnMgr.NetTotals()
1675 reply := &btcjson.GetNetTotalsResult{
1676 TotalBytesRecv: totalBytesRecv,
1677 TotalBytesSent: totalBytesSent,
1678 TimeMillis: time.Now().UTC().UnixNano() / int64(time.Millisecond),
1679 }
1680 return reply, nil
1681 }
1682
1683 // HandleGetNetworkHashPS implements the getnetworkhashps command. This command does not default to the same end block
1684 // as the parallelcoind. TODO: Really this needs to be expanded to show per-algorithm hashrates
1685 func HandleGetNetworkHashPS(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1686 var msg string
1687 var e error
1688 c, ok := cmd.(*btcjson.GetNetworkHashPSCmd)
1689 if !ok {
1690 var h string
1691 h, e = s.HelpCacher.RPCMethodHelp("getnetworkhashps")
1692 if e != nil {
1693 msg = e.Error() + "\n\n"
1694 }
1695 msg += h
1696 return nil, &btcjson.RPCError{
1697 Code: btcjson.ErrRPCInvalidParameter,
1698 Message: msg,
1699 // "invalid subcommand for addnode",
1700 }
1701 }
1702 // Note: All valid error return paths should return an int64. Literal zeros are inferred as int, and won't coerce to
1703 // int64 because the return value is an interface{}.
1704 //
1705 // When the passed height is too high or zero, just return 0 now since we can't reasonably calculate the number of
1706 // network hashes per second from invalid values. When it's negative, use the current best block height.
1707 best := s.Cfg.Chain.BestSnapshot()
1708 endHeight := int32(-1)
1709 if c.Height != nil {
1710 endHeight = int32(*c.Height)
1711 }
1712 if endHeight > best.Height || endHeight == 0 {
1713 return int64(0), nil
1714 }
1715 if endHeight < 0 {
1716 endHeight = best.Height
1717 }
1718 // Calculate the number of blocks per retarget interval based on the chain parameters.
1719 blocksPerRetarget := int32(
1720 s.Cfg.ChainParams.TargetTimespan / s.Cfg.
1721 ChainParams.TargetTimePerBlock,
1722 )
1723 // Calculate the starting block height based on the passed number of blocks.
1724 //
1725 // When the passed value is negative, use the last block the difficulty changed as the starting height. Also make
1726 // sure the starting height is not before the beginning of the chain.
1727 numBlocks := int32(120)
1728 if c.Blocks != nil {
1729 numBlocks = int32(*c.Blocks)
1730 }
1731 var startHeight int32
1732 if numBlocks <= 0 {
1733 startHeight = endHeight - ((endHeight % blocksPerRetarget) + 1)
1734 } else {
1735 startHeight = endHeight - numBlocks
1736 }
1737 if startHeight < 0 {
1738 startHeight = 0
1739 }
1740 T.F(
1741 "calculating network hashes per second from %d to %d",
1742 startHeight,
1743 endHeight,
1744 )
1745
1746 // Find the min and max block timestamps as well as calculate the total amount of work that happened between the
1747 // start and end blocks.
1748 var minTimestamp, maxTimestamp time.Time
1749 totalWork := big.NewInt(0)
1750 for curHeight := startHeight; curHeight <= endHeight; curHeight++ {
1751 hash, e := s.Cfg.Chain.BlockHashByHeight(curHeight)
1752 if e != nil {
1753 context := "Failed to fetch block hash"
1754 return nil, InternalRPCError(e.Error(), context)
1755 }
1756 // Fetch the header from chain.
1757 header, e := s.Cfg.Chain.HeaderByHash(hash)
1758 if e != nil {
1759 context := "Failed to fetch block header"
1760 return nil, InternalRPCError(e.Error(), context)
1761 }
1762 if curHeight == startHeight {
1763 minTimestamp = header.Timestamp
1764 maxTimestamp = minTimestamp
1765 } else {
1766 totalWork.Add(
1767 totalWork, blockchain.CalcWork(
1768 header.Bits,
1769 best.Height+1, header.Version,
1770 ),
1771 )
1772 if minTimestamp.After(header.Timestamp) {
1773 minTimestamp = header.Timestamp
1774 }
1775 if maxTimestamp.Before(header.Timestamp) {
1776 maxTimestamp = header.Timestamp
1777 }
1778 }
1779 }
1780 // Calculate the difference in seconds between the min and max block timestamps and avoid division by zero in the
1781 // case where there is no time difference.
1782 timeDiff := int64(maxTimestamp.Sub(minTimestamp) / time.Second)
1783 if timeDiff == 0 {
1784 return int64(0), nil
1785 }
1786 hashesPerSec := new(big.Int).Div(totalWork, big.NewInt(timeDiff))
1787 return hashesPerSec.Int64(), nil
1788 }
1789
1790 // HandleGetPeerInfo implements the getpeerinfo command.
1791 func HandleGetPeerInfo(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1792 peers := s.Cfg.ConnMgr.ConnectedPeers()
1793 syncPeerID := s.Cfg.SyncMgr.SyncPeerID()
1794 infos := make([]*btcjson.GetPeerInfoResult, 0, len(peers))
1795 for _, p := range peers {
1796 statsSnap := p.ToPeer().StatsSnapshot()
1797 var addr, addrLocal string
1798 if statsSnap.Inbound {
1799 addr =
1800 statsSnap.Addr
1801 addrLocal =
1802 p.ToPeer().LocalAddr().String()
1803 // (*s.Config.P2PConnect)[0]
1804 } else {
1805 addr =
1806 statsSnap.Addr
1807 addrLocal =
1808 // (*s.Config.P2PConnect)[0]
1809 p.ToPeer().LocalAddr().String()
1810 }
1811 info := &btcjson.GetPeerInfoResult{
1812 ID: statsSnap.ID,
1813 Addr: addr,
1814 AddrLocal: addrLocal,
1815 Services: fmt.Sprintf("%08d", uint64(statsSnap.Services)),
1816 RelayTxes: !p.IsTxRelayDisabled(),
1817 LastSend: statsSnap.LastSend.Unix(),
1818 LastRecv: statsSnap.LastRecv.Unix(),
1819 BytesSent: statsSnap.BytesSent,
1820 BytesRecv: statsSnap.BytesRecv,
1821 ConnTime: statsSnap.ConnTime.Unix(),
1822 PingTime: float64(statsSnap.LastPingMicros),
1823 TimeOffset: statsSnap.TimeOffset,
1824 Version: statsSnap.Version,
1825 SubVer: statsSnap.UserAgent,
1826 Inbound: statsSnap.Inbound,
1827 StartingHeight: statsSnap.StartingHeight,
1828 CurrentHeight: statsSnap.LastBlock,
1829 BanScore: int32(p.GetBanScore()),
1830 FeeFilter: p.GetFeeFilter(),
1831 SyncNode: statsSnap.ID == syncPeerID,
1832 }
1833 if p.ToPeer().LastPingNonce() != 0 {
1834 wait := float64(time.Since(statsSnap.LastPingTime).Nanoseconds())
1835 // We actually want microseconds.
1836 info.PingWait = wait / 1000
1837 }
1838 infos = append(infos, info)
1839 }
1840 return infos, nil
1841 }
1842
1843 // HandleGetRawMempool implements the getrawmempool command.
1844 func HandleGetRawMempool(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1845 c := cmd.(*btcjson.GetRawMempoolCmd)
1846 mp := s.Cfg.TxMemPool
1847 if c.Verbose != nil && *c.Verbose {
1848 return mp.RawMempoolVerbose(), nil
1849 }
1850 // The response is simply an array of the transaction hashes if the verbose flag is not set.
1851 descs := mp.TxDescs()
1852 hashStrings := make([]string, len(descs))
1853 for i := range hashStrings {
1854 hashStrings[i] = descs[i].Tx.Hash().String()
1855 }
1856 return hashStrings, nil
1857 }
1858
1859 // HandleGetRawTransaction implements the getrawtransaction command.
1860 func HandleGetRawTransaction(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1861 var msg string
1862 var e error
1863 c, ok := cmd.(*btcjson.GetRawTransactionCmd)
1864 if !ok {
1865 var h string
1866 h, e = s.HelpCacher.RPCMethodHelp("getrawtransaction")
1867 if e != nil {
1868 msg = e.Error() + "\n\n"
1869 }
1870 msg += h
1871 return nil, &btcjson.RPCError{
1872 Code: btcjson.ErrRPCInvalidParameter,
1873 Message: msg,
1874 // "invalid subcommand for addnode",
1875 }
1876 }
1877 // Convert the provided transaction hash hex to a Hash.
1878 txHash, e := chainhash.NewHashFromStr(c.Txid)
1879 if e != nil {
1880 return nil, DecodeHexError(c.Txid)
1881 }
1882 verbose := false
1883 if c.Verbose != nil {
1884 verbose = *c.Verbose != 0
1885 }
1886 // Try to fetch the transaction from the memory pool and if that fails, try the block database.
1887 var mtx *wire.MsgTx
1888 var blkHash *chainhash.Hash
1889 var blkHeight int32
1890 tx, e := s.Cfg.TxMemPool.FetchTransaction(txHash)
1891 if e != nil {
1892 if s.Cfg.TxIndex == nil {
1893 return nil, &btcjson.RPCError{
1894 Code: btcjson.ErrRPCNoTxInfo,
1895 Message: "The transaction index must be " +
1896 "enabled to query the blockchain " +
1897 "(specify --txindex)",
1898 }
1899 }
1900 // Look up the location of the transaction.
1901 var blockRegion *database.BlockRegion
1902 blockRegion, e = s.Cfg.TxIndex.TxBlockRegion(txHash)
1903 if e != nil {
1904 context := "Failed to retrieve transaction location"
1905 return nil, InternalRPCError(e.Error(), context)
1906 }
1907 if blockRegion == nil {
1908 return nil, NoTxInfoError(txHash)
1909 }
1910 // Load the raw transaction bytes from the database.
1911 var txBytes []byte
1912 e = s.Cfg.DB.View(
1913 func(dbTx database.Tx) (e error) {
1914 txBytes, e = dbTx.FetchBlockRegion(blockRegion)
1915 return e
1916 },
1917 )
1918 if e != nil {
1919 return nil, NoTxInfoError(txHash)
1920 }
1921 // When the verbose flag isn't set, simply return the serialized transaction as a hex-encoded string. This is
1922 // done here to avoid deserializing it only to reserialize it again later.
1923 if !verbose {
1924 return hex.EncodeToString(txBytes), nil
1925 }
1926 // Grab the block height.
1927 blkHash = blockRegion.Hash
1928 blkHeight, e = s.Cfg.Chain.BlockHeightByHash(blkHash)
1929 if e != nil {
1930 context := "Failed to retrieve block height"
1931 return nil, InternalRPCError(e.Error(), context)
1932 }
1933 // Deserialize the transaction
1934 var msgTx wire.MsgTx
1935 e = msgTx.Deserialize(bytes.NewReader(txBytes))
1936 if e != nil {
1937 context := deserialfail
1938 return nil, InternalRPCError(e.Error(), context)
1939 }
1940 mtx = &msgTx
1941 } else {
1942 // When the verbose flag isn't set, simply return the network-serialized transaction as a hex-encoded string.
1943 if !verbose {
1944 // Note that this is intentionally not directly returning because the first return value is a string and it
1945 // would result in returning an empty string to the client instead of nothing (nil) in the case of an error.
1946 var mtxHex string
1947 mtxHex, e = MessageToHex(tx.MsgTx())
1948 if e != nil {
1949 return nil, e
1950 }
1951 return mtxHex, nil
1952 }
1953 mtx = tx.MsgTx()
1954 }
1955 // The verbose flag is set, so generate the JSON object and return it.
1956 var blkHeader *wire.BlockHeader
1957 var blkHashStr string
1958 var chainHeight int32
1959 if blkHash != nil {
1960 // Fetch the header from chain.
1961 var header wire.BlockHeader
1962 header, e = s.Cfg.Chain.HeaderByHash(blkHash)
1963 if e != nil {
1964 context := "Failed to fetch block header"
1965 return nil, InternalRPCError(e.Error(), context)
1966 }
1967 blkHeader = &header
1968 blkHashStr = blkHash.String()
1969 chainHeight = s.Cfg.Chain.BestSnapshot().Height
1970 }
1971 rawTxn, e := CreateTxRawResult(
1972 s.Cfg.ChainParams, mtx, txHash.String(),
1973 blkHeader, blkHashStr, blkHeight, chainHeight,
1974 )
1975 if e != nil {
1976 return nil, e
1977 }
1978 return *rawTxn, nil
1979 }
1980
1981 // HandleGetTxOut handles gettxout commands.
1982 func HandleGetTxOut(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
1983 var msg string
1984 var e error
1985 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
1986 c, ok := cmd.(*btcjson.GetTxOutCmd)
1987 if !ok {
1988 var h string
1989 h, e = s.HelpCacher.RPCMethodHelp("gettxout")
1990 if e != nil {
1991 msg = e.Error() + "\n\n"
1992 }
1993 msg += h
1994 return nil, &btcjson.RPCError{
1995 Code: btcjson.ErrRPCInvalidParameter,
1996 Message: msg,
1997 // "invalid subcommand for addnode",
1998 }
1999 }
2000 // Convert the provided transaction hash hex to a Hash.
2001 txHash, e := chainhash.NewHashFromStr(c.Txid)
2002 if e != nil {
2003 return nil, DecodeHexError(c.Txid)
2004 }
2005 // If requested and the tx is available in the mempool try to fetch it from there, otherwise attempt to fetch from
2006 // the block database.
2007 var bestBlockHash string
2008 var confirmations int32
2009 var value int64
2010 var pkScript []byte
2011 var isCoinbase bool
2012 includeMempool := true
2013 if c.IncludeMempool != nil {
2014 includeMempool = *c.IncludeMempool
2015 }
2016 // TODO: This is racy. It should attempt to fetch it directly and check the error.
2017 if includeMempool && s.Cfg.TxMemPool.HaveTransaction(txHash) {
2018 tx, e := s.Cfg.TxMemPool.FetchTransaction(txHash)
2019 if e != nil {
2020 return nil, NoTxInfoError(txHash)
2021 }
2022 mtx := tx.MsgTx()
2023 if c.Vout > uint32(len(mtx.TxOut)-1) {
2024 return nil, &btcjson.RPCError{
2025 Code: btcjson.ErrRPCInvalidTxVout,
2026 Message: "Output index number (vout) does not " +
2027 "exist for transaction.",
2028 }
2029 }
2030 txOut := mtx.TxOut[c.Vout]
2031 if txOut == nil {
2032 errStr := fmt.Sprintf(
2033 "Output index: %d for txid: %s "+
2034 "does not exist", c.Vout, txHash,
2035 )
2036 return nil, InternalRPCError(errStr, "")
2037 }
2038 best := s.Cfg.Chain.BestSnapshot()
2039 bestBlockHash = best.Hash.String()
2040 confirmations = 0
2041 value = txOut.Value
2042 pkScript = txOut.PkScript
2043 isCoinbase = blockchain.IsCoinBaseTx(mtx)
2044 } else {
2045 out := wire.OutPoint{Hash: *txHash, Index: c.Vout}
2046 entry, e := s.Cfg.Chain.FetchUtxoEntry(out)
2047 if e != nil {
2048 return nil, NoTxInfoError(txHash)
2049 }
2050 // To match the behavior of the reference client, return nil (JSON null) if the transaction output is spent by
2051 // another transaction already in the main chain. Mined transactions that are spent by a mempool transaction are
2052 // not affected by this.
2053 if entry == nil || entry.IsSpent() {
2054 return nil, nil
2055 }
2056 best := s.Cfg.Chain.BestSnapshot()
2057 bestBlockHash = best.Hash.String()
2058 confirmations = 1 + best.Height - entry.BlockHeight()
2059 value = entry.Amount()
2060 pkScript = entry.PkScript()
2061 isCoinbase = entry.IsCoinBase()
2062 }
2063 // Disassemble script into single line printable format. The disassembled string will contain [error] inline if the
2064 // script doesn't fully parse, so ignore the error here.
2065 disbuf, _ := txscript.DisasmString(pkScript)
2066 // Get further info about the script. Ignore the error here since an error means the script couldn't parse and there
2067 // is no additional information about it anyways.
2068 scriptClass, addrs, reqSigs, _ := txscript.ExtractPkScriptAddrs(pkScript, s.Cfg.ChainParams)
2069 addresses := make([]string, len(addrs))
2070 for i, addr := range addrs {
2071 addresses[i] = addr.EncodeAddress()
2072 }
2073 txOutReply := &btcjson.GetTxOutResult{
2074 BestBlock: bestBlockHash,
2075 Confirmations: int64(confirmations),
2076 Value: amt.Amount(value).ToDUO(),
2077 ScriptPubKey: btcjson.ScriptPubKeyResult{
2078 Asm: disbuf,
2079 Hex: hex.EncodeToString(pkScript),
2080 ReqSigs: int32(reqSigs),
2081 Type: scriptClass.String(),
2082 Addresses: addresses,
2083 },
2084 Coinbase: isCoinbase,
2085 }
2086 return txOutReply, nil
2087 }
2088
2089 // HandleHelp implements the help command.
2090 func HandleHelp(s *Server, cmd interface{}, closeChan qu.C) (
2091 interface{}, error,
2092 ) {
2093 var msg string
2094 var e error
2095 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2096 c, ok := cmd.(*btcjson.HelpCmd)
2097 if !ok {
2098 var h string
2099 h, e = s.HelpCacher.RPCUsage(true)
2100 if e != nil {
2101 msg = e.Error() + "\n"
2102 }
2103 msg += h
2104 return nil, &btcjson.RPCError{
2105 Code: btcjson.ErrRPCInvalidParameter,
2106 Message: msg,
2107 // "invalid subcommand for addnode",
2108 }
2109 }
2110 // Provide a usage overview of all commands when no specific command was specified.
2111 var command string
2112 if c.Command != nil {
2113 command = *c.Command
2114 }
2115 if command == "" {
2116 var usage string
2117 usage, e = s.HelpCacher.RPCUsage(false)
2118 if e != nil {
2119 context := "Failed to generate RPC usage"
2120 return nil, InternalRPCError(e.Error(), context)
2121 }
2122 return usage, nil
2123 }
2124 // Chk that the command asked for is supported and implemented. Only search the main list of handlers since help
2125 // should not be provided for commands that are unimplemented or related to wallet functionality.
2126 if _, ok := RPCHandlers[command]; !ok {
2127 return nil, &btcjson.RPCError{
2128 Code: btcjson.ErrRPCInvalidParameter,
2129 Message: "Unknown command: " + command,
2130 }
2131 }
2132 // Get the help for the command.
2133 help, e := s.HelpCacher.RPCMethodHelp(command)
2134 if e != nil {
2135 context := "Failed to generate help"
2136 return nil, InternalRPCError(e.Error(), context)
2137 }
2138 return help, nil
2139 }
2140
2141 // HandleNode handles node commands.
2142 func HandleNode(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2143 var msg string
2144 var e error
2145 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2146 c, ok := cmd.(*btcjson.NodeCmd)
2147 if !ok {
2148 var h string
2149 h, e = s.HelpCacher.RPCMethodHelp("help")
2150 if e != nil {
2151 msg = e.Error() + "\n\n"
2152 }
2153 msg += h
2154 return nil, &btcjson.RPCError{
2155 Code: btcjson.ErrRPCInvalidParameter,
2156 Message: msg,
2157 // "invalid subcommand for addnode",
2158 }
2159 }
2160 var addr string
2161 var nodeID uint64
2162 var errN error
2163 params := s.Cfg.ChainParams
2164 switch c.SubCmd {
2165 case "disconnect":
2166 // If we have a valid uint disconnect by node id. Otherwise, attempt to disconnect by address, returning an
2167 // error if a valid IP address is not supplied.
2168 if nodeID, errN = strconv.ParseUint(c.Target, 10, 32); errN == nil {
2169 e = s.Cfg.ConnMgr.DisconnectByID(int32(nodeID))
2170 } else {
2171 if _, _, errP := net.SplitHostPort(c.Target); errP == nil || net.ParseIP(c.Target) != nil {
2172 addr = NormalizeAddress(c.Target, params.DefaultPort)
2173 e = s.Cfg.ConnMgr.DisconnectByAddr(addr)
2174 } else {
2175 return nil, &btcjson.RPCError{
2176 Code: btcjson.ErrRPCInvalidParameter,
2177 Message: "invalid address or node ID",
2178 }
2179 }
2180 }
2181 if e != nil && PeerExists(s.Cfg.ConnMgr, addr, int32(nodeID)) {
2182 return nil, &btcjson.RPCError{
2183 Code: btcjson.ErrRPCMisc,
2184 Message: "can't disconnect a permanent peer, use remove",
2185 }
2186 }
2187 case "remove":
2188 // If we have a valid uint disconnect by node id. Otherwise, attempt to disconnect by address, returning an
2189 // error if a valid IP address is not supplied.
2190 if nodeID, errN = strconv.ParseUint(c.Target, 10, 32); errN == nil {
2191 e = s.Cfg.ConnMgr.RemoveByID(int32(nodeID))
2192 } else {
2193 if _, _, errP := net.SplitHostPort(c.Target); errP == nil || net.ParseIP(c.Target) != nil {
2194 addr = NormalizeAddress(c.Target, params.DefaultPort)
2195 e = s.Cfg.ConnMgr.RemoveByAddr(addr)
2196 } else {
2197 return nil, &btcjson.RPCError{
2198 Code: btcjson.ErrRPCInvalidParameter,
2199 Message: "invalid address or node ID",
2200 }
2201 }
2202 }
2203 if e != nil && PeerExists(s.Cfg.ConnMgr, addr, int32(nodeID)) {
2204 return nil, &btcjson.RPCError{
2205 Code: btcjson.ErrRPCMisc,
2206 Message: "can't remove a temporary peer, use disconnect",
2207 }
2208 }
2209 case "connect":
2210 addr = NormalizeAddress(c.Target, params.DefaultPort)
2211 // Default to temporary connections.
2212 subCmd := "temp"
2213 if c.ConnectSubCmd != nil {
2214 subCmd = *c.ConnectSubCmd
2215 }
2216 switch subCmd {
2217 case "perm", "temp":
2218 e = s.Cfg.ConnMgr.Connect(addr, subCmd == "perm")
2219 default:
2220 return nil, &btcjson.RPCError{
2221 Code: btcjson.ErrRPCInvalidParameter,
2222 Message: "invalid subcommand for node connect",
2223 }
2224 }
2225 default:
2226 return nil, &btcjson.RPCError{
2227 Code: btcjson.ErrRPCInvalidParameter,
2228 Message: "invalid subcommand for node",
2229 }
2230 }
2231 if e != nil {
2232 return nil, &btcjson.RPCError{
2233 Code: btcjson.ErrRPCInvalidParameter,
2234 Message: e.Error(),
2235 }
2236 }
2237 // no data returned unless an error.
2238 return nil, nil
2239 }
2240
2241 // HandlePing implements the ping command.
2242 func HandlePing(s *Server, cmd interface{}, closeChan qu.C) (
2243 interface{}, error,
2244 ) {
2245 // Ask Server to ping \o_
2246 nonce, e := wire.RandomUint64()
2247 if e != nil {
2248 return nil, InternalRPCError(
2249 "Not sending ping - failed to generate nonce: "+e.Error(), "",
2250 )
2251 }
2252 s.Cfg.ConnMgr.BroadcastMessage(wire.NewMsgPing(nonce))
2253 return nil, nil
2254 }
2255
2256 // HandleSearchRawTransactions implements the searchrawtransactions command.
2257 // TODO: simplify this, break it up
2258 func HandleSearchRawTransactions(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2259 // Respond with an error if the address index is not enabled.
2260 addrIndex := s.Cfg.AddrIndex
2261 if addrIndex == nil {
2262 return nil, &btcjson.RPCError{
2263 Code: btcjson.ErrRPCMisc,
2264 Message: "Address index must be enabled (--addrindex)",
2265 }
2266 }
2267 // Override the flag for including extra previous output information in each input if needed.
2268 c := cmd.(*btcjson.SearchRawTransactionsCmd)
2269 vinExtra := false
2270 if c.VinExtra != nil {
2271 vinExtra = *c.VinExtra != 0
2272 }
2273 // Including the extra previous output information requires the transaction index. Currently the address index
2274 // relies on the transaction index, so this check is redundant, but it's better to be safe in case the address index
2275 // is ever changed to not rely on it.
2276 if vinExtra && s.Cfg.TxIndex == nil {
2277 return nil, &btcjson.RPCError{
2278 Code: btcjson.ErrRPCMisc,
2279 Message: "Transaction index must be enabled (--txindex)",
2280 }
2281 }
2282 // Attempt to decode the supplied address.
2283 params := s.Cfg.ChainParams
2284 addr, e := btcaddr.Decode(c.Address, params)
2285 if e != nil {
2286 return nil, &btcjson.RPCError{
2287 Code: btcjson.ErrRPCInvalidAddressOrKey,
2288 Message: "Invalid address or key: " + e.Error(),
2289 }
2290 }
2291 // Override the default number of requested entries if needed. Also, just return now if the number of requested
2292 // entries is zero to avoid extra work.
2293 numRequested := 100
2294 if c.Count != nil {
2295 numRequested = *c.Count
2296 if numRequested < 0 {
2297 numRequested = 1
2298 }
2299 }
2300 if numRequested == 0 {
2301 return nil, nil
2302 }
2303 // Override the default number of entries to skip if needed.
2304 var numToSkip int
2305 if c.Skip != nil {
2306 numToSkip = *c.Skip
2307 if numToSkip < 0 {
2308 numToSkip = 0
2309 }
2310 }
2311 // Override the reverse flag if needed.
2312 var reverse bool
2313 if c.Reverse != nil {
2314 reverse = *c.Reverse
2315 }
2316 // Add transactions from mempool first if client asked for reverse order. Otherwise, they will be added last (as
2317 // needed depending on the requested counts). NOTE: This code doesn't txsort by dependency. This might be something to
2318 // do in the future for the client's convenience, or leave it to the client.
2319 numSkipped := uint32(0)
2320 addressTxns := make([]RetrievedTx, 0, numRequested)
2321 if reverse {
2322 // Transactions in the mempool are not in a block header yet, so the block header field in the retrieved
2323 // transaction struct is left nil.
2324 mpTxns, mpSkipped := FetchMempoolTxnsForAddress(
2325 s, addr,
2326 uint32(numToSkip), uint32(numRequested),
2327 )
2328 numSkipped += mpSkipped
2329 for _, tx := range mpTxns {
2330 addressTxns = append(addressTxns, RetrievedTx{Tx: tx})
2331 }
2332 }
2333 // Fetch transactions from the database in the desired order if more are needed.
2334 if len(addressTxns) < numRequested {
2335 e = s.Cfg.DB.View(
2336 func(dbTx database.Tx) (e error) {
2337 regions, dbSkipped, e := addrIndex.TxRegionsForAddress(
2338 dbTx, addr,
2339 uint32(numToSkip)-numSkipped, uint32(numRequested-len(addressTxns)),
2340 reverse,
2341 )
2342 if e != nil {
2343 return e
2344 }
2345 // Load the raw transaction bytes from the database.
2346 serializedTxns, e := dbTx.FetchBlockRegions(regions)
2347 if e != nil {
2348 return e
2349 }
2350 // Add the transaction and the hash of the block it is contained in to the list. Note that the transaction
2351 // is left serialized here since the caller might have requested non-verbose output and hence there would
2352 // be/ no point in deserializing it just to reserialize it later.
2353 for i, serializedTx := range serializedTxns {
2354 addressTxns = append(
2355 addressTxns, RetrievedTx{
2356 TxBytes: serializedTx,
2357 BlkHash: regions[i].Hash,
2358 },
2359 )
2360 }
2361 numSkipped += dbSkipped
2362 return nil
2363 },
2364 )
2365 if e != nil {
2366 context := "Failed to load address index entries"
2367 return nil, InternalRPCError(e.Error(), context)
2368 }
2369 }
2370 // Add transactions from mempool last if client did not request reverse order and the number of results is still
2371 // under the number requested.
2372 if !reverse && len(addressTxns) < numRequested {
2373 // Transactions in the mempool are not in a block header yet, so the block header field in the retrieved
2374 // transaction struct is left nil.
2375 mpTxns, mpSkipped := FetchMempoolTxnsForAddress(
2376 s, addr,
2377 uint32(numToSkip)-numSkipped, uint32(numRequested-len(addressTxns)),
2378 )
2379 numSkipped += mpSkipped
2380 for _, tx := range mpTxns {
2381 addressTxns = append(addressTxns, RetrievedTx{Tx: tx})
2382 }
2383 }
2384 // Address has never been used if neither source yielded any results.
2385 if len(addressTxns) == 0 {
2386 return nil, &btcjson.RPCError{
2387 Code: btcjson.ErrRPCNoTxInfo,
2388 Message: "No information available about address",
2389 }
2390 }
2391 // Serialize all of the transactions to hex.
2392 hexTxns := make([]string, len(addressTxns))
2393 for i := range addressTxns {
2394 // Simply encode the raw bytes to hex when the retrieved transaction is already in serialized form.
2395 rtx := &addressTxns[i]
2396 if rtx.TxBytes != nil {
2397 hexTxns[i] = hex.EncodeToString(rtx.TxBytes)
2398 continue
2399 }
2400 // Serialize the transaction first and convert to hex when the retrieved transaction is the deserialized
2401 // structure.
2402 hexTxns[i], e = MessageToHex(rtx.Tx.MsgTx())
2403 if e != nil {
2404 return nil, e
2405 }
2406 }
2407 // When not in verbose mode, simply return a list of serialized txns.
2408 if c.Verbose != nil && *c.Verbose == 0 {
2409 return hexTxns, nil
2410 }
2411 // Normalize the provided filter addresses (if any) to ensure there are no duplicates.
2412 filterAddrMap := make(map[string]struct{})
2413 if c.FilterAddrs != nil && len(*c.FilterAddrs) > 0 {
2414 for _, addr := range *c.FilterAddrs {
2415 filterAddrMap[addr] = struct{}{}
2416 }
2417 }
2418 // The verbose flag is set, so generate the JSON object and return it.
2419 best := s.Cfg.Chain.BestSnapshot()
2420 srtList := make([]btcjson.SearchRawTransactionsResult, len(addressTxns))
2421 for i := range addressTxns {
2422 // The deserialized transaction is needed, so deserialize the retrieved transaction if it's in serialized form
2423 // (which will be the case when it was lookup up from the database). Otherwise, use the existing deserialized
2424 // transaction.
2425 var rtx *RetrievedTx
2426 rtx = &addressTxns[i]
2427 var mtx *wire.MsgTx
2428 if rtx.Tx == nil {
2429 // Deserialize the transaction.
2430 mtx = new(wire.MsgTx)
2431 e = mtx.Deserialize(bytes.NewReader(rtx.TxBytes))
2432 if e != nil {
2433 context := deserialfail
2434 return nil, InternalRPCError(e.Error(), context)
2435 }
2436 } else {
2437 mtx = rtx.Tx.MsgTx()
2438 }
2439 result := &srtList[i]
2440 result.Hex = hexTxns[i]
2441 result.TxID = mtx.TxHash().String()
2442 result.Vin, e = CreateVinListPrevOut(
2443 s, mtx, params, vinExtra,
2444 filterAddrMap,
2445 )
2446 if e != nil {
2447 return nil, e
2448 }
2449 result.VOut = CreateVoutList(mtx, params, filterAddrMap)
2450 result.Version = mtx.Version
2451 result.LockTime = mtx.LockTime
2452 // Transactions grabbed from the mempool aren't yet in a block, so conditionally fetch block details here. This
2453 // will be reflected in the final JSON output (mempool won't have confirmations or block information).
2454 var blkHeader *wire.BlockHeader
2455 var blkHashStr string
2456 var blkHeight int32
2457 if blkHash := rtx.BlkHash; blkHash != nil {
2458 // Fetch the header from chain.
2459 header, e := s.Cfg.Chain.HeaderByHash(blkHash)
2460 if e != nil {
2461 return nil, &btcjson.RPCError{
2462 Code: btcjson.ErrRPCBlockNotFound,
2463 Message: "Block not found",
2464 }
2465 }
2466 // Get the block height from chain.
2467 height, e := s.Cfg.Chain.BlockHeightByHash(blkHash)
2468 if e != nil {
2469 context := blockheightfail
2470 return nil, InternalRPCError(e.Error(), context)
2471 }
2472 blkHeader = &header
2473 blkHashStr = blkHash.String()
2474 blkHeight = height
2475 }
2476 // Add the block information to the result if there is any.
2477 if blkHeader != nil {
2478 // This is not a typo, they are identical in Bitcoin Core as well.
2479 result.Time = blkHeader.Timestamp.Unix()
2480 result.Blocktime = blkHeader.Timestamp.Unix()
2481 result.BlockHash = blkHashStr
2482 result.Confirmations = uint64(1 + best.Height - blkHeight)
2483 }
2484 }
2485 return srtList, nil
2486 }
2487
2488 // HandleSendRawTransaction implements the sendrawtransaction command.
2489 func HandleSendRawTransaction(
2490 s *Server,
2491 cmd interface{},
2492 closeChan qu.C,
2493 ) (interface{}, error) {
2494 var msg string
2495 var e error
2496 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2497 c, ok := cmd.(*btcjson.SendRawTransactionCmd)
2498 if !ok {
2499 var h string
2500 h, e = s.HelpCacher.RPCMethodHelp("sendrawtransaction")
2501 if e != nil {
2502 msg = e.Error() + "\n\n"
2503 }
2504 msg += h
2505 return nil, &btcjson.RPCError{
2506 Code: btcjson.ErrRPCInvalidParameter,
2507 Message: msg,
2508 // "invalid subcommand for addnode",
2509 }
2510 }
2511 // Deserialize and send off to tx relay
2512 hexStr := c.HexTx
2513 if len(hexStr)%2 != 0 {
2514 hexStr = "0" + hexStr
2515 }
2516 serializedTx, e := hex.DecodeString(hexStr)
2517 if e != nil {
2518 return nil, DecodeHexError(hexStr)
2519 }
2520 var msgTx wire.MsgTx
2521 e = msgTx.Deserialize(bytes.NewReader(serializedTx))
2522 if e != nil {
2523 return nil, &btcjson.RPCError{
2524 Code: btcjson.ErrRPCDeserialization,
2525 Message: "TX decode failed: " + e.Error(),
2526 }
2527 }
2528 // Use 0 for the tag to represent local node.
2529 tx := util.NewTx(&msgTx)
2530 acceptedTxs, e := s.Cfg.TxMemPool.ProcessTransaction(s.Cfg.Chain, tx, false, false, 0)
2531 if e != nil {
2532 // When the error is a rule error, it means the transaction was simply rejected as opposed to something actually
2533 // going wrong, so log such. Otherwise, something really did go wrong, so log an actual error. In both cases, a
2534 // JSON-RPC error is returned to the client with the deserialization error code (to match bitcoind behavior).
2535 if _, ok := e.(mempool.RuleError); ok {
2536 D.F("rejected transaction %v: %v", tx.Hash(), e)
2537
2538 } else {
2539 E.F(
2540 "failed to process transaction %v: %v", tx.Hash(), e,
2541 )
2542 }
2543 return nil, &btcjson.RPCError{
2544 Code: btcjson.ErrRPCDeserialization,
2545 Message: "TX rejected: " + e.Error(),
2546 }
2547 }
2548 // When the transaction was accepted it should be the first item in the returned array of accepted transactions.
2549 //
2550 // The only way this will not be true is if the API for ProcessTransaction changes and this code is not properly
2551 // updated, but ensure the condition holds as a safeguard.
2552 //
2553 // Also, since an error is being returned to the caller, ensure the transaction is removed from the memory pool.
2554 if len(acceptedTxs) == 0 || !acceptedTxs[0].Tx.Hash().IsEqual(tx.Hash()) {
2555 s.Cfg.TxMemPool.RemoveTransaction(tx, true)
2556 errStr := fmt.Sprintf("transaction %v is not in accepted list", tx.Hash())
2557 return nil, InternalRPCError(errStr, "")
2558 }
2559 // Generate and relay inventory vectors for all newly accepted transactions into the memory pool due to the original
2560 // being accepted.
2561 s.Cfg.ConnMgr.RelayTransactions(acceptedTxs)
2562 // Notify both websocket and getblocktemplate long poll clients of all newly accepted transactions.
2563 s.NotifyNewTransactions(acceptedTxs)
2564 // Keep track of all the sendrawtransaction request txns so that they can be rebroadcast if they don't make their
2565 // way into a block.
2566 txD := acceptedTxs[0]
2567 iv := wire.NewInvVect(wire.InvTypeTx, txD.Tx.Hash())
2568 s.Cfg.ConnMgr.AddRebroadcastInventory(iv, txD)
2569 return tx.Hash().String(), nil
2570 }
2571
2572 // HandleSetGenerate implements the setgenerate command.
2573 func HandleSetGenerate(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) { // cpuminer
2574 c, ok := cmd.(*btcjson.SetGenerateCmd)
2575 if ok {
2576 if c.Generate {
2577 s.Cfg.StartController.Signal()
2578 } else {
2579 s.Cfg.StopController.Signal()
2580 }
2581 return &struct{}{}, nil
2582 }
2583 return nil, errors.New("command was not a btcjson.SetGenerateCmd")
2584 // var msg string
2585 // var e error
2586 // // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2587 // c, ok := cmd.(*btcjson.SetGenerateCmd)
2588 // if !ok {
2589 // var h string
2590 // h, e = s.HelpCacher.RPCMethodHelp("setgenerate")
2591 // if e != nil {
2592 // msg = err.E.Ln() + "\n\n"
2593 // }
2594 // msg += h
2595 // return nil, &btcjson.RPCError{
2596 // Code: btcjson.ErrRPCInvalidParameter,
2597 // Message: msg,
2598 // // "invalid subcommand for addnode",
2599 // }
2600 // }
2601 // D.S(c)
2602 // // Disable generation regardless of the provided generate flag if the maximum number of threads (goroutines for our
2603 // // purposes) is 0. Otherwise enable or disable it depending on the provided flag. l.ScriptError(*c.GenProcLimit,
2604 // // c.Generate)
2605 // generate := c.Generate
2606 // genProcLimit := *s.Config.GenThreads
2607 // if c.GenProcLimit != nil {
2608 // genProcLimit = *c.GenProcLimit
2609 // if !generate {
2610 // *c.GenProcLimit = 0
2611 // }
2612 // if *c.GenProcLimit == 0 {
2613 // generate = false
2614 // }
2615 // }
2616 // D.Ln("generating", generate, "threads", genProcLimit)
2617 // // if s.Cfg.CPUMiner.IsMining() {
2618 // // // if s.cfg.CPUMiner.GetAlgo() != s.cfg.Algo {
2619 // // s.Cfg.CPUMiner.Stop()
2620 // // generate = true
2621 // // // }
2622 // // }
2623 // // if !generate {
2624 // // s.Cfg.CPUMiner.Stop()
2625 // // } else {
2626 // // // Respond with an error if there are no addresses to pay the created
2627 // // // blocks to.
2628 // // if len(s.StateCfg.ActiveMiningAddrs) == 0 {
2629 // // return nil, &btcjson.RPCError{
2630 // // Code: btcjson.ErrRPCInternal.Code,
2631 // // Message: "no payment addresses specified via --miningaddr",
2632 // // }
2633 // // }
2634 // // // It's safe to call start even if it's already started.
2635 // // s.Cfg.CPUMiner.SetNumWorkers(int32(genProcLimit))
2636 // // s.Cfg.CPUMiner.Start()
2637 // // }
2638 // //*s.Config.Generate = generate
2639 // //*s.Config.GenThreads = genProcLimit
2640 // //if s.StateCfg.Miner != nil {
2641 // // D.Ln("stopping existing miner")
2642 // // consume.Kill(s.StateCfg.Miner)
2643 // // s.StateCfg.Miner = nil
2644 // //}
2645 // D.Ln("saving configuration")
2646 // save.Pod(s.Config)
2647 // //if *s.Config.Generate && *s.Config.GenThreads != 0 {
2648 // // D.Ln("starting miner")
2649 // // args := []string{os.Args[0], "-D", *s.Config.DataDir}
2650 // // if *s.Config.KopachGUI {
2651 // // args = append(args, "--kopachgui")
2652 // // }
2653 // // args = append(args, "kopach")
2654 // // // args = apputil.PrependForWindows(args)
2655 // // s.StateCfg.Miner = consume.Log(s.Quit, func(ent *log.Entry) (e error) {
2656 // // D.Ln(ent.Level, ent.Time, ent.Text, ent.CodeLocation)
2657 // // return
2658 // // }, func(pkg string) (out bool) {
2659 // // return false
2660 // // }, args...)
2661 // // consume.Start(s.StateCfg.Miner)
2662 // //} else {
2663 // // consume.Kill(s.StateCfg.Miner)
2664 // //}
2665 // return nil, nil
2666 }
2667
2668 // HandleStop implements the stop command.
2669 func HandleStop(s *Server, cmd interface{}, closeChan qu.C) (
2670 interface{}, error,
2671 ) {
2672 interrupt.Request()
2673 return nil, nil
2674 }
2675
2676 // HandleRestart implements the restart command.
2677 func HandleRestart(s *Server, cmd interface{}, closeChan qu.C) (
2678 interface{}, error,
2679 ) {
2680 // select {
2681 // case s.RequestProcessShutdown <- struct{}{}:
2682 // default:
2683 // }
2684 interrupt.RequestRestart()
2685 return nil, nil
2686 }
2687
2688 // HandleSubmitBlock implements the submitblock command.
2689 func HandleSubmitBlock(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2690 var msg string
2691 var e error
2692 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2693 c, ok := cmd.(*btcjson.SubmitBlockCmd)
2694 if !ok {
2695 var h string
2696 h, e = s.HelpCacher.RPCMethodHelp("submitblock")
2697 if e != nil {
2698 msg = e.Error() + "\n\n"
2699 }
2700 msg += h
2701 return nil, &btcjson.RPCError{
2702 Code: btcjson.ErrRPCInvalidParameter,
2703 Message: msg,
2704 // "invalid subcommand for addnode",
2705 }
2706 }
2707 // Deserialize the submitted block.
2708 hexStr := c.HexBlock
2709 if len(hexStr)%2 != 0 {
2710 hexStr = "0" + c.HexBlock
2711 }
2712 serializedBlock, e := hex.DecodeString(hexStr)
2713 if e != nil {
2714 return nil, DecodeHexError(hexStr)
2715 }
2716 block, e := block2.NewFromBytes(serializedBlock)
2717 if e != nil {
2718 return nil, &btcjson.RPCError{
2719 Code: btcjson.ErrRPCDeserialization,
2720 Message: "Block decode failed: " + e.Error(),
2721 }
2722 }
2723 // Process this block using the same rules as blocks coming from other nodes. This will in turn relay it to the
2724 // network like normal.
2725 _, e = s.Cfg.SyncMgr.SubmitBlock(block, blockchain.BFNone)
2726 if e != nil {
2727 return fmt.Sprintf("rejected: %s", e.Error()), nil
2728 }
2729 I.F(
2730 "accepted block %s via submitblock", block.Hash(),
2731 )
2732
2733 return nil, nil
2734 }
2735
2736 // HandleUnimplemented is the handler for commands that should ultimately be supported but are not yet implemented.
2737 func HandleUnimplemented(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2738 return nil, ErrRPCUnimplemented
2739 }
2740
2741 // HandleUptime implements the uptime command.
2742 func HandleUptime(s *Server, cmd interface{}, closeChan qu.C) (
2743 interface{}, error,
2744 ) {
2745 return time.Now().Unix() - s.Cfg.StartupTime, nil
2746 }
2747
2748 // HandleValidateAddress implements the validateaddress command.
2749 func HandleValidateAddress(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2750 var msg string
2751 var e error
2752 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2753 c, ok := cmd.(*btcjson.ValidateAddressCmd)
2754 if !ok {
2755 var h string
2756 h, e = s.HelpCacher.RPCMethodHelp("validateaddress")
2757 if e != nil {
2758 msg = e.Error() + "\n\n"
2759 }
2760 msg += h
2761 return nil, &btcjson.RPCError{
2762 Code: btcjson.ErrRPCInvalidParameter,
2763 Message: msg,
2764 // "invalid subcommand for addnode",
2765 }
2766 }
2767 result := btcjson.ValidateAddressChainResult{}
2768 addr, e := btcaddr.Decode(c.Address, s.Cfg.ChainParams)
2769 if e != nil {
2770 // Return the default value (false) for IsValid.
2771 return result, nil
2772 }
2773 result.Address = addr.EncodeAddress()
2774 result.IsValid = true
2775 return result, nil
2776 }
2777
2778 // HandleVerifyChain implements the verifychain command.
2779 func HandleVerifyChain(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2780 var msg string
2781 var e error
2782 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2783 c, ok := cmd.(*btcjson.VerifyChainCmd)
2784 if !ok {
2785 var h string
2786 h, e = s.HelpCacher.RPCMethodHelp("verifychain")
2787 if e != nil {
2788 msg = e.Error() + "\n\n"
2789 }
2790 msg += h
2791 return nil, &btcjson.RPCError{
2792 Code: btcjson.ErrRPCInvalidParameter,
2793 Message: msg,
2794 // "invalid subcommand for addnode",
2795 }
2796 }
2797 var checkLevel, checkDepth int32
2798 if c.CheckLevel != nil {
2799 checkLevel = *c.CheckLevel
2800 }
2801 if c.CheckDepth != nil {
2802 checkDepth = *c.CheckDepth
2803 }
2804 e = VerifyChain(s, checkLevel, checkDepth)
2805 return e == nil, nil
2806 }
2807
2808 // HandleResetChain deletes the existing chain database and restarts
2809 func HandleResetChain(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2810 // dbName := blockdb.NamePrefix + "_" + *s.Config.DbType
2811 // if *s.Config.DbType == "sqlite" {
2812 // dbName += ".db"
2813 // }
2814 // dbPath := filepath.Join(filepath.Join(*s.Config.DataDir, s.Cfg.ChainParams.Name), dbName)
2815 // select {
2816 // case s.RequestProcessShutdown <- struct{}{}:
2817 // default:
2818 // }
2819 // defer interrupt.RequestRestart()
2820 // os.RemoveAll(dbPath)
2821 return nil, nil
2822 }
2823
2824 // HandleVerifyMessage implements the verifymessage command.
2825 func HandleVerifyMessage(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2826 var msg string
2827 var e error
2828 // c, ok := cmd.(*btcjson.GetRawTransactionCmd)
2829 c, ok := cmd.(*btcjson.VerifyMessageCmd)
2830 if !ok {
2831 var h string
2832 h, e = s.HelpCacher.RPCMethodHelp("verifymessage")
2833 if e != nil {
2834 msg = e.Error() + "\n\n"
2835 }
2836 msg += h
2837 return nil, &btcjson.RPCError{
2838 Code: btcjson.ErrRPCInvalidParameter,
2839 Message: msg,
2840 // "invalid subcommand for addnode",
2841 }
2842 }
2843 // Decode the provided address.
2844 params := s.Cfg.ChainParams
2845 addr, e := btcaddr.Decode(c.Address, params)
2846 if e != nil {
2847 return nil, &btcjson.RPCError{
2848 Code: btcjson.ErrRPCInvalidAddressOrKey,
2849 Message: "Invalid address or key: " + e.Error(),
2850 }
2851 }
2852 // Only P2PKH addresses are valid for signing.
2853 if _, ok := addr.(*btcaddr.PubKeyHash); !ok {
2854 return nil, &btcjson.RPCError{
2855 Code: btcjson.ErrRPCType,
2856 Message: "Address is not a pay-to-pubkey-hash address",
2857 }
2858 }
2859 // Decode base64 signature.
2860 sig, e := base64.StdEncoding.DecodeString(c.Signature)
2861 if e != nil {
2862 return nil, &btcjson.RPCError{
2863 Code: btcjson.ErrRPCParse.Code,
2864 Message: "Malformed base64 encoding: " + e.Error(),
2865 }
2866 }
2867 // Validate the signature - this just shows that it was valid at all. we will compare it with the key next.
2868 var buf bytes.Buffer
2869 e = wire.WriteVarString(&buf, 0, "Bitcoin Signed Message:\n")
2870 if e != nil {
2871 D.Ln(e)
2872
2873 }
2874 e = wire.WriteVarString(&buf, 0, c.Message)
2875 if e != nil {
2876 D.Ln(e)
2877
2878 }
2879 expectedMessageHash := chainhash.DoubleHashB(buf.Bytes())
2880 pk, wasCompressed, e := ecc.RecoverCompact(
2881 ecc.S256(), sig,
2882 expectedMessageHash,
2883 )
2884 if e != nil {
2885 // Mirror Bitcoin Core behavior, which treats error in RecoverCompact as invalid signature.
2886 return false, nil
2887 }
2888 // Reconstruct the pubkey hash.
2889 var serializedPK []byte
2890 if wasCompressed {
2891 serializedPK = pk.SerializeCompressed()
2892 } else {
2893 serializedPK = pk.SerializeUncompressed()
2894 }
2895 address, e := btcaddr.NewPubKey(serializedPK, params)
2896 if e != nil {
2897 // Again mirror Bitcoin Core behavior, which treats error in public key reconstruction as invalid signature.
2898 return false, nil
2899 }
2900 // Return boolean if addresses match.
2901 return address.EncodeAddress() == c.Address, nil
2902 }
2903
2904 // HandleVersion implements the version command. NOTE: This is a btcsuite extension ported from github.com/decred/dcrd.
2905 func HandleVersion(s *Server, cmd interface{}, closeChan qu.C) (interface{}, error) {
2906 result := map[string]btcjson.VersionResult{
2907 "podjsonrpcapi": {
2908 VersionString: JSONRPCSemverString,
2909 Major: JSONRPCSemverMajor,
2910 Minor: JSONRPCSemverMinor,
2911 Patch: JSONRPCSemverPatch,
2912 },
2913 }
2914 return result, nil
2915 }
2916