miningcore/README.md

15 KiB

Build status Docker Build Statu Docker Stars Docker Pulls license

MiningCore

MiningCore is the multi-currency pool-engine powering poolmining.org

Even though the pool engine can be used to run a production-pool, doing so currently requires to develop your own website frontend talking to the pool's API-Endpoint at http://127.0.0.1:4000. This is going to change in the future.

Features

  • Supports clusters of pools each running individual currencies
  • Ultra-low-latency Stratum implementation using asynchronous I/O (LibUv)
  • Adaptive share difficulty ("vardiff")
  • PoW validation (hashing) using native code for maximum performance
  • Session management for purging DDoS/flood initiated zombie workers
  • Payment processing
  • Banning System for banning peers that are flooding with invalid shares
  • Live Stats API on Port 4000
  • POW (proof-of-work) & POS (proof-of-stake) support
  • Detailed per-pool logging to console & filesystem
  • Runs on Linux and Windows

Coins

Coin Implemented Tested Planned
Bitcoin Yes Yes
Bitcoin Cash Yes Yes
Litecoin Yes Yes
Monero Yes Yes
DASH Yes Yes
Groestlcoin Yes Yes
Ethereum No Oct 2017
Ethereum Classic No Oct 2017
Zcash No Nov 2017
Dogecoin Yes No
DigiByte Yes No
Namecoin Yes No
Viacoin Yes No
Peercoin Yes No

Runtime Requirements

PostgreSQL Database setup

Create the database:

createuser miningcore
createdb miningcore
psql (enter the password for postgressql)
alter user miningcore with encrypted password 'some-secure-password';
grant all privileges on database miningcore to miningcore;

Import the database schema:

wget https://raw.githubusercontent.com/coinfoundry/miningcore/master/src/MiningCore/Persistence/Postgres/Scripts/createdb.sql
psql -d miningcore -U miningcore -f createdb.sql

Configuration

MiningCore is configured using a single JSON configuration file which may be used to initialize a cluster of multiple pool each supporting a different crypto-currency.

Note: Please refer to this page for a list of supported coins and other configuration options.

Example configuration:

{
  "logging": {
    "level": "info",
    "enableConsoleLog": true,
    "enableConsoleColors": true,
    "logFile": "",
    "logBaseDirectory": "",
    "perPoolLogFile": false
  },
  "banning": {
    "manager": "integrated" // "integrated" or "iptables" (linux only)
  },
  "notifications": {
    "enabled": true,
    "email": {
      "host": "smtp.example.com",
      "port": 587,
      "user": "user",
      "password": "password",
      "fromAddress": "info@yourpool.org",
      "fromName": "pool support"
    },
    "admin": {
      "enabled": false,
      "emailAddress": "user@example.com",
      "notifyBlockFound": true
    }
  },
  // Where to persist shares and blocks to
  "persistence": {
    // Persist to postgresql database
    "postgres": {
      "host": "127.0.0.1",
      "port": 5432,
      "user": "miningcore",
      "password": "yourpassword",
      "database": "miningcore"
    }
  },
  // Do not allow 0.1% donation to MiningCore developers. Please leave this disabled to help support development of MiningCore.
  "disableDevDonation": false,
  // Generate payouts for recorded shares and blocks
  "paymentProcessing": {
    "enabled": true,
    "interval": 600, // how often to process payouts
    // Path to a file used to backup shares under emergency conditions such as database outage
    "shareRecoveryFile": "recovered-shares.txt"
  },
  // Api Settings
  "api": {
    "enabled": true,
    "listenAddress": "0.0.0.0", // Binding address for API, Default: 127.0.0.1
    "port": 80 // Binding port for API, Default: 4000
  },
  "pools": [{
    // DON'T change the id after a production pool has begun collecting shares!
    "id": "dash1",
    "enabled": true,
    "coin": {
      "type": "DASH"
    },
    // Address to where block rewards are given (pool wallet)
    "address": "yiZodEgQLbYDrWzgBXmfUUHeBVXBNr8rwR",
    // Block rewards go to the configured pool wallet address to later be paid out to miners,
    // except for a percentage that can go to, for examples, pool operator(s) as pool fees or
    // or to donations address. Addresses or hashed public keys can be used. Here is an example
    // of rewards going to the main pool op
    "rewardRecipients": [
      {
        "type": "op",
        "address": "yiZodEgQLbYDrWzgBXmfUUHeBVXBNr8rwR", // pool
        "percentage": 1.5
      }
    ],
    // How often to poll RPC daemons for new blocks, in milliseconds
    "blockRefreshInterval": 1000,
    // Some miner apps will consider the pool dead/offline if it doesn't receive anything new jobs
    // for around a minute, so every time we broadcast jobs, set a timeout to rebroadcast
    // in this many seconds unless we find a new job. Set to zero or remove to disable this.
    "jobRebroadcastTimeout": 55,
    // Some attackers will create thousands of workers that use up all available socket connections,
    // usually the workers are zombies and don't submit shares after connecting. This features
    // detects those and disconnects them.
    "clientConnectionTimeout": 600, // Remove workers that haven't been in contact for this many seconds
    // If a worker is submitting a high threshold of invalid shares we can temporarily ban their IP
    // to reduce system/network load. Also useful to fight against flooding attacks. If running
    // behind something like HAProxy be sure to enable 'tcpProxyProtocol', otherwise you'll end up
    // banning your own IP address (and therefore all workers).
    "banning": {
      "enabled": true,
      "time": 600, // How many seconds to ban worker for
      "invalidPercent": 50, // What percent of invalid shares triggers ban
      "checkThreshold": 50 // Check invalid percent when this many shares have been submitted
    },
    // Each pool can have as many ports for your miners to connect to as you wish. Each port can
    // be configured to use its own pool difficulty and variable difficulty settings. varDiff is
    // optional and will only be used for the ports you configure it for.
    "ports": {
      "3052": { // A port for your miners to connect to
        "listenAddress": "0.0.0.0", // the binding address for the port, default: 127.0.0.1
        "difficulty": 0.02, // the pool difficulty for this port
        // Variable difficulty is a feature that will automatically adjust difficulty for
        // individual miners based on their hashrate in order to lower networking overhead
        "varDiff": {
          "minDiff": 0.01, // Minimum difficulty
          "maxDiff": null, // Network difficulty will be used if it is lower than this
          "targetTime": 15, // Try to get 1 share per this many seconds
          "retargetTime": 90, // Check to see if we should retarget every this many seconds
          "variancePercent": 30 // Allow time to very this % from target without retargeting
        }
      },
      "3053": { //  Another port for your miners to connect to, this port does not use varDiff
        "listenAddress": "0.0.0.0", // the binding address for the port, default: 127.0.0.1
        "difficulty": 100 // 256 //  The pool difficulty
      }
    },
    // Recommended to have at least two daemon instances running in case one drops out-of-sync
    // or offline. For redundancy, all instances will be polled for block/transaction updates
    // and be used for submitting blocks. Creating a backup daemon involves spawning a daemon
    // using the "-datadir=/backup" argument which creates a new daemon instance with it's own
    // RPC config. For more info on this see: https:// en.bitcoin.it/wiki/Data_directory
    // and https:// en.bitcoin.it/wiki/Running_bitcoind
    "daemons": [{
        "host": "127.0.0.1",
        "port": 15001,
        "user": "user",
        "password": "pass"
      }
    ],
    // Generate payouts for recorded shares
    "paymentProcessing": {
      "enabled": true,
      "minimumPayment": 0.01, // in pool-base-currency (ie. Bitcoin, NOT Satoshis)
      "payoutScheme": "PPLNS",
      "payoutSchemeConfig": {
        "factor": 2.0
      }
    }
  }]
}

API

MiningCore exposes a simple REST API at http://localhost:4000. The primary purpose of the API is to power custom web-frontends for the pool.

/api/pools

Returns configuration data and current stats for all configured pools.

Example Response:

{
  "pools": [{
      "id": "xmr1",
      "coin": {
        "type": "XMR"
      },
      "ports": {
        "4032": {
          "difficulty": 1600.0,
          "varDiff": {
            "minDiff": 1600.0,
            "maxDiff": 160000.0,
            "targetTime": 15.0,
            "retargetTime": 90.0,
            "variancePercent": 30.0
          }
        },
        "4256": {
          "difficulty": 5000.0
        }
      },
      "paymentProcessing": {
        "enabled": true,
        "minimumPayment": 0.01,
        "payoutScheme": "PPLNS",
        "payoutSchemeConfig": {
          "factor": 2.0
        },
        "minimumPaymentToPaymentId": 5.0
      },
      "banning": {
        "enabled": true,
        "checkThreshold": 50,
        "invalidPercent": 50.0,
        "time": 600
      },
      "clientConnectionTimeout": 600,
      "jobRebroadcastTimeout": 55,
      "blockRefreshInterval": 1000,
      "poolFeePercent": 0.0,
      "donationsPercent": 0.0,
      "poolStats": {
        "connectedMiners": 0,
        "poolHashRate": 0.0
      },
      "networkStats": {
        "networkType": "Test",
        "networkHashRate": 39.05,
        "networkDifficulty": 2343.0,
        "lastNetworkBlockTime": "2017-09-17T10:35:55.0394813Z",
        "blockHeight": 157,
        "connectedPeers": 2,
        "rewardType": "POW"
      }
    }]
}

/api/pool/<poolid>/stats/hourly

Returns pool stats for the last 24 hours (stats array contains 24 entries)

Example Response:

{
  "stats": [
    {
      "poolHashRate": 20.0,
      "connectedMiners": 12,
      "created": "2017-09-16T10:00:00"
    },
    {
      "poolHashRate": 25.0,
      "connectedMiners": 15,
      "created": "2017-09-16T11:00:00"
    },

    ...

    {
      "poolHashRate": 23.0,
      "connectedMiners": 13,
      "created": "2017-09-17T10:00:00"
    }
  ]
}

/api/pool/<poolid>/miner/<miner-wallet-address>/stats

Provides current stats about a miner on a specific pool

Example Response:

{
  "pendingShares": 354,
  "pendingBalance": 1.456,
  "totalPaid": 12.354
}

/api/pool/<poolid>/blocks

Returns information about blocks mined by the pool. Results can be paged by using the page and pageSize query parameters

http://localhost:4000/api/pool/xmr1/blocks?page=2&pageSize=3

Example Response:

[
  {
    "blockHeight": 197,
    "status": "pending",
    "transactionConfirmationData": "6e7f68c7891e0f2fdbfd0086d88be3b0d57f1d8f4e1cb78ddc509506e312d94d",
    "reward": 17.558881241740,
    "infoLink": "https://xmrchain.net/block/6e7f68c7891e0f2fdbfd0086d88be3b0d57f1d8f4e1cb78ddc509506e312d94d",
    "created": "2017-09-16T07:41:50.242856"
  },
  {
    "blockHeight": 196,
    "status": "confirmed",
    "transactionConfirmationData": "bb0b42b4936cfa210da7308938ad6d2d34c5339d45b61c750c1e0be2475ec039",
    "reward": 17.558898015821,
    "infoLink": "https://xmrchain.net/block/bb0b42b4936cfa210da7308938ad6d2d34c5339d45b61c750c1e0be2475ec039",
    "created": "2017-09-16T07:41:39.664172"
  },
  {
    "blockHeight": 195,
    "status": "orphaned",
    "transactionConfirmationData": "b9b5943b2646ebfd19311da8031c66b164ace54a7f74ff82556213d9b54daaeb",
    "reward": 17.558914789917,
    "infoLink": "https://xmrchain.net/block/b9b5943b2646ebfd19311da8031c66b164ace54a7f74ff82556213d9b54daaeb",
    "created": "2017-09-16T07:41:14.457664"
  }
]

/api/pool/<poolid>/payments

Returns information about payments issued by the pool. Results can be paged by using the page and pageSize query parameters

http://localhost:4000/api/pool/xmr1/payments?page=2&pageSize=3

Example Response:

[
  {
    "coin": "XMR",
    "address": "9wviCeWe2D8XS82k2ovp5EUYLzBt9pYNW2LXUFsZiv8S3Mt21FZ5qQaAroko1enzw3eGr9qC7X1D7Geoo2RrAotYPwq9Gm8",
    "amount": 7.5354,
    "transactionConfirmationData": "9e7f68c7891e0f2fdbfd0086d88be3b0d57f1d8f4e1cb78ddc509506e312d94d",
    "infoLink": "https://xmrchain.net/tx/9e7f68c7891e0f2fdbfd0086d88be3b0d57f1d8f4e1cb78ddc509506e312d94d",
    "created": "2017-09-16T07:41:50.242856"
  }
]

Docker

The official MiningCore docker-image expects a valid pool configuration file as volume argument:

$ docker run -d -p 3032:3032 -v /path/to/config.json:/config.json:ro coinfoundry/miningcore-docker

You also need to expose all stratum ports specified in your configuration file.

Building from Source (Shell)

Install the .Net Core 2.0 SDK for your platform

git clone https://github.com/coinfoundry/miningcore
cd miningcore/src/MiningCore

Linux

Install dev-dependencies (Ubuntu)

apt-get update -y && apt-get -y install git cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev
./linux-build.sh

Windows

windows-build.bat

Now copy config.json to ../../build, edit it to your liking and run:

cd ../../build
dotnet MiningCore.dll -c config.json

Building from Source (Visual Studio)

  • Install Visual Studio 2017 (Community Edition is sufficient)
  • Install the .Net Core 2.0 SDK for your platform
  • Open MiningCore.sln in VS 2017