network-bitcoin-1.8.3: src/Network/Bitcoin/Mining.hs
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wall #-}
-- | An interface to bitcoind's available mining RPC calls. The implementation
-- of these functions can be found at <https://github.com/bitcoin/bitcoin/blob/master/src/rpcmining.cpp>.
--
-- If any APIs are missing, patches are always welcome. If you look at the
-- source of this module, you'll see that the interface code is trivial.
--
-- Note that it is highly discouraged to use bitcoind for actual bitcoin
-- mining. It uses the CPU for mining, which is much, much less power
-- efficient than GPU mining. If you're paying for power, you will not come
-- out ahead.
--
-- Instead, consider using a GPU miner listed at <https://en.bitcoin.it/wiki/Software#Mining_apps>.
module Network.Bitcoin.Mining ( Client
, getClient
, getGenerate
, setGenerate
, generate
, generateToAddress
, getHashesPerSec
, MiningInfo(..)
, getMiningInfo
, HashData(..)
, getWork
, solveBlock
, Transaction(..)
, CoinBaseAux(..)
, BlockTemplate(..)
, getBlockTemplate
, submitBlock
) where
import Control.Monad
import Data.Aeson as A
import Network.Bitcoin.Internal
-- | Returns whether or not bitcoind is generating bitcoins.
getGenerate :: Client -- ^ bitcoind RPC client
-> IO Bool
getGenerate client = callApi client "getgenerate" []
-- | Controls whether or not bitcoind is generating bitcoins.
-- If bitcoind runs in regtest mode the number of generated hashes is returned.
-- See https://bitcoin.org/en/developer-reference#setgenerate for more details.
setGenerate :: Client -- ^ bitcoind RPC client
-> Bool -- ^ Turn it on, or turn it off?
-> Maybe Int -- ^ Generation is limited to this number of
-- processors. Set it to Nothing to keep the value
-- at what it was before, Just -1 to use all
-- available cores, and any other value to limit it.
-- If bitcoind runs in regtest mode instead of the number of processors,
-- this specifies the number of hashes to generate.
-> IO (Maybe [HexString])
setGenerate client onOff Nothing =
unArr <$> callApi client "setgenerate" [ tj onOff ]
setGenerate client onOff (Just limit) =
unArr <$> callApi client "setgenerate" [ tj onOff, tj limit ]
-- | The generate RPC nearly instantly generates blocks.
-- See https://bitcoin.org/en/developer-reference#generate for more details.
generate :: Client
-> Int -- ^ The number of blocks to generate.
-- The RPC call will not return until all
-- blocks have been generated or the maxium
-- number of iterations has been reached
-> Maybe Int -- ^ The maximum number of iterations that
-- are tried to create the requested number
-- of blocks. Default is 1000000
-> IO [HexString] -- ^ An array containing the block header
-- hashes of the generated blocks
-- (may be empty if used with generate 0)
generate client blocks Nothing =
callApi client "generate" [ tj blocks ]
generate client blocks (Just maxTries) =
callApi client "generate" [ tj blocks, tj maxTries]
-- | The generatetoaddress RPC mines blocks immediately to a specified address.
-- See https://bitcoin.org/en/developer-reference#generatetoaddress for more details.
generateToAddress :: Client
-> Int -- ^ The number of blocks to generate.
-- The RPC call will not return until all
-- blocks have been generated or the maxium
-- number of iterations has been reached
-> Address -- ^ The address to send the newly generated Bitcoin to
-> Maybe Int -- ^ The maximum number of iterations that
-- are tried to create the requested number
-- of blocks. Default is 1000000
-> IO [HexString]
generateToAddress client blocks address Nothing =
callApi client "generatetoaddress" [ tj blocks, tj address ]
generateToAddress client blocks address (Just maxTries) =
callApi client "generatetoaddress" [ tj blocks, tj address, tj maxTries ]
-- | Returns a recent hashes per second performance measurement while
-- generating.
getHashesPerSec :: Client -> IO Integer
getHashesPerSec client = callApi client "gethashespersec" []
-- | Information related to the current bitcoind mining operation.
--
-- If a field is undocumented here, it's because I don't know what it means.
-- If you DO know what it means, I'd love it if you would submit a patch to
-- help complete this documentation.
data MiningInfo =
MiningInfo {
-- | The number of blocks in our block-chain.
nBlocks :: Integer
-- | The size of the current block we're mining.
, currentBlockSize :: Integer
, currentBlockTransaction :: Integer
-- | How difficult mining currently is.
, difficulty :: Double
-- | Any mining errors that may have come up.
, miningErrors :: Text
-- | Are we currently generating bitcoins?
, isGenerating :: Bool
-- | How many processors have we limited bitcoin mining to?
, generationProcessorLimit :: Integer
-- | How fast is the mining going?
, hashesPerSecond :: Integer
, pooledTransactions :: Integer
-- | Are we on the bitcoin test network (as opposed to the real
-- thing)?
, miningOnTestNetwork :: Bool
}
deriving ( Show, Read, Ord, Eq )
instance FromJSON MiningInfo where
parseJSON (Object o) = MiningInfo <$> o .: "blocks"
<*> o .: "currentblocksize"
<*> o .: "currentblocktx"
<*> o .: "difficulty"
<*> o .: "errors"
<*> o .: "generate"
<*> o .: "genproclimit"
<*> o .: "hashespersec"
<*> o .: "pooledtx"
<*> o .: "testnet"
parseJSON _ = mzero
-- | Returns an object containing mining-related information.
getMiningInfo :: Client -> IO MiningInfo
getMiningInfo client = callApi client "getmininginfo" []
-- | The hash data returned from 'getWork'.
data HashData =
HashData { blockData :: HexString
-- | Little-endian hash target, formatted as a hexadecimal string.
, hdTarget :: HexString
, hash1 :: HexString
, midstate :: HexString
}
deriving ( Show, Read, Ord, Eq )
instance FromJSON HashData where
parseJSON (Object o) = HashData <$> o .: "data"
<*> o .: "target"
<*> o .: "hash1"
<*> o .: "midstate"
parseJSON _ = mzero
instance ToJSON HashData where
toJSON (HashData dat tar has mid) = object ["data" .= dat, "target" .= tar, "hash1" .= has, "midstate" .= mid]
-- | Returns formatted hash data to work on.
getWork :: Client -> IO HashData
getWork client = callApi client "getwork" []
-- | Tries to solve the given block, and returns true if it was successful.
solveBlock :: Client -> HexString -> IO Bool
solveBlock client data_ = callApi client "getwork" [ tj data_ ]
-- | A transaction to be included in the next block.
data Transaction =
Transaction { txnData :: HexString
, txnHash :: HexString
, depends :: Vector Integer
, txnFee :: Maybe Integer
, sigOps :: Integer
}
deriving ( Show, Read, Ord, Eq )
instance FromJSON Transaction where
parseJSON (Object o) = Transaction <$> o .: "data"
<*> o .: "hash"
<*> o .: "depends"
<*> o .:? "fee"
<*> o .: "sigops"
parseJSON _ = mzero
data CoinBaseAux = CoinBaseAux { cbFlags :: HexString
}
deriving ( Show, Read, Ord, Eq )
instance FromJSON CoinBaseAux where
parseJSON (Object o) = CoinBaseAux <$> o .: "flags"
parseJSON _ = mzero
-- | A template for constructing a block to work on.
--
-- See <https://en.bitcoin.it/wiki/BIP_0022> for the full specification.
data BlockTemplate =
BlockTemplate { blockVersion :: Integer
-- | Hash of current highest block.
, previousBlockHash :: HexString
-- | Contents of non-coinbase transactions that should be
-- included in the next block.
, transactionsToInclude :: Vector Transaction
-- | Data that should be included in coinbase.
, coinBaseAux :: CoinBaseAux
-- | Maximum allowable input to coinbase transaction,
-- including the generation award and transaction fees.
, coinBaseValue :: Integer
-- | Hash target.
, btTarget :: HexString
-- | Minimum timestamp appropriate for next block.
, minTime :: Integer
-- | Range of valid nonces.
, nonceRange :: HexString
-- | Limit of sigops in blocks.
, sigopLimit :: Integer
-- | Limit of block size.
, sizeLimit :: Integer
-- | Current timestamp.
, curTime :: Integer
-- | Compressed target of the next block.
, btBits :: HexString
-- | Height of the next block.
, btHeight :: Integer
}
deriving ( Show, Read, Ord, Eq )
instance FromJSON BlockTemplate where
parseJSON (Object o) = BlockTemplate <$> o .: "version"
<*> o .: "previousblockhash"
<*> o .: "transactions"
<*> o .: "coinbaseaux"
<*> o .: "coinbasevalue"
<*> o .: "target"
<*> o .: "mintime"
<*> o .: "noncerange"
<*> o .: "sigoplimit"
<*> o .: "sizelimit"
<*> o .: "curtime"
<*> o .: "bits"
<*> o .: "height"
parseJSON _ = mzero
-- | Returns data needed to construct a block to work on.
getBlockTemplate :: Client -> IO BlockTemplate
getBlockTemplate client = callApi client "getblocktemplate" []
-- | Unfortunately, the submitblock API call returns null on success, and
-- the string "rejected" on failure.
--
-- We use 'StupidReturnValue' to parse this ridiculous API.
data StupidReturnValue = SRV { unStupid :: Bool }
instance FromJSON StupidReturnValue where
parseJSON Null = return $ SRV True
parseJSON _ = return $ SRV False
-- | Attempts to submit a new block to the network.
submitBlock :: Client
-> HexString -- ^ The block to submit.
-> IO Bool -- ^ Was the block accepted by the network?
submitBlock client block = unStupid <$> callApi client "submitblock" [ tj block ]