Giter Site home page Giter Site logo

node-stratum-pool's Introduction

s-nomp: Some New Open Mining Portal

NOTE: We're working on putting together an "official" s-nomp which can be supported by many coins and pools instead of so many running their own flavors. More to come!

This is a Equihash mining pool based off Node Open Mining Portal.

Production Usage Notice

This is beta software. All of the following are things that can change and break an existing s-nomp setup: functionality of any feature, structure of configuration files and structure of redis data. If you use this software in production then DO NOT pull new code straight into production usage because it can and often will break your setup and require you to tweak things like config files or redis data. Only tagged releases are considered stable.

Paid Solution

Usage of this software requires abilities with sysadmin, database admin, coin daemons, and sometimes a bit of programming. Running a production pool can literally be more work than a full-time job.

Community / Support

Please join our Discord to follow development. Any support questions can be answered here quickly as well.

https://discord.gg/4mVaTsH

Usage

Requirements

Seriously

These are legitimate requirements. If you use old versions of Node.js or Redis that may come with your system package manager then you will have problems. Follow the linked instructions to get the last stable versions.

Redis security warning: be sure firewall access to redis - an easy way is to include bind 127.0.0.1 in your redis.conf file. Also it's a good idea to learn about and understand software that you are using - a good place to start with redis is data persistence.

0) Setting up coin daemon

Follow the build/install instructions for your coin daemon. Your coin.conf file should end up looking something like this:

daemon=1
rpcuser=zclassicrpc
rpcpassword=securepassword
rpcport=8232

For redundancy, its recommended to have at least two daemon instances running in case one drops out-of-sync or offline, 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 command-line argument which creates a new daemon instance with it's own config directory and coin.conf file. Learn about the daemon, how to use it and how it works if you want to be a good pool operator. For starters be sure to read:

1) Downloading & Installing

Clone the repository and run npm update for all the dependencies to be installed:

sudo apt-get install build-essential libsodium-dev npm libboost-all-dev
sudo npm install n -g
sudo n stable
git clone https://github.com/s-nomp/s-nomp.git s-nomp
cd s-nomp
npm update
npm install
Pool config

Take a look at the example json file inside the pool_configs directory. Rename it to zclassic.json and change the example fields to fit your setup.

Please Note that: 1 Difficulty is actually 8192, 0.125 Difficulty is actually 1024.

Whenever a miner submits a share, the pool counts the difficulty and keeps adding them as the shares. 

ie: Miner 1 mines at 0.1 difficulty and finds 10 shares, the pool sees it as 1 share. Miner 2 mines at 0.5 difficulty and finds 5 shares, the pool sees it as 2.5 shares. 
[Optional, recommended] Setting up blocknotify
  1. In config.json set the port and password for blockNotifyListener
  2. In your daemon conf file set the blocknotify command to use:
node [path to cli.js] [coin name in config] [block hash symbol]

Example: inside zclassic.conf add the line

blocknotify=node /home/user/s-nomp/scripts/cli.js blocknotify zclassic %s

Alternatively, you can use a more efficient block notify script written in pure C. Build and usage instructions are commented in scripts/blocknotify.c.

3) Start the portal

npm start
Optional enhancements for your awesome new mining pool server setup:
  • Use something like forever to keep the node script running in case the master process crashes.
  • Use something like redis-commander to have a nice GUI for exploring your redis database.
  • Use something like logrotator to rotate log output from s-nomp.
  • Use New Relic to monitor your s-nomp instance and server performance.

Upgrading s-nomp

When updating s-nomp to the latest code its important to not only git pull the latest from this repo, but to also update the node-stratum-pool and node-multi-hashing modules, and any config files that may have been changed.

  • Inside your s-nomp directory (where the init.js script is) do git pull to get the latest s-nomp code.
  • Remove the dependenices by deleting the node_modules directory with rm -r node_modules.
  • Run npm update to force updating/reinstalling of the dependencies.
  • Compare your config.json and pool_configs/coin.json configurations to the latest example ones in this repo or the ones in the setup instructions where each config field is explained. You may need to modify or add any new changes.

Credits

s-nomp

z-nomp

NOMP

License

Released under the MIT License. See LICENSE file.

node-stratum-pool's People

Contributors

bart-is avatar blondfrogs avatar bluecircle avatar bmatusiak avatar bolkin avatar bricecarpentier avatar chrisfranko avatar cronicc avatar cryptosharks131 avatar darkcoinproject avatar earlz avatar egyptianbman avatar hashtobewild avatar hellcatz avatar jmprcx avatar lucasjones avatar nettts avatar nlevo avatar pittxid avatar rdoria1 avatar sennevb avatar sirsavary avatar suchpool avatar tarrenj avatar tentofficial avatar thetrunk avatar vekexasia avatar waveringana avatar zone117x avatar zzzpotato avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-stratum-pool's Issues

Sapling/Overwinter Support - transaction.js

There is a issue with your recent sapling upgrade in the transaction.js file. This little snippet of code will cause the pool to not create over winter transactions correctly when sapling has been added to the coin options. What happens is that the first if statement for sapling returns true, but if the sapling block height has not been reached the second statement will return false and the overwinter statement will be skipped.

if (coin.sapling) {
    if (coin.sapling === true || (typeof coin.sapling === 'number' && coin.sapling <= blockHeight)) {
        txb.setVersion(bitcoin.Transaction.ZCASH_SAPLING_VERSION);
    }
} else if (coin.overwinter) {
    if (coin.overwinter === true || (typeof coin.overwinter === 'number' && coin.overwinter <= blockHeight)) {
        txb.setVersion(bitcoin.Transaction.ZCASH_OVERWINTER_VERSION);
    }
}

I suggest you change the code to this.

    if (coin.sapling === true || (typeof coin.sapling === 'number' && coin.sapling <= blockHeight)) {
        txb.setVersion(bitcoin.Transaction.ZCASH_SAPLING_VERSION);
    }

    else if (coin.overwinter === true || (typeof coin.overwinter === 'number' && coin.overwinter <= blockHeight)) {
        txb.setVersion(bitcoin.Transaction.ZCASH_OVERWINTER_VERSION);
    }

Also you might want to change sapling and overwinter to saplingActivationHeight and overwinterActivationHeight for better descriptions.

Masternode Payments Missing

The following issue is reported in the daemon debug log re: missing masternode payment whenever a block is thought to be found: Address info is xxxxx out.

2022-03-15 21:56:34 CMasternodeBlockPayees::IsTransactionValid -- ERROR: Missing required payment, possible payees: 'PtZ7aQYjBHTVRN9UyaCJ4dHt7xD3CpvV8wU(19)', amount: 125000000 PSL
2022-03-15 21:56:34 Pxxxxxxxxxxxxxxxxxxxxxxx -- 625000000
2022-03-15 21:56:34 OP_DUP OP_HASH160 96101f5bad3070ca9bf4c32675f3d749dcef0412 OP_EQUALVERIFY OP_CHECKSIG
2022-03-15 21:56:34 Pxxxxxxxxxxxxxxxxxxxxxx -- 0
2022-03-15 21:56:34 OP_DUP OP_HASH160 dd5da9233cbae09b091c56570ba3df8d2e7a6809 OP_EQUALVERIFY OP_CHECKSIG
2022-03-15 21:56:34 ERROR: ConnectBlock(PASTEL): InValid coinbase transaction (MN payment) at height 232611: CTransaction(hash=2284f2fb5f, ver=4, fOverwintered=1, nVersionGroupId=892f2085, vin.size=1, vout.size=2, nLockTime=0, nExpiryHeight=0, valueBalance=0, vShieldedSpend.size=0, vShieldedOutput.size=0)
CTxIn(COutPoint(0000000000, 0), coinbase 03a38c030044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b)
CTxOut(nValue=6250.00000000, scriptPubKey=76a91496101f5bad3070ca9bf4c326)
CTxOut(nValue=0.00000000, scriptPubKey=76a914dd5da9233cbae09b091c5657)

The coin's blocktemplate is supposed to pay 5000 to miners and 1250 (20%) to masternodes. Instead, the full reward amount is attempted to payout to the pool without factoring in masternode payments.

This is the coin config file:

{
"name": "pastel",
"symbol": "psl",
"algorithm": "equihash",
"parameters": {
"N": 200,
"K": 9,
"personalization": "PslPoW"
},
"overwinter": true,
"sapling": true,
"requireShielding": false,
"subsidyMultipleOfSatoshi": 125000,
"masternodeReward": true,
"masternodePayee": true,
"masternodePayment": true,
"paymasternodeReward": true,

"explorer": {
    "txURL": "https://explorer.pastel.network/tx/",
    "blockURL": "https://explorer.pastel.network/block/",
    "_comment_explorer": "This is the coin's explorer full base url for transaction and blocks i.e. (https://explorer.coin.com/tx/). The pool will automatically add the transaction id or block id at the end."
}

}

From what I've gathered, the RPC call for masternodeReward, MasternodePayee, and MasternodePayment should be pulled from the coin's daemon in order to correctly payout masternodes when a block is found. Is that correct? If not, what should be adjusted to ensure masternode payments are correctly deducted from the blockreward?

stratum should disconnect miners if connection to the node is lost

You can setup a coin daemon, get it up to the top of the chain and verify that getblocktemplate is working properly. Then start up your s-nomp instance for that coin and it will connect and after that, it will allow miners to connect and start mining.

If some time after that the coin daemon becomes unavailable and getblocktemplate fails, s-nomp will reject all new connections to the pool until the problem with the coin daemon is resolved. That is the proper behavior.

Existing connections, however, are not dropped. This has the effect that if a coin daemon dies, all currently connected miners will continue to mine without any indication on their part that there is a problem.

The code should be updated to disconnect all existing miners if getblocktemplate fails.

Error, founders reward missing for block template!

OS: Ubuntu 18.04
Block Daemon: zcashd 4.2.0

zcash.conf:

addnode=mainnet.z.cash
rpcuser=<my rpc user>
rpcpassword=<my password>
rpcthreads=8
rpcworkqueue=512
blocknotify=/pools/zecpool/blocknotify 127.0.0.1:17117 zec %s

Using latest S-NOMP from github.

config.json:

  "defaultPoolConfigs": {
        "blockRefreshInterval": 0,
        "jobRebroadcastTimeout": 55,
        "connectionTimeout": 600,
        "emitInvalidBlockHashes": false,
        "validateWorkerUsername": true,
        "tcpProxyProtocol": false,



    "blockNotifyListener": {
    "enabled": true,
    "port": 17117
    }

Using the coins/zec.json that is in the git.

Continuously get the error of:

Error, founders reward missing for block template!

tcpdump of json packet from getblocksubsidy:

{"method":"getblocksubsidy","params":[1124772],"id":1611613376034}HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Jan 2021 22:22:56 GMT
Content-Length: 607
Connection: close

{"result":{"fundingstreams":[{"recipient":"Electric Coin Company","specification":"https://zips.z.cash/zip-0214","value":0.21875000,"valueZat":21875000,"address":"t3ZBdBe4iokmsjdhMuwkxEdqMCFN16YxKe6"},{"recipient":"Zcash Foundation","specification":"https://zips.z.cash/zip-0214","value":0.15625000,"valueZat":15625000,"address":"t3dvVE3SQEi7kqNzwrfNePxZ1d4hUyztBA1"},{"recipient":"Major Grants","specification":"https://zips.z.cash/zip-0214","value":0.25000000,"valueZat":25000000,"address":"t3XyYW8yBFRuMnfvm5KLGFbEVz25kckZXym"}],"miner":2.50000000,"founders":0.00000000},"error":null,"id":1611613376034}

Tried several different things but can't figure it out.

getblocksubsidy

The getblocksubsidy call in the pool.js file does not pass in a block height parameter. This can cause the pool to hang when the block subsidy changes (i.e. halving) as the getblocksubsidy RPC call in Zcash (and I assume most clones) returns the blocksubsidy for the block at the chain tip, not the required block subsidy for the next block to be submitted.

This is the relevant code from zcash 2.0.0 from the mining.cpp file.

UniValue getblocksubsidy(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() > 1)
        throw runtime_error(
            "getblocksubsidy height\n"
            "\nReturns block subsidy reward, taking into account the mining slow start and the founders reward, of block at index provided.\n"
            "\nArguments:\n"
            "1. height         (numeric, optional) The block height.  If not provided, defaults to the current height of the chain.\n"
            "\nResult:\n"
            "{\n"
            "  \"miner\" : x.xxx           (numeric) The mining reward amount in " + CURRENCY_UNIT + ".\n"
            "  \"founders\" : x.xxx        (numeric) The founders reward amount in " + CURRENCY_UNIT + ".\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getblocksubsidy", "1000")
            + HelpExampleRpc("getblockubsidy", "1000")
        );

    LOCK(cs_main);
    int nHeight = (params.size()==1) ? params[0].get_int() : chainActive.Height();
    if (nHeight < 0)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");

    CAmount nReward = GetBlockSubsidy(nHeight, Params().GetConsensus());
    CAmount nFoundersReward = 0;
    if ((nHeight > 0) && (nHeight <= Params().GetConsensus().GetLastFoundersRewardBlockHeight())) {
        nFoundersReward = nReward/5;
        nReward -= nFoundersReward;
    }
    UniValue result(UniValue::VOBJ);
    result.push_back(Pair("miner", ValueFromAmount(nReward)));
    result.push_back(Pair("founders", ValueFromAmount(nFoundersReward)));
    return result;
}

MAKE P2P CONNECTION MORE RESILIENT

I have a ZEN pool with the p2p enabled.

Always the first two or three p2p connection attempts fail:

34|pool_zen | 2019-06-01 21:36:57 [Pool] [horizen] (Thread 1) p2p had a socket error {"errno":"ECONNRESET","code":"ECONNRESET","syscall":"read"}

To fix this issue and make the p2p connection more resilient i modified the pool.js as follows:

   let retryCount = 1000

    function SetupPeer() {
        if (!options.p2p || !options.p2p.enabled)
            return;

        if (options.testnet && !options.coin.peerMagicTestnet) {
            emitErrorLog('p2p cannot be enabled in testnet without peerMagicTestnet set in coin configuration');
            return;
        }
        else if (!options.coin.peerMagic) {
            emitErrorLog('p2p cannot be enabled without peerMagic set in coin configuration');
            return;
        }

        _this.peer = new peer(options);
        _this.peer.on('connected', function () {
            emitLog('p2p connection successful');
        }).on('connectionRejected', function () {
            emitErrorLog('p2p connection failed - likely incorrect p2p magic value');
            retryCount--
            if (retryCount > 0) {
              emitLog('p2p trying to connect again soon... retryCount: ' + retryCount)
              setTimeout(SetupPeer, 2000)
            }
        }).on('disconnected', function () {
            emitWarningLog('p2p peer node disconnected - attempting reconnection...');
        }).on('connectionFailed', function (e) {
            emitErrorLog('p2p connection failed - likely incorrect host or port');
        }).on('socketError', function (e) {
            emitErrorLog('p2p had a socket error ' + JSON.stringify(e));
        }).on('error', function (msg) {
            emitWarningLog('p2p had an error ' + msg);
        }).on('blockFound', function (hash) {
            _this.processBlockNotify(hash, 'p2p');
        });
    }

As you can see I haved added a retry.

Now this implementation is obviously NOT perfect, BUT it proves to work.

Before i would have 0 p2p connections... maybe 1 in begining then they would all die..

With the code above i am able to maintain p2p connections

FYI my horizen daemon has TLS enabled

Please include some form of retry in your code as I have layed out.

Thanks

Cheers!

who to add algo x16r

What ammendmends in stratum should be done to add new(unsupported) algorithm in your S-NOMP pool. Pls advise. Thank you.

Better Error Catching Due to Perf/Env Failures

Most of the time when node-startum-pool has a slight lag with RPC from the daemons due to performance of hardware/software, network latency, etc... the whole pool crashes or the pool stops listening due to a very quick timeout.

I couldn't imagine if chrome crashed every time facebook wouldn't load the whole way for somebody. lol.

E.G.
DNS use case to talk to from node-stratum-pool to daemons. If main DNS server times out linux by default waits 5 seconds (crazy long I know) to start using the second DNS server. s-nomp will give a socket hangup almost instantly if it doesn't respond. Now this is good but the connection doesn't timeout on node-stratum's side and it retries the socket indefinitely. DNS is used in scaled setups.. being forceful on IP is something I'm against. Now I've worked around this by setting the DNS timeout to 500ms.

Another scenario from someone else.

2) it hangs from 1 to 5 minutes, the daemon is just busy, it doesn't break
3) after this short period of times, it replies again and works as usual
WHAT'S HAPPENING UNDER THE HOOD:
1) the pool recognize that the daemon is not replying anymore --> socket hang up
2) it drops the pool for that specific coin --> zeroclassic pool fork died (it drops the stratum, nothing inside logs, all clear)
SOLUTION:
1) before dropping a pool fork, wait more time OR double check multiple times ---> IF SOCKET HANG UP MORE THAN 3 TIMES IN A ROW --> drop pool
got it?

from jacko0088.

Now my solution is to force a reconnect to the daemon after N socket hangups set by the end user or statically coded and a timeout_connect option.

TypeError: Cannot read property 'toString' of null

return s.toString().replace(/[^a-zA-Z0-9.]+/g, '');

I'm creating this issue as a reminder for myself to look into this.

TypeError: Cannot read property 'toString' of null
    at getSafeString (node_modules/stratum-pool/lib/stratum.js:143:34)
    at getSafeWorkerString (node_modules/stratum-pool/lib/stratum.js:146:17)
    at handleAuthorize (node_modules/stratum-pool/lib/stratum.js:158:28)
    at handleMessage (node_modules/stratum-pool/lib/stratum.js:85:17)
    at messages.forEach.message (node_modules/stratum-pool/lib/stratum.js:291:25)
    at Array.forEach (<anonymous>)
    at Socket.socket.on.d (node_modules/stratum-pool/lib/stratum.js:273:26)

I couldn't ask for a better stack trace! Ok, it looks like someone was submitting requests to authenticate but the miner isn't sending any params through which leads message.params[0] being null. I'm tempted to create a PR that instabans any requests such as this.

Empty address in rewardRecipients will still deduct fee from coinbase

Currently the default rewardRecipient is empty with a 0.2 value. If the user does not specify an address here, the fee is deducted from the coinbase and given to no one as seen here

    "rewardRecipients": {
        "": 0.2
    },

function SetupRecipients() {
var recipients = [];
options.feePercent = 0;
options.rewardRecipients = options.rewardRecipients || {};
for (var r in options.rewardRecipients) {
var percent = options.rewardRecipients[r];
var rObj = {
percent: percent,
address: r
};
recipients.push(rObj);
options.feePercent += percent;
}
if (recipients.length === 0) {
emitErrorLog('No rewardRecipients have been setup which means no fees will be taken');
}
options.recipients = recipients;
}

I feel like most pool ops will always set this fee, however solo miners using s-nomp may not (thinking they are getting 100% anyways). Should we add a check here to let the pool operator know it's still blank? Maybe something simple like this?

        if('' in options.rewardRecipients) {
            emitErrorLog('No fee address specified!');
        }

Or perhaps we should set it to always use a value of 0 if no address is given?

problem with getblocktemplate

Hi,

Any method to bypass getblocktemplate rpc call to start pool? My pool for a coin don't have getblocktemplate in daemon (dev remove it).

Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.