text:
#include "darksend.h"
#include "main.h"
#include "init.h"

#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>

#include <algorithm>
#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost;

/** The main object for accessing darksend */
CDarkSendPool darkSendPool;
/** A helper object for signing messages from masternodes */
CDarkSendSigner darkSendSigner;
/** Object for who's going to get paid on which blocks */
CMasternodePayments masternodePayments;
/** The list of active masternodes */
std::vector<CMasterNode> darkSendMasterNodes;
/** All denominations used by darksend */
std::vector<int64> darkSendDenominations;
/** Which masternodes we're asked other clients for */
std::vector<CTxIn> vecMasternodeAskedFor;
/** The current darksends in progress on the network */
std::vector<CDarksendQueue> vecDarksendQueue;
// count peers we've requested the list from
int RequestedMasterNodeList = 0;

/* *** BEGIN DARKSEND MAGIC - DARKCOIN **********
    Copyright 2014, Darkcoin Developers
        eduffield - evan@darkcoin.io
*/

struct CompareValueOnly
{
    bool operator()(const pair<int64, CTxIn>& t1,
                    const pair<int64, CTxIn>& t2) const
    {
        return t1.first < t2.first;
    }
};

struct CompareValueOnly2
{
    bool operator()(const pair<int64, int>& t1,
                    const pair<int64, int>& t2) const
    {
        return t1.first < t2.first;
    }
};

int randomizeList (int i) { return std::rand()%i;}

void CDarkSendPool::SetNull(bool clearEverything){
    finalTransaction.vin.clear();
    finalTransaction.vout.clear();

    entries.clear();

    state = POOL_STATUS_ACCEPTING_ENTRIES;

    lastTimeChanged = GetTimeMillis();

    entriesCount = 0;
    lastEntryAccepted = 0;
    countEntriesAccepted = 0;

    sessionUsers = 0;
    sessionAmount = 0;
    sessionFoundMasternode = false;
    sessionTries = 0;
    vecSessionCollateral.clear();
    txCollateral = CTransaction();

    if(clearEverything){
        myEntries.clear();

        if(fMasterNode){
            sessionID = 1 + (rand() % 999999);
        } else {
            sessionID = 0;
        }
    }

    // -- seed random number generator (used for ordering output lists)
    unsigned int seed = 0;
    RAND_bytes((unsigned char*)&seed, sizeof(seed));
    std::srand(seed);
}

bool CDarkSendPool::SetCollateralAddress(std::string strAddress){
    CBitcoinAddress address;
    if (!address.SetString(strAddress))
    {
        LogPrintf("CDarkSendPool::SetCollateralAddress - Invalid DarkSend collateral address\n");
        return false;
    }
    collateralPubKey.SetDestination(address.Get());
    return true;
}

//
// Unlock coins after Darksend fails or succeeds
//
void CDarkSendPool::UnlockCoins(){
    BOOST_FOREACH(CTxIn v, lockedCoins)
        pwalletMain->UnlockCoin(v.prevout);

    lockedCoins.clear();
}

//
// Check the Darksend progress and send client updates if a masternode
//
void CDarkSendPool::Check()
{
    if(fDebug) LogPrintf("CDarkSendPool::Check()\n");
    if(fDebug) LogPrintf("CDarkSendPool::Check() - entries count %lu\n", entries.size());

    // If entries is full, then move on to the next phase
    if(state == POOL_STATUS_ACCEPTING_ENTRIES && entries.size() >= GetMaxPoolTransactions())
    {
        if(fDebug) LogPrintf("CDarkSendPool::Check() -- ACCEPTING OUTPUTS\n");
        UpdateState(POOL_STATUS_FINALIZE_TRANSACTION);
    }

    // create the finalized transaction for distribution to the clients
    if(state == POOL_STATUS_FINALIZE_TRANSACTION && finalTransaction.vin.empty() && finalTransaction.vout.empty()) {
        if(fDebug) LogPrintf("CDarkSendPool::Check() -- FINALIZE TRANSACTIONS\n");
        UpdateState(POOL_STATUS_SIGNING);

        if (fMasterNode) {
            // make our new transaction
            CTransaction txNew;
            for(unsigned int i = 0; i < entries.size(); i++){
                BOOST_FOREACH(const CTxOut v, entries[i].vout)
                    txNew.vout.push_back(v);

                BOOST_FOREACH(const CDarkSendEntryVin s, entries[i].sev)
                    txNew.vin.push_back(s.vin);
            }
            // shuffle the outputs for improved anonymity
            std::random_shuffle ( txNew.vout.begin(), txNew.vout.end(), randomizeList);

            if(fDebug) LogPrintf("Transaction 1: %s\n", txNew.ToString().c_str());

            SignFinalTransaction(txNew, NULL);

            // request signatures from clients
            RelayDarkSendFinalTransaction(sessionID, txNew);
        }
    }

    // collect signatures from clients

    // If we have all of the signatures, try to compile the transaction
    if(state == POOL_STATUS_SIGNING && SignaturesComplete()) {
        if(fDebug) LogPrintf("CDarkSendPool::Check() -- SIGNING\n");
        UpdateState(POOL_STATUS_TRANSMISSION);

        CWalletTx txNew = CWalletTx(pwalletMain, finalTransaction);

        LOCK2(cs_main, pwalletMain->cs_wallet);
        {
            if (fMasterNode) { //only the main node is master atm
                if(fDebug) LogPrintf("Transaction 2: %s\n", txNew.ToString().c_str());

                // See if the transaction is valid
                if (!txNew.AcceptToMemoryPool(true, false))
                {
                    LogPrintf("CDarkSendPool::Check() - CommitTransaction : Error: Transaction not valid\n");
                    SetNull();
                    pwalletMain->Lock();

                    // not much we can do in this case
                    UpdateState(POOL_STATUS_ACCEPTING_ENTRIES);
                    RelayDarkSendCompletedTransaction(sessionID, true, "Transaction not valid, please try again");
                    return;
                }

                LogPrintf("CDarkSendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND\n");

                // Broadcast the transaction to the network
                txNew.AddSupportingTransactions();
                txNew.fTimeReceivedIsTxTime = true;
                txNew.RelayWalletTransaction();

                // Tell the clients it was successful
                RelayDarkSendCompletedTransaction(sessionID, false, "Transaction Created Successfully");
            }
        }
    }

    // move on to next phase, allow 3 seconds incase the masternode wants to send us anything else
    if((state == POOL_STATUS_TRANSMISSION && fMasterNode) || (state == POOL_STATUS_SIGNING && completedTransaction) ) {
        LogPrintf("CDarkSendPool::Check() -- COMPLETED -- RESETTING \n");
        SetNull(true);
        UnlockCoins();
        if(fMasterNode) RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET);
        pwalletMain->Lock();
    }

    // reset if we're here for 10 seconds
    if((state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) && GetTimeMillis()-lastTimeChanged >= 10000) {
        LogPrintf("CDarkSendPool::Check() -- RESETTING MESSAGE \n");
        SetNull(true);
        if(fMasterNode) RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET);
        UnlockCoins();
    }
}

//
// Charge clients a fee if they're abusive
//
// Why bother? Darksend uses collateral to ensure abuse to the process is kept to a minimum.
// The submission and signing stages in darksend are completely separate. In the cases where
// a client submits a transaction then refused to sign, there must be a cost. Otherwise they
// would be able to do this over and over again and bring the mixing to a hault.
//
// How does this work? Messages to masternodes come in via "dsi", these require a valid collateral
// transaction for the client to be able to enter the pool. This transaction is kept by the masternode
// until the transaction is either complete or fails.
//
void CDarkSendPool::ChargeFees(){

    if(fMasterNode) {
        int i = 0;

        if(state == POOL_STATUS_ACCEPTING_ENTRIES){
            BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollateral) {
                bool found = false;
                BOOST_FOREACH(const CDarkSendEntry& v, entries) {
                    if(v.collateral == txCollateral) {
                        found = true;
                    }
                }

                // This queue entry didn't send us the promised transaction
                if(!found){
                    LogPrintf("CDarkSendPool::ChargeFees -- found uncooperative node (didn't send transaction). charging fees. %u\n", i);

                    CWalletTx wtxCollateral = CWalletTx(pwalletMain, txCollateral);

                    // Broadcast
                    if (!wtxCollateral.AcceptToMemoryPool(true, false))
                    {
                        // This must not fail. The transaction has already been signed and recorded.
                        LogPrintf("CDarkSendPool::ChargeFees() : Error: Transaction not valid");
                    }
                    wtxCollateral.RelayWalletTransaction();
                    i++;
                }
            }
        }

        if(state == POOL_STATUS_SIGNING) {
            // who didn't sign?
            BOOST_FOREACH(const CDarkSendEntry v, entries) {
                BOOST_FOREACH(const CDarkSendEntryVin s, v.sev) {
                    if(!s.isSigSet){
                        LogPrintf("CDarkSendPool::ChargeFees -- found uncooperative node (didn't sign). charging fees. %u\n", i);

                        CWalletTx wtxCollateral = CWalletTx(pwalletMain, v.collateral);

                        // Broadcast
                        if (!wtxCollateral.AcceptToMemoryPool(true, false))
                        {
                            // This must not fail. The transaction has already been signed and recorded.
                            LogPrintf("CDarkSendPool::ChargeFees() : Error: Transaction not valid");
                        }
                        wtxCollateral.RelayWalletTransaction();
                    }
                    i++;
                }
            }
        }
    }
}

//
// Check for various timeouts (queue objects, darksend, etc)
//
void CDarkSendPool::CheckTimeout(){
    // catching hanging sessions
    if(!fMasterNode) {
        if(state == POOL_STATUS_TRANSMISSION) {
            if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() -- Session complete -- Running Check()\n");
            Check();
        }
    }

    // check darksend queue objects for timeouts
    int c = 0;
    vector<CDarksendQueue>::iterator it;
    for(it=vecDarksendQueue.begin();it<vecDarksendQueue.end();it++){
        if((*it).IsExpired()){
            if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() : Removing expired queue entry - %d\n", c);
            vecDarksendQueue.erase(it);
            break;
        }
        c++;
    }

    /* Check to see if we're ready for submissions from clients */
    if(state == POOL_STATUS_QUEUE && sessionUsers == GetMaxPoolTransactions()) {
        CDarksendQueue dsq;
        dsq.nDenom = GetDenominationsByAmount(sessionAmount);
        dsq.vin = vinMasterNode;
        dsq.time = GetTime();
        dsq.ready = true;
        dsq.Sign();
        dsq.Relay();

        UpdateState(POOL_STATUS_ACCEPTING_ENTRIES);
    }

    int addLagTime = 0;
    if(!fMasterNode) addLagTime = 10000; //if we're the client, give the server a few extra seconds before resetting.

    if(state == POOL_STATUS_ACCEPTING_ENTRIES || state == POOL_STATUS_QUEUE){
        c = 0;

        // if it's a masternode, the entries are stored in "entries", otherwise they're stored in myEntries
        std::vector<CDarkSendEntry> *vec = &myEntries;
        if(fMasterNode) vec = &entries;

        // check for a timeout and reset if needed
        vector<CDarkSendEntry>::iterator it2;
        for(it2=vec->begin();it2<vec->end();it2++){
            if((*it2).IsExpired()){
                if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() : Removing expired entry - %d\n", c);
                vec->erase(it2);
                if(entries.size() == 0 && myEntries.size() == 0){
                    SetNull(true);
                    UnlockCoins();
                }
                if(fMasterNode){
                    RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET);
                }
                break;
            }
            c++;
        }

        if(GetTimeMillis()-lastTimeChanged >= 30000+addLagTime){
            lastTimeChanged = GetTimeMillis();

            ChargeFees();
            // reset session information for the queue query stage (before entering a masternode, clients will send a queue request to make sure they're compatible denomination wise)
            sessionUsers = 0;
            sessionAmount = 0;
            sessionFoundMasternode = false;
            sessionTries = 0;
            vecSessionCollateral.clear();

            UpdateState(POOL_STATUS_ACCEPTING_ENTRIES);
        }
    } else if(GetTimeMillis()-lastTimeChanged >= 30000+addLagTime){
        if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() -- Session timed out (30s) -- resetting\n");
        SetNull();
        UnlockCoins();

        UpdateState(POOL_STATUS_ERROR);
        lastMessage = "Session timed out (30), please resubmit";
    }

    if(state == POOL_STATUS_SIGNING && GetTimeMillis()-lastTimeChanged >= 10000+addLagTime ) {
        if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() -- Session timed out -- restting\n");
        ChargeFees();
        SetNull();
        UnlockCoins();
        //add my transactions to the new session

        UpdateState(POOL_STATUS_ERROR);
        lastMessage = "Signing timed out, please resubmit";
    }
}

// check to see if the signature is valid
bool CDarkSendPool::SignatureValid(const CScript& newSig, const CTxIn& newVin){
    CTransaction txNew;
    txNew.vin.clear();
    txNew.vout.clear();

    int found = -1;
    CScript sigPubKey = CScript();
    unsigned int i = 0;

    BOOST_FOREACH(CDarkSendEntry e, entries) {
        BOOST_FOREACH(const CTxOut out, e.vout)
            txNew.vout.push_back(out);

        BOOST_FOREACH(const CDarkSendEntryVin s, e.sev){
            txNew.vin.push_back(s.vin);

            if(s.vin == newVin){
                found = i;
                sigPubKey = s.vin.prevPubKey;
            }
            i++;
        }
    }

    if(found >= 0){ //might have to do this one input at a time?
        int n = found;
        txNew.vin[n].scriptSig = newSig;
        if(fDebug) LogPrintf("CDarkSendPool::SignatureValid() - Sign with sig %s\n", newSig.ToString().substr(0,24).c_str());
        if (!VerifyScript(txNew.vin[n].scriptSig, sigPubKey, txNew, n, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)){
            if(fDebug) LogPrintf("CDarkSendPool::SignatureValid() - Signing - Error signing input %u\n", n);
            return false;
        }
    }

    if(fDebug) LogPrintf("CDarkSendPool::SignatureValid() - Signing - Succesfully signed input\n");
    return true;
}

// check to make sure the collateral provided by the client is valid
bool CDarkSendPool::IsCollateralValid(const CTransaction& txCollateral){
    if(txCollateral.vout.size() < 1) return false;

    int64 nValueIn = 0;
    int64 nValueOut = 0;
    bool missingTx = false;

    CTransaction tx;
    BOOST_FOREACH(const CTxOut o, txCollateral.vout)
        nValueOut += o.nValue;

    BOOST_FOREACH(const CTxIn i, txCollateral.vin){
        CTransaction tx2;
        uint256 hash;
        if(GetTransaction(i.prevout.hash, tx2, hash, true)){
            if(tx2.vout.size() > i.prevout.n) {
                nValueIn += tx2.vout[i.prevout.n].nValue;
            }
        } else{
            missingTx = true;
        }
    }

    if(missingTx){
        if(fDebug) LogPrintf ("CDarkSendPool::IsCollateralValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString().c_str());
        return false;
    }

    //collateral transactions are required to pay out DARKSEND_COLLATERAL as a fee to the miners
    if(nValueIn-nValueOut < DARKSEND_COLLATERAL) {
        if(fDebug) LogPrintf ("CDarkSendPool::IsCollateralValid - did not include enough fees in transaction %"PRI64d"\n%s\n", nValueOut-nValueIn, txCollateral.ToString().c_str());
        return false;
    }

    LogPrintf("CDarkSendPool::IsCollateralValid %s\n", txCollateral.ToString().c_str());

    CWalletTx wtxCollateral = CWalletTx(pwalletMain, txCollateral);
    if (!wtxCollateral.IsAcceptable(true, false)){
        if(fDebug) LogPrintf ("CDarkSendPool::IsCollateralValid - didn't pass IsAcceptable\n");
        return false;
    }

    return true;
}

//
// Add a clients transaction to the pool
//
bool CDarkSendPool::AddEntry(const std::vector<CTxIn>& newInput, const int64& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, std::string& error){
    if (!fMasterNode) return false;

    BOOST_FOREACH(CTxIn in, newInput) {
        if (in.prevout.IsNull() || nAmount < 0) {
            if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - input not valid!\n");
            error = "input not valid";
            sessionUsers--;
            return false;
        }
    }

    if (!IsCollateralValid(txCollateral)){
        if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - collateral not valid!\n");
        error = "collateral not valid";
        sessionUsers--;
        return false;
    }

    if(entries.size() >= GetMaxPoolTransactions()){
        if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - entries is full!\n");
        error = "entries is full";
        sessionUsers--;
        return false;
    }

    BOOST_FOREACH(CTxIn in, newInput) {
        LogPrintf("looking for vin -- %s\n", in.ToString().c_str());
        BOOST_FOREACH(const CDarkSendEntry v, entries) {
            BOOST_FOREACH(const CDarkSendEntryVin s, v.sev){
                if(s.vin == in) {
                    if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - found in vin\n");
                    error = "already have that vin";
                    sessionUsers--;
                    return false;
                }
            }
        }
    }

    if(state == POOL_STATUS_ACCEPTING_ENTRIES) {
        CDarkSendEntry v;
        v.Add(newInput, nAmount, txCollateral, newOutput);
        entries.push_back(v);

        LogPrintf("CDarkSendPool::AddEntry -- adding %s\n", newInput[0].ToString().c_str());
        error = "";

        return true;
    }

    if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - can't accept new entry, wrong state!\n");
    error = "wrong state";
    sessionUsers--;
    return false;
}

bool CDarkSendPool::AddScriptSig(const CTxIn& newVin){
    if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- new sig  %s\n", newVin.scriptSig.ToString().substr(0,24).c_str());

    BOOST_FOREACH(const CDarkSendEntry v, entries) {
        BOOST_FOREACH(const CDarkSendEntryVin s, v.sev){
            if(s.vin.scriptSig == newVin.scriptSig) {
                LogPrintf("CDarkSendPool::AddScriptSig - already exists \n");
                return false;
            }
        }
    }

    if(!SignatureValid(newVin.scriptSig, newVin)){
        if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig - Invalid Sig\n");
        return false;
    }

    if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- sig %s\n", newVin.ToString().c_str());

    if(state == POOL_STATUS_SIGNING) {
        BOOST_FOREACH(CTxIn& vin, finalTransaction.vin){
            if(newVin.prevout == vin.prevout && vin.nSequence == newVin.nSequence){
                vin.scriptSig = newVin.scriptSig;
                vin.prevPubKey = newVin.prevPubKey;
                if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- adding to finalTransaction  %s\n", newVin.scriptSig.ToString().substr(0,24).c_str());
            }
        }
        for(unsigned int i = 0; i < entries.size(); i++){
            if(entries[i].AddSig(newVin)){
                if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- adding  %s\n", newVin.scriptSig.ToString().substr(0,24).c_str());
                return true;
            }
        }
    }

    LogPrintf("CDarkSendPool::AddScriptSig -- Couldn't set sig!\n" );
    return false;
}

// check to make sure everything is signed
bool CDarkSendPool::SignaturesComplete(){
    BOOST_FOREACH(const CDarkSendEntry v, entries) {
        BOOST_FOREACH(const CDarkSendEntryVin s, v.sev){
            if(!s.isSigSet) return false;
        }
    }
    return true;
}

//
// Execute a darksend denomination via a masternode.
// This is only ran from clients
//
void CDarkSendPool::SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout, int64& fee, int64 amount){
    if(darkSendPool.txCollateral == CTransaction()){
        LogPrintf ("CDarksendPool:SendDarksendDenominate() - Darksend collateral not set");
        return;
    }

    // lock the funds we're going to use
    BOOST_FOREACH(CTxIn in, txCollateral.vin)
        lockedCoins.push_back(in);

    BOOST_FOREACH(CTxIn in, vin)
        lockedCoins.push_back(in);

    // we should already be connected to a masternode
    if(!sessionFoundMasternode){
        LogPrintf("CDarkSendPool::SendDarksendDenominate() - No masternode has been selected yet.\n");
        UnlockCoins();
        SetNull(true);
        return;
    }

    if (!CheckDiskSpace())
        return;

    if(fMasterNode) {
        LogPrintf("CDarkSendPool::SendDarksendDenominate() - DarkSend from a masternode is not supported currently.\n");
        return;
    }

    UpdateState(POOL_STATUS_ACCEPTING_ENTRIES);

    LogPrintf("CDarkSendPool::SendDarksendDenominate() - Added transaction to pool.\n");

    ClearLastMessage();

    //check it against the memory pool to make sure it's valid
    {
        int64 nValueOut = 0;

        CValidationState state;
        CTransaction tx;

        BOOST_FOREACH(const CTxOut o, vout){
            nValueOut += o.nValue;
            tx.vout.push_back(o);
        }

        BOOST_FOREACH(const CTxIn i, vin){
            tx.vin.push_back(i);

            LogPrintf("dsi -- tx in %s\n", i.ToString().c_str());
        }

        bool missing = false;
        if (!tx.IsAcceptable(state, true, false, &missing, false)){ //AcceptableInputs(state, true)){
            LogPrintf("dsi -- transactione not valid! %s \n", tx.ToString().c_str());
            return;
        }

        printf("CDarksendPool::SendDarksendDenominate() - preparing transaction - \n %s\n", tx.ToString().c_str());
    }

    // store our entry for later use
    CDarkSendEntry e;
    e.Add(vin, amount, txCollateral, vout);
    myEntries.push_back(e);

    // relay our entry to the master node
    RelayDarkSendIn(vin, amount, txCollateral, vout);
    Check();
}

// Incoming message from masternode updating the progress of darksend
//    newAccepted:  -1 mean's it'n not a "transaction accepted/not accepted" message, just a standard update
//                  0 means transaction was not accepted
//                  1 means transaction was accepted

bool CDarkSendPool::StatusUpdate(int newState, int newEntriesCount, int newAccepted, std::string& error, int newSessionID){
    if(fMasterNode) return false;
    if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false;

    UpdateState(newState);
    entriesCount = newEntriesCount;

    if(newAccepted != -1) {
        lastEntryAccepted = newAccepted;
        countEntriesAccepted += newAccepted;
        if(newAccepted == 0){
            UpdateState(POOL_STATUS_ERROR);
            lastMessage = error;
        }

        if(newAccepted == 1) {
            sessionID = newSessionID;
            LogPrintf("CDarkSendPool::StatusUpdate - set sessionID to %d\n", sessionID);
            sessionFoundMasternode = true;
        }
    }

    if(newState == POOL_STATUS_ACCEPTING_ENTRIES){
        if(newAccepted == 1){
            LogPrintf("CDarkSendPool::StatusUpdate - entry accepted! \n");
            sessionFoundMasternode = true;
            //wait for other users. Masternode will report when ready
            UpdateState(POOL_STATUS_QUEUE);
        } else if (newAccepted == 0 && sessionID == 0 && !sessionFoundMasternode) {
            LogPrintf("CDarkSendPool::StatusUpdate - entry not accepted by masternode \n");
            UnlockCoins();
            DoAutomaticDenominating(); //try another masternode
        }
        if(sessionFoundMasternode) return true;
    }

    return true;
}

//
// After we receive the finalized transaction from the masternode, we must
// check it to make sure it's what we want, then sign it if we agree.
// If we refuse to sign, it's possible we'll be charged collateral
//
bool CDarkSendPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node){
    if(fDebug) LogPrintf("CDarkSendPool::AddFinalTransaction - Got Finalized Transaction\n");

    if(!finalTransaction.vin.empty()){
        LogPrintf("CDarkSendPool::AddFinalTransaction - Rejected Final Transaction!\n");
        return false;
    }

    finalTransaction = finalTransactionNew;
    LogPrintf("CDarkSendPool::SignFinalTransaction %s\n", finalTransaction.ToString().c_str());

    vector<CTxIn> sigs;

    //make sure my inputs/outputs are present, otherwise refuse to sign
    BOOST_FOREACH(const CDarkSendEntry e, myEntries) {
        BOOST_FOREACH(const CDarkSendEntryVin s, e.sev) {
            /* Sign my transaction and all outputs */
            int mine = -1;
            CScript prevPubKey = CScript();
            CTxIn vin = CTxIn();

            for(unsigned int i = 0; i < finalTransaction.vin.size(); i++){
                if(finalTransaction.vin[i] == s.vin){
                    mine = i;
                    prevPubKey = s.vin.prevPubKey;
                    vin = s.vin;
                }
            }

            if(mine >= 0){ //might have to do this one input at a time?
                int foundOutputs = 0;
                int64 nValue1 = 0;
                int64 nValue2 = 0;

                for(unsigned int i = 0; i < finalTransaction.vout.size(); i++){
                    BOOST_FOREACH(const CTxOut o, e.vout) {
                        if(finalTransaction.vout[i] == o){
                            foundOutputs++;
                            nValue1 += finalTransaction.vout[i].nValue;
                        }
                    }
                }

                BOOST_FOREACH(const CTxOut o, e.vout)
                    nValue2 += o.nValue;

                int targetOuputs = e.vout.size();
                if(foundOutputs < targetOuputs || nValue1 != nValue2) {
                    // in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's
                    // better then signing if the transaction doesn't look like what we wanted.
                    LogPrintf("CDarkSendPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n", foundOutputs, targetOuputs);
                    return false;
                }

                if(fDebug) LogPrintf("CDarkSendPool::Sign - Signing my input %i\n", mine);
                if(!SignSignature(*pwalletMain, prevPubKey, finalTransaction, mine, int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))) { // changes scriptSig
                    if(fDebug) LogPrintf("CDarkSendPool::Sign - Unable to sign my own transaction! \n");
                    // not sure what to do here, it will timeout...?
                }

                sigs.push_back(finalTransaction.vin[mine]);
                if(fDebug) LogPrintf(" -- dss %d %d %s\n", mine, (int)sigs.size(), finalTransaction.vin[mine].scriptSig.ToString().c_str());
            }

        }

        if(fDebug) LogPrintf("CDarkSendPool::Sign - txNew:\n%s", finalTransaction.ToString().c_str());
    }

    // push all of our signatures to the masternode
    if(sigs.size() > 0 && node != NULL)
        node->PushMessage("dss", sigs);

    return true;
}

// manage the masternode connections
void CDarkSendPool::ProcessMasternodeConnections(){
    LOCK(cs_vNodes);

    BOOST_FOREACH(CNode* pnode, vNodes)
    {
        //if it's our masternode, let it be
        if(submittedToMasternode == pnode->addr) continue;

        if(pnode->fDarkSendMaster){
            LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str());
            pnode->CloseSocketDisconnect();
        }
    }
}

bool CDarkSendPool::ConnectToBestMasterNode(int depth){
    if(fMasterNode) return false;

    int winner = GetCurrentMasterNode();
    LogPrintf("winner %d\n", winner);

    if(winner >= 0) {
        LogPrintf("CDarkSendPool::ConnectToBestMasterNode - Connecting to masternode at %s\n", darkSendMasterNodes[winner].addr.ToString().c_str());
        if(ConnectNode((CAddress)darkSendMasterNodes[winner].addr, NULL, true)){
            masterNodeAddr = darkSendMasterNodes[winner].addr.ToString();
            UpdateState(POOL_STATUS_ACCEPTING_ENTRIES);
            GetLastValidBlockHash(masterNodeBlockHash);
            return true;
        } else {
            darkSendMasterNodes[winner].enabled = 0;
            if(depth < 5){
                UpdateState(POOL_STATUS_ERROR);
                lastMessage = "Trying MasterNode #" + to_string(depth);
                return ConnectToBestMasterNode(depth+1);
            } else {
                UpdateState(POOL_STATUS_ERROR);
                lastMessage = "No valid MasterNode";
                LogPrintf("CDarkSendPool::ConnectToBestMasterNode - ERROR: %s\n", lastMessage.c_str());
            }
        }
    } else {
        UpdateState(POOL_STATUS_ERROR);
        lastMessage = "No valid MasterNode";
        LogPrintf("CDarkSendPool::ConnectToBestMasterNode - ERROR: %s\n", lastMessage.c_str());
    }

    //failed, so unlock any coins.
    UnlockCoins();

    //if couldn't connect, disable that one and try next
    return false;
}

bool CDarkSendPool::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey)
{
    int64 nValueIn = 0;
    CScript pubScript;

    // try once before we try to denominate
    if (!pwalletMain->SelectCoinsMasternode(vin, nValueIn, pubScript))
    {
        if(fDebug) LogPrintf("CDarkSendPool::GetMasterNodeVin - I'm not a capable masternode\n");
        return false;
    }

    CTxDestination address1;
    ExtractDestination(pubScript, address1);
    CBitcoinAddress address2(address1);

    CKeyID keyID;
    if (!address2.GetKeyID(keyID)) {
        LogPrintf("CDarkSendPool::GetMasterNodeVin - Address does not refer to a key");
        return false;
    }

    if (!pwalletMain->GetKey(keyID, secretKey)) {
        LogPrintf ("CDarkSendPool::GetMasterNodeVin - Private key for address is not known");
        return false;
    }

    pubkey = secretKey.GetPubKey();
    return true;
}

// when starting a masternode, this can enable to run as a hot wallet with no funds
bool CDarkSendPool::EnableHotColdMasterNode(CTxIn& vin, int64 sigTime, CService& addr)
{
    if(!fMasterNode) return false;

    isCapableMasterNode = MASTERNODE_IS_CAPABLE;

    vinMasterNode = vin;
    masterNodeSignatureTime = sigTime;
    masterNodeSignAddr = addr;

    LogPrintf("CDarkSendPool::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.");

    return true;
}

//
// Bootup the masternode, look for a 1000DRK input and register on the network
//
void CDarkSendPool::RegisterAsMasterNode(bool stop)
{
    if(!fMasterNode) return;

    //need correct adjusted time to send ping
    bool fIsInitialDownload = IsInitialBlockDownload();
    if(fIsInitialDownload) {
        isCapableMasterNode = MASTERNODE_SYNC_IN_PROCESS;
        LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Sync in progress. Must wait until sync is complete to start masternode.");
        return;
    }

    std::string errorMessage;

    CKey key2;
    CPubKey pubkey2;

    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
    {
        LogPrintf("Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
        exit(0);
    }

    if(isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW || isCapableMasterNode == MASTERNODE_NOT_CAPABLE || isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS){
        isCapableMasterNode = MASTERNODE_NOT_PROCESSED;
    }

    if(isCapableMasterNode == MASTERNODE_NOT_PROCESSED) {
        if(strMasterNodeAddr.empty()) {
            if(!GetLocal(masterNodeSignAddr)) {
                LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Can't detect external address. Please use the masternodeaddr configuration option.");
                isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
                return;
            }
        } else {
            masterNodeSignAddr = CService(strMasterNodeAddr);
        }

        if((fTestNet && masterNodeSignAddr.GetPort() != 19999) || (!fTestNet && masterNodeSignAddr.GetPort() != 9999)) {
            LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Invalid port");
            isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
            exit(0);
        }

        LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Checking inbound connection to '%s'\n", masterNodeSignAddr.ToString().c_str());

        if(ConnectNode((CAddress)masterNodeSignAddr, masterNodeSignAddr.ToString().c_str())){
            darkSendPool.masternodePortOpen = MASTERNODE_PORT_OPEN;
        } else {
            darkSendPool.masternodePortOpen = MASTERNODE_PORT_NOT_OPEN;
            isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
            return;
        }

        if(pwalletMain->IsLocked()){
            isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
            return;
        }

        isCapableMasterNode = MASTERNODE_NOT_CAPABLE;

        CKey SecretKey;
        // Choose coins to use
        if(GetMasterNodeVin(vinMasterNode, pubkeyMasterNode, SecretKey)) {

            if(GetInputAge(vinMasterNode) < MASTERNODE_MIN_CONFIRMATIONS){
                LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Input must have least %d confirmations - %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS, GetInputAge(vinMasterNode));
                isCapableMasterNode = MASTERNODE_INPUT_TOO_NEW;
                return;
            }

            masterNodeSignatureTime = GetAdjustedTime();

            std::string vchPubKey(pubkeyMasterNode.begin(), pubkeyMasterNode.end());
            std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
            std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + vchPubKey + vchPubKey2;

            if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, SecretKey)) {
                LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Sign message failed");
                return;
            }

            if(!darkSendSigner.VerifyMessage(pubkeyMasterNode, vchMasterNodeSignature, strMessage, errorMessage)) {
                LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Verify message failed");
                return;
            }

            LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Is capable master node!\n");

            isCapableMasterNode = MASTERNODE_IS_CAPABLE;

            pwalletMain->LockCoin(vinMasterNode.prevout);

            bool found = false;
            BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes)
                if(mn.vin == vinMasterNode)
                    found = true;

            if(!found) {
                LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Adding myself to masternode list %s - %s\n", masterNodeSignAddr.ToString().c_str(), vinMasterNode.ToString().c_str());
                CMasterNode mn(masterNodeSignAddr, vinMasterNode, pubkeyMasterNode, vchMasterNodeSignature, masterNodeSignatureTime, pubkey2);
                mn.UpdateLastSeen(masterNodeSignatureTime);
                darkSendMasterNodes.push_back(mn);
                LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Masternode input = %s\n", vinMasterNode.ToString().c_str());
            }

            RelayDarkSendElectionEntry(vinMasterNode, masterNodeSignAddr, vchMasterNodeSignature, masterNodeSignatureTime, pubkeyMasterNode, pubkey2, -1, -1, masterNodeSignatureTime);

            return;
        }
    }

    if(isCapableMasterNode != MASTERNODE_IS_CAPABLE) return;

    masterNodeSignatureTime = GetAdjustedTime();

    std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + boost::lexical_cast<std::string>(stop);

    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) {
        LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Sign message failed");
        return;
    }

    if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
        LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Verify message failed");
        return;
    }

    bool found = false;
    BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
        //LogPrintf(" -- %s\n", mn.vin.ToString().c_str());

        if(mn.vin == vinMasterNode) {
            found = true;
            mn.UpdateLastSeen();
        }
    }
    assert(found);

    LogPrintf("CDarkSendPool::RegisterAsMasterNode() - Masternode input = %s\n", vinMasterNode.ToString().c_str());

    if (stop) isCapableMasterNode = MASTERNODE_STOPPED;

    RelayDarkSendElectionEntryPing(vinMasterNode, vchMasterNodeSignature, masterNodeSignatureTime, stop);
}

bool CDarkSendPool::GetBlockHash(uint256& hash, int nBlockHeight)
{
    if(unitTest){
        hash.SetHex("00000000001432b4910722303bff579d0445fa23325bdc34538bdb226718ba79");
        return true;
    }

    const CBlockIndex *BlockLastSolved = pindexBest;
    const CBlockIndex *BlockReading = pindexBest;

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0) { return false; }

    //printf(" nBlockHeight2 %"PRI64u" %"PRI64u"\n", nBlockHeight, pindexBest->nHeight+1);

    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if(BlockReading->nHeight == nBlockHeight) {
            hash = BlockReading->GetBlockHash();
            return true;
        }

        if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
        BlockReading = BlockReading->pprev;
    }

    return false;
}

//Get the last hash that matches the modulus given. Processed in reverse order
bool CDarkSendPool::GetLastValidBlockHash(uint256& hash, int mod, int nBlockHeight)
{
    if(unitTest){
        hash.SetHex("00000000001432b4910722303bff579d0445fa23325bdc34538bdb226718ba79");
        return true;
    }

    const CBlockIndex *BlockLastSolved = pindexBest;
    const CBlockIndex *BlockReading = pindexBest;

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0) { return false; }

    int nBlocksAgo = 0;
    if(nBlockHeight > 0) nBlocksAgo = nBlockHeight - (pindexBest->nHeight+1);
    assert(nBlocksAgo >= 0);

    int n = 0;
    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if(BlockReading->nHeight % mod == 0) {
            if(n >= nBlocksAgo){
                hash = BlockReading->GetBlockHash();
                return true;
            }
            n++;
        }

        if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
        BlockReading = BlockReading->pprev;
    }

    return false;
}

void CDarkSendPool::NewBlock()
{
    if(fDebug) LogPrintf("CDarkSendPool::NewBlock \n");

    if(IsInitialBlockDownload()) return;

    masternodePayments.ProcessBlock(pindexBest->nHeight+10);

    if(!fEnableDarksend) return;

    if(!fMasterNode){
        //denominate all non-denominated inputs every 25 minutes.
        if(pindexBest->nHeight % 10 == 0) UnlockCoins();
        ProcessMasternodeConnections();
    }
}

// Darksend transaction was completed (failed or successed)
void CDarkSendPool::CompletedTransaction(bool error, std::string lastMessageNew)
{
    if(fMasterNode) return;

    if(error){
        LogPrintf("CompletedTransaction -- error \n");
        UpdateState(POOL_STATUS_ERROR);
    } else {
        LogPrintf("CompletedTransaction -- success \n");
        UpdateState(POOL_STATUS_SUCCESS);

        myEntries.clear();

        // To avoid race conditions, we'll only let DS run once per block
        cachedLastSuccess = nBestHeight;
        splitUpInARow = 0;
    }
    lastMessage = lastMessageNew;

    completedTransaction = true;
    Check();
    UnlockCoins();
}

void CDarkSendPool::ClearLastMessage()
{
    lastMessage = "";
}

//
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is to
// the proof of work for that block. The further away they are the better, the furthest will win the election
// and get paid this block
//
uint256 CMasterNode::CalculateScore(int mod, int64 nBlockHeight)
{
    if(pindexBest == NULL) return 0;

    uint256 n1 = 0;
    if(!darkSendPool.GetLastValidBlockHash(n1, mod, nBlockHeight)) return 0;

    uint256 n2 = Hash9(BEGIN(n1), END(n1));
    uint256 n3 = vin.prevout.hash > n2 ? (vin.prevout.hash - n2) : (n2 - vin.prevout.hash);

    /*
    LogPrintf(" -- MasterNode CalculateScore() n1 = %s \n", n1.ToString().c_str());
    LogPrintf(" -- MasterNode CalculateScore() n11 = %u \n", n11);
    LogPrintf(" -- MasterNode CalculateScore() n2 = %s \n", n2.ToString().c_str());
    LogPrintf(" -- MasterNode CalculateScore() vin = %s \n", vin.prevout.hash.ToString().c_str());
    LogPrintf(" -- MasterNode CalculateScore() n3 = %s \n", n3.ToString().c_str());*/

    return n3;
}

int CDarkSendPool::GetMasternodeByVin(CTxIn& vin)
{
    int i = 0;

    BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
        if (mn.vin == vin) return i;
        i++;
    }

    return -1;
}

int CDarkSendPool::GetCurrentMasterNode(int mod, int64 nBlockHeight)
{
    int i = 0;
    unsigned int score = 0;
    int winner = -1;

    // scan for winner
    BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
        mn.Check();
        if(!mn.IsEnabled()) {
            i++;
            continue;
        }

        // calculate the score for each masternode
        uint256 n = mn.CalculateScore(mod, nBlockHeight);
        unsigned int n2 = 0;
        memcpy(&n2, &n, sizeof(n2));

        // determine the winner
        if(n2 > score){
            score = n2;
            winner = i;
        }
        i++;
    }

    return winner;
}

bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner)
{
    std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight);
    std::string strPubKey = fTestNet? strTestPubKey : strMainPubKey;
    CPubKey pubkey(ParseHex(strPubKey));

    std::string errorMessage = "";
    if(!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage)){
        return false;
    }

    return true;
}

bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner)
{
    std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight);

    CKey key2;
    CPubKey pubkey2;
    std::string errorMessage = "";

    if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
    {
        LogPrintf("Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
        exit(0);
    }

    if(!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2)) {
        LogPrintf("CDarksendQueue():Relay - Sign message failed");
        return false;
    }

    if(!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage)) {
        LogPrintf("CDarksendQueue():Relay - Verify message failed");
        return false;
    }

    return true;
}

uint64 CMasternodePayments::CalculateScore(uint256 blockHash, CTxIn& vin)
{
    uint256 n1 = blockHash;
    uint256 n2 = Hash9(BEGIN(n1), END(n1));
    uint256 n3 = Hash9(BEGIN(vin.prevout.hash), END(vin.prevout.hash));
    uint256 n4 = n3 > n2 ? (n3 - n2) : (n2 - n3);

    //printf(" -- CMasternodePayments CalculateScore() n2 = %"PRI64u" \n", n2.Get64());
    //printf(" -- CMasternodePayments CalculateScore() n3 = %"PRI64u" \n", n3.Get64());
    //printf(" -- CMasternodePayments CalculateScore() n4 = %"PRI64u" \n", n4.Get64());

    return n4.Get64();
}

bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
{
    BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
        if(winner.nBlockHeight == nBlockHeight) {

            CTransaction tx;
            uint256 hash;
            if(GetTransaction(winner.vin.prevout.hash, tx, hash, true)){
                BOOST_FOREACH(CTxOut out, tx.vout){
                    if(out.nValue == 1000*COIN){
                        payee = out.scriptPubKey;
                        return true;
                    }
                }
            }

            return false;
        }
    }

    return false;
}

bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut)
{
    BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
        if(winner.nBlockHeight == nBlockHeight) {
            vinOut = winner.vin;
            return true;
        }
    }

    return false;
}

bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{
    uint256 blockHash = 0;
    if(!darkSendPool.GetBlockHash(blockHash, winnerIn.nBlockHeight-576)) {
        return false;
    }

    winnerIn.score = CalculateScore(blockHash, winnerIn.vin);

    bool foundBlock = false;
    BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
        if(winner.nBlockHeight == winnerIn.nBlockHeight) {
            foundBlock = true;
            if(winner.score < winnerIn.score){
                winner.score = winnerIn.score;
                winner.vin = winnerIn.vin;
                winner.vchSig = winnerIn.vchSig;
                return true;
            }
        }
    }

    // if it's not in the vector
    if(!foundBlock){
         vWinning.push_back(winnerIn);
         return true;
    }

    return false;
}

void CMasternodePayments::CleanPaymentList()
{
    if(pindexBest == NULL) return;

    vector<CMasternodePaymentWinner>::iterator it;
    for(it=vWinning.begin();it<vWinning.end();it++){
        if(pindexBest->nHeight - (*it).nBlockHeight > 4){
            if(fDebug) LogPrintf("Removing old masternode payment - block %d\n", (*it).nBlockHeight);
            vWinning.erase(it);
            break;
        }
    }
}

int CMasternodePayments::LastPayment(CTxIn& vin)
{
    if(pindexBest == NULL) return 0;

    int ret = GetInputAge(vin);

    BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
        if(winner.vin == vin && pindexBest->nHeight - winner.nBlockHeight < ret)
            ret = pindexBest->nHeight - winner.nBlockHeight;
    }

    return ret;
}

bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{
    if(strMasterPrivKey.empty()) return false;
    CMasternodePaymentWinner winner;

    uint256 blockHash = 0;
    if(!darkSendPool.GetBlockHash(blockHash, nBlockHeight-576)) return false;

    BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
        if(LastPayment(mn.vin) < darkSendMasterNodes.size()*.9) continue;

        uint64 score = CalculateScore(blockHash, mn.vin);
        if(score > winner.score){
            winner.score = score;
            winner.nBlockHeight = nBlockHeight;
            winner.vin = mn.vin;
        }
    }

    if(winner.nBlockHeight == 0) return false; //no masternodes available

    if(Sign(winner)){
        if(AddWinningMasternode(winner)){
            Relay(winner);
            return true;
        }
    }

    return false;
}

void CMasternodePayments::Relay(CMasternodePaymentWinner& winner)
{
    LOCK(cs_vNodes);
    BOOST_FOREACH(CNode* pnode, vNodes)
        pnode->PushMessage("mnw", winner);
}

void CMasternodePayments::Sync(CNode* node)
{
    BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning)
        if(winner.nBlockHeight >= pindexBest->nHeight-10 && winner.nBlockHeight <= pindexBest->nHeight + 20)
            node->PushMessage("mnw", winner);
}

bool CMasternodePayments::SetPrivKey(std::string strPrivKey)
{
    CMasternodePaymentWinner winner;

    // Test signing successful, proceed
    strMasterPrivKey = strPrivKey;

    Sign(winner);

    if(CheckSignature(winner)){
        LogPrintf("Successfully initialized as masternode payments master\n");
        return true;
    } else {
        return false;
    }
}

//
// Passively run Darksend in the background to anonymize funds based on the given configuration.
//
// This does NOT run by default for daemons, only for QT.
//
bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready)
{
    if(fMasterNode) return false;
    if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false;

    if(nBestHeight == cachedLastSuccess) {
        LogPrintf("CDarkSendPool::DoAutomaticDenominating - Last successful ds+ was too recent\n");
        return false;
    }
    if(!fEnableDarksend) {
        LogPrintf("CDarkSendPool::DoAutomaticDenominating - Darksend is disabled\n");
        return false;
    }

    if (!fDryRun && pwalletMain->IsLocked()){
        return false;
    }

    if(darkSendPool.GetState() != POOL_STATUS_ERROR && darkSendPool.GetState() != POOL_STATUS_SUCCESS){
        if(darkSendPool.GetMyTransactionCount() > 0){
            return true;
        }
    }

    // ** find the coins we'll use
    std::vector<CTxIn> vCoins;
    int64 nValueMin = 0.01*COIN;
    int64 nValueMax = 999*COIN;
    int64 nValueIn = 0;
    int minRounds = -2; //non denominated funds are rounds of less than 0
    int maxAmount = 1000;
    bool hasFeeInput = false;

    // if we have more denominated funds (of any maturity) than the nAnonymizeDarkcoinAmount, we should use use those
    if(pwalletMain->GetDenominatedBalance(true) >= nAnonymizeDarkcoinAmount*COIN) {
        minRounds = 0;
    }
    //if we're set to less than a thousand, don't submit for than that to the pool
    if(nAnonymizeDarkcoinAmount < 1000) maxAmount = nAnonymizeDarkcoinAmount;

    int64 balanceNeedsAnonymized = pwalletMain->GetBalance() - pwalletMain->GetAnonymizedBalance();
    if(balanceNeedsAnonymized > maxAmount*COIN) balanceNeedsAnonymized= maxAmount*COIN;
    if(balanceNeedsAnonymized < COIN*2.5){
        LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating \n");
        return false;
    }

    // if the balance is more the pool max, take the pool max
    if(balanceNeedsAnonymized > nValueMax) balanceNeedsAnonymized = nValueMax;

    // select coins that should be given to the pool
    if (!pwalletMain->SelectCoinsDark(nValueMin, maxAmount*COIN, vCoins, nValueIn, minRounds, nDarksendRounds, hasFeeInput))
    {
        nValueIn = 0;
        vCoins.clear();

        // look for inputs larger than the max amount, if we find anything we need to split it up
        if (pwalletMain->SelectCoinsDark(maxAmount*COIN, 9999999*COIN, vCoins, nValueIn, minRounds, nDarksendRounds, hasFeeInput))
        {
            if(!fDryRun) SplitUpMoney();
            return true;
        }

        LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating (2)\n");
        return false;
    }

    // the darksend pool can only take 1.1DRK minimum
    if(nValueIn < COIN*1.1){
        //simply look for non-denominated coins
        if (pwalletMain->SelectCoinsDark(maxAmount*COIN, 9999999*COIN, vCoins, nValueIn, minRounds, nDarksendRounds, hasFeeInput))
        {
            if(!fDryRun) SplitUpMoney();
            return true;
        }

        LogPrintf("DoAutomaticDenominating : Too little to denominate (must have 1.1DRK) \n");
        return false;
    }

    //check to see if we have the fee sized inputs, it requires these
    if(!pwalletMain->HasDarksendFeeInputs()){
        if(!fDryRun) SplitUpMoney(true);
        return true;
    }

    if(fDryRun) return true;

    // initial phase, find a masternode
    if(!sessionFoundMasternode){
        int64 nTotalValue = pwalletMain->GetTotalValue(vCoins) - DARKSEND_FEE;
        if(nTotalValue > maxAmount*COIN) nTotalValue = maxAmount*COIN;

        double fDarkcoinSubmitted = nTotalValue / COIN;

        LogPrintf("Submiting Darksend for %f DRK\n", fDarkcoinSubmitted);

        if(pwalletMain->GetDenominatedBalance(true, true) > 0){ //get denominated unconfirmed inputs
            LogPrintf("DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n");
            return false;
        }

        // Look through the queues and see if anything matches
        BOOST_FOREACH(CDarksendQueue& dsq, vecDarksendQueue){
            CService addr;
            if(dsq.time == 0) continue;
            if(!dsq.GetAddress(addr)) continue;

            // If we don't match the denominations, we don't want to submit our inputs
            if(dsq.nDenom != GetDenominationsByAmount(nTotalValue)) {
                if(fDebug) LogPrintf(" dsq.nDenom != GetDenominationsByAmount %"PRI64d" %d \n", dsq.nDenom, GetDenominationsByAmount(nTotalValue));
                continue;
            }
            dsq.time = 0; //remove node

            // connect to masternode and submit the queue request
            if(ConnectNode((CAddress)addr, NULL, true)){
                submittedToMasternode = addr;
                LOCK(cs_vNodes);
                BOOST_FOREACH(CNode* pnode, vNodes)
                {
                    if(submittedToMasternode != pnode->addr) continue;

                    std::string strReason;
                    if(txCollateral == CTransaction()){
                        if(!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)){
                            LogPrintf("DoAutomaticDenominating -- dsa error:%s\n", strReason.c_str());
                            return false;
                        }
                    }

                    sessionAmount = nTotalValue;
                    pnode->PushMessage("dsa", nTotalValue, txCollateral);
                    LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for %"PRI64d" - denom %d\n", nTotalValue, GetDenominationsByAmount(nTotalValue));
                    return true;
                }
            } else {
                LogPrintf("DoAutomaticDenominating --- error connecting \n");
                return DoAutomaticDenominating();
            }
        }

        // otherwise, try one randomly
        if(sessionTries++ < 10){
            //pick a random masternode to use
            int max_value = darkSendMasterNodes.size();
            if(max_value <= 0) return false;
            int i = (rand() % max_value);

            lastTimeChanged = GetTimeMillis();
            LogPrintf("DoAutomaticDenominating -- attempt %d connection to masternode %s\n", sessionTries, darkSendMasterNodes[i].addr.ToString().c_str());
            if(ConnectNode((CAddress)darkSendMasterNodes[i].addr, NULL, true)){
                submittedToMasternode = darkSendMasterNodes[i].addr;
                LOCK(cs_vNodes);
                BOOST_FOREACH(CNode* pnode, vNodes)
                {
                    if(darkSendMasterNodes[i].addr != pnode->addr) continue;

                    std::string strReason;
                    if(txCollateral == CTransaction()){
                        if(!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)){
                            LogPrintf("DoAutomaticDenominating -- dsa error:%s\n", strReason.c_str());
                            return false;
                        }
                    }

                    sessionAmount = nTotalValue;
                    pnode->PushMessage("dsa", nTotalValue, txCollateral);
                    LogPrintf("DoAutomaticDenominating --- connected, sending dsa for %"PRI64d" - denom %d\n", nTotalValue, GetDenominationsByAmount(nTotalValue));
                    return true;
                }
            } else {
                LogPrintf("DoAutomaticDenominating --- error connecting \n");
                return DoAutomaticDenominating();
            }
        } else {
            return false;
        }
    }

    if(!ready) return true;
    if(sessionAmount == 0) return true;

    // Submit transaction to the pool if we get here, use sessionAmount so we use the same amount of money
    std::string strError = pwalletMain->PrepareDarksendDenominate(minRounds, sessionAmount);
    LogPrintf("DoAutomaticDenominating : Running darksend denominate. Return '%s'\n", strError.c_str());

    if(strError == "") return true;

    LogPrintf("DoAutomaticDenominating : Error running denominate, %s\n", strError.c_str());
    return false;
}

// Split up large inputs or create fee sized inputs
bool CDarkSendPool::SplitUpMoney(bool justCollateral)
{
    if((nBestHeight - lastSplitUpBlock) < 10){
        LogPrintf("SplitUpMoney - Too soon to split up again\n");
        return false;
    }

    if(splitUpInARow >= 2){
        LogPrintf("Error: Darksend SplitUpMoney was called multiple times in a row. This should not happen. Please submit a detailed explanation of the steps it took to create this error and submit to evan@darkcoin.io. \n");
        fEnableDarksend = false;
        return false;
    }

    int64 nTotalBalance = pwalletMain->GetDenominatedBalance(false);
    if(justCollateral && nTotalBalance > 1*COIN) nTotalBalance = 1*COIN;
    int64 nTotalOut = 0;
    lastSplitUpBlock = nBestHeight;

    LogPrintf("DoAutomaticDenominating: Split up large input (justCollateral %d):\n", justCollateral);
    LogPrintf(" -- nTotalBalance %"PRI64d"\n", nTotalBalance);
    LogPrintf(" -- denom %"PRI64d" \n", pwalletMain->GetDenominatedBalance(false));

    // make our change address
    CReserveKey reservekey(pwalletMain);

    CScript scriptChange;
    CPubKey vchPubKey;
    assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
    scriptChange.SetDestination(vchPubKey.GetID());

    CWalletTx wtx;
    int64 nFeeRet = 0;
    std::string strFail = "";
    vector< pair<CScript, int64> > vecSend;

    int64 a = 1*COIN;

    // ****** Add fees ************ /
    vecSend.push_back(make_pair(scriptChange, (DARKSEND_COLLATERAL*5)+DARKSEND_FEE));
    nTotalOut += (DARKSEND_COLLATERAL*5)+DARKSEND_FEE;

    for(int d = 0; d <= 4+nDarksendRounds; d++){
        vecSend.push_back(make_pair(scriptChange, DARKSEND_FEE));
        nTotalOut += DARKSEND_FEE;
    }

    // ****** Add outputs in bases of two from 1 darkcoin *** /
    if(!justCollateral){
        bool continuing = true;

        while(continuing){
            if(nTotalOut + a < nTotalBalance-DARKSEND_FEE){
                //LogPrintf(" nTotalOut %"PRI64d", added %"PRI64d"\n", nTotalOut, a);

                vecSend.push_back(make_pair(scriptChange, a));
                nTotalOut += a;
            } else {
                continuing = false;
            }

            a = a * 2;
        }
    }

    if((justCollateral && nTotalOut <= 0.1*COIN) || vecSend.size() < 3) {
        LogPrintf("SplitUpMoney: Not enough outputs to make a transaction\n");
        return false;
    }
    if((!justCollateral && nTotalOut <= 1.1*COIN) || vecSend.size() < 3){
        LogPrintf("SplitUpMoney: Not enough outputs to make a transaction\n");
        return false;
    }

    CCoinControl *coinControl=NULL;
    bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRet, strFail, coinControl, ONLY_NONDENOMINATED);
    if(!success){
        LogPrintf("SplitUpMoney: Error - %s\n", strFail.c_str());
        return false;
    }

    pwalletMain->CommitTransaction(wtx, reservekey);

    LogPrintf("SplitUpMoney Success: tx %s\n", wtx.GetHash().GetHex().c_str());

    splitUpInARow++;
    return true;
}

int CDarkSendPool::GetMasternodeByRank(int findRank)
{
    int i = 0;

    std::vector<pair<unsigned int, int> > vecMasternodeScores;

    i = 0;
    BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
        mn.Check();
        if(!mn.IsEnabled()) {
            i++;
            continue;
        }

        uint256 n = mn.CalculateScore();
        unsigned int n2 = 0;
        memcpy(&n2, &n, sizeof(n2));

        vecMasternodeScores.push_back(make_pair(n2, i));
        i++;
    }

    sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly2());

    int rank = 0;
    BOOST_FOREACH (PAIRTYPE(unsigned int, int)& s, vecMasternodeScores){
        rank++;
        if(rank == findRank) return s.second;
    }

    return -1;
}

int CDarkSendPool::GetMasternodeRank(CTxIn& vin, int mod)
{
    std::vector<pair<unsigned int, CTxIn> > vecMasternodeScores;

    BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
        mn.Check();
        if(!mn.IsEnabled()) {
            continue;
        }

        uint256 n = mn.CalculateScore(mod);
        unsigned int n2 = 0;
        memcpy(&n2, &n, sizeof(n2));

        vecMasternodeScores.push_back(make_pair(n2, mn.vin));
    }

    sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly());

    unsigned int rank = 0;
    BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){
        rank++;
        if(s.second == vin) return rank;
    }

    return -1;
}

// Recursively determine the rounds of a given input (How deep is the darksend chain for a given input)
int CDarkSendPool::GetInputDarksendRounds(CTxIn in, int rounds)
{
    if(rounds >= 9) return rounds;

    std::string padding = "";
    padding.insert(0, ((rounds+1)*5)+3, ' ');

    CWalletTx tx;
    if(pwalletMain->GetTransaction(in.prevout.hash,tx)){
        // bounds check
        if(in.prevout.n >= tx.vout.size()) return -4;

        if(tx.vout[in.prevout.n].nValue == DARKSEND_FEE) return -3;

        if(rounds == 0){ //make sure the final output is non-denominate
            bool found = false;
            BOOST_FOREACH(int64 d, darkSendDenominations)
                if(tx.vout[in.prevout.n].nValue == d) found = true;

            if(!found) {
                //LogPrintf(" - NOT DENOM\n");
                return -2;
            }
        }
        bool found = false;

        BOOST_FOREACH(CTxOut out, tx.vout){
            BOOST_FOREACH(int64 d, darkSendDenominations)
                if(out.nValue == d)
                    found = true;
        }

        if(!found) {
            //LogPrintf(" - NOT FOUND\n");
            return rounds;
        }

        // find my vin and look that up
        BOOST_FOREACH(CTxIn in2, tx.vin) {
            if(pwalletMain->IsMine(in2)){
                //LogPrintf("rounds :: %s %s %d NEXT\n", padding.c_str(), in.ToString().c_str(), rounds);
                int n = GetInputDarksendRounds(in2, rounds+1);
                if(n != -3) return n;
            }
        }
    } else {
        //LogPrintf("rounds :: %s %s %d NOTFOUND\n", padding.c_str(), in.ToString().c_str(), rounds);
    }

    return rounds-1;
}

void CMasterNode::Check()
{
    //once spent, stop doing the checks
    if(enabled==3) return;

    if(!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS)){
        enabled = 4;
        return;
    }

    if(!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS)){
        enabled = 2;
        return;
    }

    if(!unitTest){
        CValidationState state;
        CTransaction tx = CTransaction();
        CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
        tx.vin.push_back(vin);
        tx.vout.push_back(vout);

        if(!tx.AcceptableInputs(state, true)) {
            enabled = 3;
            return;
        }
    }

    enabled = 1; // OK
}

bool CDarkSendPool::IsCompatibleWithEntries(std::vector<CTxOut> vout)
{
    BOOST_FOREACH(const CDarkSendEntry v, entries) {
        LogPrintf(" IsCompatibleWithEntries %d %d\n", GetDenominations(vout), GetDenominations(v.vout));

        BOOST_FOREACH(CTxOut o1, vout)
            LogPrintf(" vout 1 - %s\n", o1.ToString().c_str());

        BOOST_FOREACH(CTxOut o2, v.vout)
            LogPrintf(" vout 2 - %s\n", o2.ToString().c_str());

        if(GetDenominations(vout) != GetDenominations(v.vout)) return false;
    }

    return true;
}

bool CDarkSendPool::IsCompatibleWithSession(int64 nAmount, CTransaction txCollateral, std::string& strReason)
{
    LogPrintf("CDarkSendPool::IsCompatibleWithSession - sessionAmount %"PRI64d" sessionUsers %d\n", sessionAmount, sessionUsers);

    if (!unitTest && !IsCollateralValid(txCollateral)){
        if(fDebug) LogPrintf ("CDarkSendPool::IsCompatibleWithSession - collateral not valid!\n");
        strReason = "collateral not valid";
        return false;
    }

    if(sessionUsers < 0) sessionUsers = 0;

    if(sessionAmount == 0) {
        sessionAmount = nAmount;
        sessionUsers++;
        lastTimeChanged = GetTimeMillis();
        entries.clear();

        if(!unitTest){
            //broadcast that I'm accepting entries, only if it's the first entry though
            CDarksendQueue dsq;
            dsq.nDenom = GetDenominationsByAmount(nAmount);
            dsq.vin = vinMasterNode;
            dsq.time = GetTime();
            dsq.Sign();
            dsq.Relay();
        }

        UpdateState(POOL_STATUS_QUEUE);
        vecSessionCollateral.push_back(txCollateral);
        return true;
    }

    if((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE) || sessionUsers >= GetMaxPoolTransactions()){
        if((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE)) strReason = "incompatible mode";
        if(sessionUsers >= GetMaxPoolTransactions()) strReason = "masternode queue is full";
        LogPrintf("CDarkSendPool::IsCompatibleWithSession - incompatible mode, return false %d %d\n", state != POOL_STATUS_ACCEPTING_ENTRIES, sessionUsers >= GetMaxPoolTransactions());
        return false;
    }

    if(GetDenominationsByAmount(nAmount) != GetDenominationsByAmount(sessionAmount)) {
        strReason = "no matching denominations found for mixing";
        return false;
    }

    LogPrintf("CDarkSendPool::IsCompatibleWithSession - compatible\n");

    sessionUsers++;
    lastTimeChanged = GetTimeMillis();
    vecSessionCollateral.push_back(txCollateral);

    return true;
}

// return a bitshifted integer representing the denominations in this list
int CDarkSendPool::GetDenominations(const std::vector<CTxOut>& vout){
    std::vector<pair<int64, int> > denomUsed;

    // make a list of denominations, with zero uses
    BOOST_FOREACH(int64 d, darkSendDenominations)
        denomUsed.push_back(make_pair(d, 0));

    // look for denominations and update uses to 1
    BOOST_FOREACH(CTxOut out, vout)
        BOOST_FOREACH (PAIRTYPE(int64, int)& s, denomUsed)
            if (out.nValue == s.first)
                s.second = 1;

    int denom = 0;
    int c = 0;
    // if the denomination is used, shift the bit on.
    // then move to the next
    BOOST_FOREACH (PAIRTYPE(int64, int)& s, denomUsed)
        denom |= s.second << c++;

    // Function returns as follows:
    //
    // bit 0 - 500DRK+1 ( bit on if present )
    // bit 1 - 100DRK+1
    // bit 2 - 10DRK+1
    // bit 3 - 1DRK+1
    //
    //

    return denom;
}

// calculate the outputs from a given amount of darkcoin and
// return the bitshifted integer to represent them
int CDarkSendPool::GetDenominationsByAmount(int64 nAmount){
    CScript e = CScript();
    int64 nValueLeft = nAmount;

    std::vector<CTxOut> vout1;
    BOOST_FOREACH(int64 v, darkSendDenominations){
        int nOutputs = 0;
        while(nValueLeft - v >= 0 && nOutputs <= 10) {
            CTxOut o(v, e);
            vout1.push_back(o);
            nValueLeft -= v;
            nOutputs++;
        }
    }

    return GetDenominations(vout1);
}

bool CDarkSendSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey){
    CScript payee2;
    payee2.SetDestination(pubkey.GetID());

    CTransaction txVin;
    uint256 hash;
    if(GetTransaction(vin.prevout.hash, txVin, hash, true)){
        BOOST_FOREACH(CTxOut out, txVin.vout){
            if(out.nValue == 1000*COIN){
                if(out.scriptPubKey == payee2) return true;
            }
        }
    }

    return false;
}

bool CDarkSendSigner::SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey){
    CBitcoinSecret vchSecret;
    bool fGood = vchSecret.SetString(strSecret);

    if (!fGood) {
        errorMessage = "Invalid private key";
        return false;
    }

    key = vchSecret.GetKey();
    pubkey = key.GetPubKey();

    return true;
}

bool CDarkSendSigner::SignMessage(std::string strMessage, std::string& errorMessage, vector<unsigned char>& vchSig, CKey key)
{
    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    if (!key.SignCompact(ss.GetHash(), vchSig)) {
        errorMessage = "Sign failed";
        return false;
    }

    return true;
}

bool CDarkSendSigner::VerifyMessage(CPubKey pubkey, vector<unsigned char>& vchSig, std::string strMessage, std::string& errorMessage)
{
    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey2;
    if (!pubkey2.RecoverCompact(ss.GetHash(), vchSig)) {
        errorMessage = "Error recovering pubkey";
        return false;
    }

    return (pubkey2.GetID() == pubkey.GetID());
}

bool CDarksendQueue::Sign()
{
    if(!fMasterNode) return false;

    std::string strMessage = vin.ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(time) + boost::lexical_cast<std::string>(ready);

    CKey key2;
    CPubKey pubkey2;
    std::string errorMessage = "";

    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
    {
        LogPrintf("Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
        exit(0);
    }

    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, key2)) {
        LogPrintf("CDarksendQueue():Relay - Sign message failed");
        return false;
    }

    if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) {
        LogPrintf("CDarksendQueue():Relay - Verify message failed");
        return false;
    }

    return true;
}

bool CDarksendQueue::Relay()
{

    LOCK(cs_vNodes);
    BOOST_FOREACH(CNode* pnode, vNodes){
        pnode->PushMessage("dsq", (*this));
    }

    return true;
}

bool CDarksendQueue::CheckSignature()
{
    BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {

        if(mn.vin == vin) {
            std::string strMessage = vin.ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(time) + boost::lexical_cast<std::string>(ready);

            std::string errorMessage = "";
            if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){
                return error("Got bad masternode address signature %s \n", vin.ToString().c_str());
            }

            return true;
        }
    }

    return false;
}

void ThreadCheckDarkSendPool()
{
    // Make this thread recognisable as the wallet flushing thread
    RenameThread("bitcoin-darksend");

    unsigned int c = 0;
    while (true)
    {
        MilliSleep(1000);
        //LogPrintf("ThreadCheckDarkSendPool::check timeout\n");
        darkSendPool.CheckTimeout();

        if(c % 60 == 0){
            vector<CMasterNode>::iterator it = darkSendMasterNodes.begin();
            while(it != darkSendMasterNodes.end()){
                (*it).Check();
                if((*it).enabled == 4 || (*it).enabled == 3){
                    LogPrintf("Removing inactive masternode %s\n", (*it).addr.ToString().c_str());
                    it = darkSendMasterNodes.erase(it);
                } else {
                    ++it;
                }
            }

            masternodePayments.CleanPaymentList();
        }

        //try to sync the masternode list and payment list every 20 seconds
        if(c % 5 == 0 && RequestedMasterNodeList <= 2){
            bool fIsInitialDownload = IsInitialBlockDownload();
            if(!fIsInitialDownload) {
                LOCK(cs_vNodes);
                BOOST_FOREACH(CNode* pnode, vNodes)
                {
                    if (pnode->nVersion >= darkSendPool.MIN_PEER_PROTO_VERSION) {

                        //keep track of who we've asked for the list
                        if(pnode->HasFulfilledRequest("mnsync")) continue;
                        pnode->FulfilledRequest("mnsync");

                        LogPrintf("Successfully synced, asking for Masternode list and payment list\n");

                        pnode->PushMessage("dseg", CTxIn()); //request full mn list
                        pnode->PushMessage("mnget"); //sync payees
                        RequestedMasterNodeList++;
                    }
                }
            }
        }

        if(c == MASTERNODE_PING_SECONDS){
            darkSendPool.RegisterAsMasterNode(false);
            c = 0;
        }

        //auto denom every 2.5 minutes
        if(c % 60 == 0){
            darkSendPool.DoAutomaticDenominating();
        }
        c++;
    }
}

max_stars_repo_name: xeddmc/darkcoin

max_issues_repo_name: xeddmc/darkcoin

max_forks_repo_name: xeddmc/darkcoin


text:
#define BOOST_TEST_NO_MAIN

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <boost/test/unit_test.hpp>
#include "../core/RegistryCache.h"
#include "../core/FileCache.h"

using namespace FinagleRegistryProxy;
using namespace std;

BOOST_AUTO_TEST_SUITE( serialize_fixture_suite )

const string filename = "/tmp/serialize.test";
const int count = 2;

struct F {
	F() {
		// BOOST_TEST_MESSAGE("setup fixture");
		setup();
	}
	~F() {
		teardown();
	}

	RegistryCache* p;

	Registry createReg(int i) {
		Registry r;
		stringstream ss;
		ss << "servier" << i;
		r.name = ss.str();
		r.host = "localhost";
		r.port = i;
		r.ephemeral = "e";
		r.ctime = 1232344;
		return r;
	}

	void setup() {
		p = new RegistryCache();
		for (int i = 0; i < count; i++) {
			Registry r = createReg(i);
			p->add(r);
		}
		// BOOST_TEST_MESSAGE("cache ready");
	}

	void teardown() {
		if (p) {
			delete p;
			p = NULL;
		}
		// BOOST_TEST_MESSAGE("cache tear down");
	}

};

BOOST_FIXTURE_TEST_CASE( empty , F) {
	BOOST_CHECK(true);
}

BOOST_FIXTURE_TEST_CASE( unser_no_file, F) {
	remove(filename.c_str());
	p->clear();
	p->from_file(filename);

	BOOST_CHECK_EQUAL(p->size(), 0);
}

BOOST_FIXTURE_TEST_CASE( serialize , F) {
	p->save(filename);
	BOOST_CHECK(true);
}

BOOST_FIXTURE_TEST_CASE( unserialize , F) {
	setup();

	const string content =
			"[{\"name\":\"servier0\",\"host\":\"localhost\",\"port\":0,\"weight\":3600 },{\"name\":\"servier1\",\"host\":\"localhost\",\"port\":1,\"weight\":3600 }]";
	// vector<Registry>
	RVector v = Registry::unserialize(content);
	BOOST_CHECK_EQUAL(v.size(), 2);

}

BOOST_FIXTURE_TEST_CASE( unserialize2 , F) {
	setup();

	const string content =
			"[{\"name\":\"servier0\",\"host\":\"localhost\",\"port\":\"99\",\"weight\":3600 },{\"name\":\"servier1\",\"host\":\"localhost\",\"port\":1,\"weight\":3600 }]";
	// vector<Registry>
	RVector v = Registry::unserialize(content);

	BOOST_CHECK_EQUAL(v.size(), 2);
	BOOST_CHECK_EQUAL(v.at(0).port, 99);
	//cout << v.at(0).port << endl;
	BOOST_CHECK_EQUAL(v.at(1).port, 1);
}
BOOST_FIXTURE_TEST_CASE( unserialize3 , F) {
	setup();

	const string content =
			"[{\"name\":\"servier0\",\"host\":\"localhost\",\"port\":\"x99\",\"weight\":3600 },{\"name\":\"servier1\",\"host\":\"localhost\",\"port\":22,\"weight\":3600 }]";
	// vector<Registry>
	RVector v = Registry::unserialize(content);
	cout << v.size() << "$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; // << v.at(0).port << endl;

	BOOST_CHECK_EQUAL(v.size(), 2);
	BOOST_CHECK_EQUAL(v.at(0).port, 0);
	BOOST_CHECK_EQUAL(v.at(1).port, 22);
}

BOOST_FIXTURE_TEST_CASE( ser_vs_unser , F) {
	assert(count > 0);

	p->save(filename);

	RegistryCache* up = new RegistryCache();
	up->from_file(filename);

	BOOST_CHECK_EQUAL(up->size(), count);

	Registry left = createReg(1);
	RVector* v = p->get(left.name);
	BOOST_CHECK_EQUAL(v->size(), 1);
	Registry right = v->front();
	BOOST_CHECK_EQUAL(left.name, right.name);
	BOOST_CHECK_EQUAL(left.host, right.host);
	BOOST_CHECK_EQUAL(left.port, right.port);

	left = createReg(count - 1);
	BOOST_CHECK_EQUAL(v->size(), 1);
	right = v->front();
	BOOST_CHECK_EQUAL(left.name, right.name);
	BOOST_CHECK_EQUAL(left.host, right.host);
	BOOST_CHECK_EQUAL(left.port, right.port);

	delete up;
	up = NULL;

	teardown();
}

BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: cychenyin/sfproxy

max_issues_repo_name: cychenyin/sfproxy

max_forks_repo_name: cychenyin/sfproxy


text:
/**
 * Copyright (c) 2011-2017 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <bitcoin/bitcoin/error.hpp>

#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#else
#	pragma warning (push, 0)
#	pragma warning (disable: 4996)
#endif
#include <boost/asio.hpp>
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#else
#	pragma warning (default: 4996)
#	pragma warning (pop)
#endif

#include <boost/system/error_code.hpp>
#include <bitcoin/bitcoin/compat.hpp>

using namespace bc;

class error_category_impl
  : public std::error_category
{
public:
    virtual const char* name() const BC_NOEXCEPT;
    virtual std::string message(int ev) const BC_NOEXCEPT;
    virtual std::error_condition default_error_condition(int ev)
        const BC_NOEXCEPT;
};

static const error_category_impl& get_error_category_instance()
{
    static error_category_impl instance;
    return instance;
}

const char* error_category_impl::name() const BC_NOEXCEPT
{
    return "bitcoin";
}

std::string error_category_impl::message(int ev) const BC_NOEXCEPT
{
    static const std::unordered_map<int, std::string> messages =
    {
        // general codes
        { error::success, "success" },
        { error::deprecated, "deprecated" },
        { error::unknown, "unknown error" },
        { error::not_found, "object does not exist" },
        { error::file_system, "file system error" },
        { error::non_standard, "transaction not standard" },
        { error::not_implemented, "feature not implemented" },
        { error::oversubscribed, "service oversubscribed" },

        // network
        { error::service_stopped, "service stopped" },
        { error::operation_failed, "operation failed" },
        { error::resolve_failed, "resolving hostname failed" },
        { error::network_unreachable, "unable to reach remote host" },
        { error::address_in_use, "address already in use" },
        { error::listen_failed, "incoming connection failed" },
        { error::accept_failed, "connection acceptance failed" },
        { error::bad_stream, "bad data stream" },
        { error::channel_timeout, "connection timed out" },
        { error::address_blocked, "address blocked by policy" },
        { error::channel_stopped, "channel stopped" },
        { error::peer_throttling, "unresponsive peer may be throttling" },

        // database
        { error::store_block_invalid_height, "block out of order" },
        { error::store_block_missing_parent, "block missing parent" },
        { error::store_block_duplicate, "block duplicate" },

        // blockchain
        { error::duplicate_block, "duplicate block" },
        { error::orphan_block, "missing block parent" },
        { error::invalid_previous_block, "previous block failed to validate" },
        { error::insufficient_work, "insufficient work to reorganize" },
        { error::orphan_transaction, "missing transaction parent" },
        { error::insufficient_fee, "insufficient transaction fee" },
        { error::dusty_transaction, "output value too low" },
        { error::stale_chain, "blockchain too far behind" },

        // check header
        { error::invalid_proof_of_work, "proof of work invalid" },
        { error::futuristic_timestamp, "timestamp too far in the future" },

        // accept header
        { error::checkpoints_failed, "block hash rejected by checkpoint" },
        { error::old_version_block, "block version rejected at current height" },
        { error::incorrect_proof_of_work, "proof of work does not match bits field" },
        { error::timestamp_too_early, "block timestamp is too early" },

        // check block
        { error::block_size_limit, "block size limit exceeded" },
        { error::empty_block, "block has no transactions" },
        { error::first_not_coinbase, "first transaction not a coinbase" },
        { error::extra_coinbases, "more than one coinbase" },
        { error::internal_duplicate, "matching transaction hashes in block" },
        { error::block_internal_double_spend, "double spend internal to block" },
        { error::forward_reference, "transactions out of order" },
        { error::merkle_mismatch, "merkle root mismatch" },
        { error::block_legacy_sigop_limit, "too many block legacy signature operations" },

        // accept block
        { error::block_non_final, "block contains a non-final transaction" },
        { error::coinbase_height_mismatch, "block height mismatch in coinbase" },
        { error::coinbase_value_limit, "coinbase value too high" },
        { error::block_embedded_sigop_limit, "too many block embedded signature operations" },
        { error::invalid_witness_commitment, "invalid witness commitment" },
        { error::block_weight_limit, "block weight limit exceeded" },

        // check transaction
        { error::empty_transaction, "transaction inputs or outputs empty" },
        { error::previous_output_null, "non-coinbase transaction has input with null previous output" },
        { error::spend_overflow, "spend outside valid range" },
        { error::invalid_coinbase_script_size, "coinbase script too small or large" },
        { error::coinbase_transaction, "coinbase transaction disallowed in memory pool" },
        { error::transaction_internal_double_spend, "double spend internal to transaction" },
        { error::transaction_size_limit, "transaction size limit exceeded" },
        { error::transaction_legacy_sigop_limit, "too many transaction legacy signature operations" },

        // accept transaction
        { error::transaction_non_final, "transaction currently non-final for next block" },
        { error::premature_validation, "transaction validation under checkpoint" },
        { error::unspent_duplicate, "matching transaction with unspent outputs" },
        { error::missing_previous_output, "previous output not found" },
        { error::double_spend, "double spend of input" },
        { error::coinbase_maturity, "immature coinbase spent" },
        { error::spend_exceeds_value, "spend exceeds value of inputs" },
        { error::transaction_embedded_sigop_limit, "too many transaction embedded signature operations" },
        { error::sequence_locked, "transaction currently locked" },
        { error::transaction_weight_limit, "transaction weight limit exceeded" },

        // connect input
        { error::invalid_script, "invalid script" },
        { error::invalid_script_size, "invalid script size" },
        { error::invalid_push_data_size, "invalid push data size" },
        { error::invalid_operation_count, "invalid operation count" },
        { error::invalid_stack_size, "invalid stack size" },
        { error::invalid_stack_scope, "invalid stack scope" },
        { error::invalid_script_embed, "invalid script embed" },
        { error::invalid_signature_encoding, "invalid signature encoding" },
        { error::invalid_signature_lax_encoding, "invalid signature lax encoding" },
        { error::incorrect_signature, "incorrect signature" },
        { error::unexpected_witness, "unexpected witness" },
        { error::invalid_witness, "invalid witness" },
        { error::dirty_witness, "dirty witness" },
        { error::stack_false, "stack false" },

        // op eval
        { error::op_disabled, "op_disabled" },
        { error::op_reserved, "op_reserved" },
        { error::op_push_size, "op_push_size" },
        { error::op_push_data, "op_push_data" },
        { error::op_if, "op_if" },
        { error::op_notif, "op_notif" },
        { error::op_else, "op_else" },
        { error::op_endif, "op_endif" },
        { error::op_verify1, "op_verify1" },
        { error::op_verify2, "op_verify2" },
        { error::op_return, "op_return" },
        { error::op_to_alt_stack, "op_to_alt_stack" },
        { error::op_from_alt_stack, "op_from_alt_stack" },
        { error::op_drop2, "op_drop2" },
        { error::op_dup2, "op_dup2" },
        { error::op_dup3, "op_dup3" },
        { error::op_over2, "op_over2" },
        { error::op_rot2, "op_rot2" },
        { error::op_swap2, "op_swap2" },
        { error::op_if_dup, "op_if_dup" },
        { error::op_drop, "op_drop" },
        { error::op_dup, "op_dup" },
        { error::op_nip, "op_nip" },
        { error::op_over, "op_over" },
        { error::op_pick, "op_pick" },
        { error::op_roll, "op_roll" },
        { error::op_rot, "op_rot" },
        { error::op_swap, "op_swap" },
        { error::op_tuck, "op_tuck" },
        { error::op_size, "op_size" },
        { error::op_equal, "op_equal" },
        { error::op_equal_verify1, "op_equal_verify1" },
        { error::op_equal_verify2, "op_equal_verify2" },
        { error::op_add1, "op_add1" },
        { error::op_sub1, "op_sub1" },
        { error::op_negate, "op_negate" },
        { error::op_abs, "op_abs" },
        { error::op_not, "op_not" },
        { error::op_nonzero, "op_nonzero" },
        { error::op_add, "op_add" },
        { error::op_sub, "op_sub" },
        { error::op_bool_and, "op_bool_and" },
        { error::op_bool_or, "op_bool_or" },
        { error::op_num_equal, "op_num_equal" },
        { error::op_num_equal_verify1, "op_num_equal_verify1" },
        { error::op_num_equal_verify2, "op_num_equal_verify2" },
        { error::op_num_not_equal, "op_num_not_equal" },
        { error::op_less_than, "op_less_than" },
        { error::op_greater_than, "op_greater_than" },
        { error::op_less_than_or_equal, "op_less_than_or_equal" },
        { error::op_greater_than_or_equal, "op_greater_than_or_equal" },
        { error::op_min, "op_min" },
        { error::op_max, "op_max" },
        { error::op_within, "op_within" },
        { error::op_ripemd160, "op_ripemd160" },
        { error::op_sha1, "op_sha1" },
        { error::op_sha256, "op_sha256" },
        { error::op_hash160, "op_hash160" },
        { error::op_hash256, "op_hash256" },
        { error::op_code_seperator, "op_code_seperator" },
        { error::op_check_sig_verify1, "op_check_sig_verify1" },
        { error::op_check_sig, "op_check_sig" },
        { error::op_check_multisig_verify1, "op_check_multisig_verify1" },
        { error::op_check_multisig_verify2, "op_check_multisig_verify2" },
        { error::op_check_multisig_verify3, "op_check_multisig_verify3" },
        { error::op_check_multisig_verify4, "op_check_multisig_verify4" },
        { error::op_check_multisig_verify5, "op_check_multisig_verify5" },
        { error::op_check_multisig_verify6, "op_check_multisig_verify6" },
        { error::op_check_multisig_verify7, "op_check_multisig_verify7" },
        { error::op_check_multisig, "op_check_multisig" },
        { error::op_check_locktime_verify1, "op_check_locktime_verify1" },
        { error::op_check_locktime_verify2, "op_check_locktime_verify2" },
        { error::op_check_locktime_verify3, "op_check_locktime_verify3" },
        { error::op_check_locktime_verify4, "op_check_locktime_verify4" },
        { error::op_check_locktime_verify5, "op_check_locktime_verify5" },
        { error::op_check_locktime_verify6, "op_check_locktime_verify6" },
        { error::op_check_sequence_verify1, "op_check_sequence_verify1" },
        { error::op_check_sequence_verify2, "op_check_sequence_verify2" },
        { error::op_check_sequence_verify3, "op_check_sequence_verify3" },
        { error::op_check_sequence_verify4, "op_check_sequence_verify4" },
        { error::op_check_sequence_verify5, "op_check_sequence_verify5" },
        { error::op_check_sequence_verify6, "op_check_sequence_verify6" },
        { error::op_check_sequence_verify7, "op_check_sequence_verify7" },

        // Added out of order (bip147).
        { error::op_check_multisig_verify8, "op_check_multisig_verify8" },
    };

    const auto message = messages.find(ev);
    return message != messages.end() ? message->second : "invalid code";
}

// We are not currently using this.
std::error_condition error_category_impl::default_error_condition(int ev)
    const BC_NOEXCEPT
{
    return std::error_condition(ev, *this);
}

namespace libbitcoin {
namespace error {

    code make_error_code(error_code_t e)
    {
        return code(e, get_error_category_instance());
    }

    std::error_condition make_error_condition(error_condition_t e)
    {
        return std::error_condition(e, get_error_category_instance());
    }

    error_code_t boost_to_error_code(const boost_code& ec)
    {
        namespace boost_error = boost::system::errc;

#ifdef _MSC_VER
        // TODO: is there a means to map ASIO errors to boost errors?
        // ASIO codes are unique on Windows but not on Linux.
        namespace asio_error = boost::asio::error;
#endif
        // TODO: use a static map (hash table)
        switch (ec.value())
        {
            // There should be no boost mapping to the shutdown sentinel.
            //    return error::service_stopped;

            case boost_error::success:
                return error::success;

            // network errors
#ifdef _MSC_VER
            case asio_error::connection_aborted:
            case asio_error::connection_reset:
            case asio_error::operation_aborted:
            case asio_error::operation_not_supported:
#endif
            case boost_error::connection_aborted:
            case boost_error::connection_refused:
            case boost_error::connection_reset:
            case boost_error::not_connected:
            case boost_error::operation_canceled:
            case boost_error::operation_not_permitted:
            case boost_error::operation_not_supported:
            case boost_error::owner_dead:
            case boost_error::permission_denied:
                return error::operation_failed;

#ifdef _MSC_VER
            case asio_error::address_family_not_supported:
#endif
            case boost_error::address_family_not_supported:
            case boost_error::address_not_available:
            case boost_error::bad_address:
            case boost_error::destination_address_required:
                return error::resolve_failed;

            case boost_error::broken_pipe:
            case boost_error::host_unreachable:
            case boost_error::network_down:
            case boost_error::network_reset:
            case boost_error::network_unreachable:
            case boost_error::no_link:
            case boost_error::no_protocol_option:
            case boost_error::no_such_file_or_directory:
            case boost_error::not_a_socket:
            case boost_error::protocol_not_supported:
            case boost_error::wrong_protocol_type:
                return error::network_unreachable;

            case boost_error::address_in_use:
            case boost_error::already_connected:
            case boost_error::connection_already_in_progress:
            case boost_error::operation_in_progress:
                return error::address_in_use;

            case boost_error::bad_message:
            case boost_error::illegal_byte_sequence:
            case boost_error::io_error:
            case boost_error::message_size:
            case boost_error::no_message_available:
            case boost_error::no_message:
            case boost_error::no_stream_resources:
            case boost_error::not_a_stream:
            case boost_error::protocol_error:
                return error::bad_stream;

#ifdef _MSC_VER
            case asio_error::timed_out:
#endif
            case boost_error::stream_timeout:
            case boost_error::timed_out:
                return error::channel_timeout;

            // file system errors
            case boost_error::cross_device_link:
            case boost_error::bad_file_descriptor:
            case boost_error::device_or_resource_busy:
            case boost_error::directory_not_empty:
            case boost_error::executable_format_error:
            case boost_error::file_exists:
            case boost_error::file_too_large:
            case boost_error::filename_too_long:
            case boost_error::invalid_seek:
            case boost_error::is_a_directory:
            case boost_error::no_space_on_device:
            case boost_error::no_such_device:
            case boost_error::no_such_device_or_address:
            case boost_error::read_only_file_system:
            // same as operation_would_block on non-windows
            //case boost_error::resource_unavailable_try_again:
            case boost_error::text_file_busy:
            case boost_error::too_many_files_open:
            case boost_error::too_many_files_open_in_system:
            case boost_error::too_many_links:
            case boost_error::too_many_symbolic_link_levels:
                return error::file_system;

            // unknown errors
            case boost_error::argument_list_too_long:
            case boost_error::argument_out_of_domain:
            case boost_error::function_not_supported:
            case boost_error::identifier_removed:
            case boost_error::inappropriate_io_control_operation:
            case boost_error::interrupted:
            case boost_error::invalid_argument:
            case boost_error::no_buffer_space:
            case boost_error::no_child_process:
            case boost_error::no_lock_available:
            case boost_error::no_such_process:
            case boost_error::not_a_directory:
            case boost_error::not_enough_memory:
            case boost_error::operation_would_block:
            case boost_error::resource_deadlock_would_occur:
            case boost_error::result_out_of_range:
            case boost_error::state_not_recoverable:
            case boost_error::value_too_large:
            default:
                return error::unknown;
        }
    }

    error_code_t posix_to_error_code(int ec)
    {
        // TODO: expand mapping for database scenario.
        switch (ec)
        {
            // protocol codes (from zeromq)
            case ENOBUFS:
            case ENOTSUP:
            case EPROTONOSUPPORT:
                return error::operation_failed;
            case ENETDOWN:
                return error::network_unreachable;
            case EADDRINUSE:
                return error::address_in_use;
            case EADDRNOTAVAIL:
                return error::resolve_failed;
            case ECONNREFUSED:
                return error::accept_failed;
            case EINPROGRESS:
                return error::channel_timeout;
            case EAGAIN:
                return error::channel_timeout;
            case EFAULT:
                return error::bad_stream;
            case EINTR:
            case ENOTSOCK:
                return error::service_stopped;
            default:
                return error::unknown;
        }
    }

} // namespace error
} // namespace libbitcoin

max_stars_repo_name: anatolse/beam

max_issues_repo_name: anatolse/beam

max_forks_repo_name: anatolse/beam


text:
//
// Copyright (c) 2019 INRIA
//

#include "pinocchio/multibody/model.hpp"

# include <eigen3/Eigen/Core>
#include "pinocchio/math/matrix.hpp"

#include <boost/test/unit_test.hpp>
#include <boost/utility/binary.hpp>

BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE(test_matrix_matrix_product)
{
  using namespace pinocchio;
  using namespace Eigen;
  const Eigen::DenseIndex m = 20, n = 100;
  MatrixXd M1(MatrixXd::Ones(m,n)), M2(MatrixXd::Ones(n,m));
  MatrixMatrixProduct<MatrixXd,MatrixXd>::type res = M1 * M2;
  BOOST_CHECK(!res.eval().isZero());
}

BOOST_AUTO_TEST_CASE(test_scalar_matrix_product)
{
  using namespace pinocchio;
  using namespace Eigen;
  const Eigen::DenseIndex m = 20, n = 100;
  MatrixXd M(MatrixXd::Ones(m,n));
  const double alpha = 0.;
  ScalarMatrixProduct<double,MatrixXd>::type res = alpha * M;
  BOOST_CHECK(res.eval().isZero());
}

BOOST_AUTO_TEST_CASE(test_matrix_scalar_product)
{
  using namespace pinocchio;
  using namespace Eigen;
  const Eigen::DenseIndex m = 20, n = 100;
  MatrixXd M(MatrixXd::Ones(m,n));
  const double alpha = 1.;
  MatrixScalarProduct<MatrixXd,double>::type res = M * alpha;
  BOOST_CHECK(res.eval() == M);
}

BOOST_AUTO_TEST_SUITE_END()


text:
#include <sstream>
#include "stream-util.h"

#define BOOST_TEST_MODULE
#define BOOST_TEST_DYN_LINK

#include <boost/test/unit_test.hpp>
#include "common/test-init.h"

using namespace std;

BOOST_AUTO_TEST_CASE(TestHarnessOStreamWorks) {

  stringstream* sut = new stringstream();
  unique_ptr<ostream> ofs(sut);
  TestHarnessOStream output_stream(move(ofs));
  stringstream* log = new stringstream();
  unique_ptr<ostream> logger(log);
  output_stream.SetDebugLogStream(move(logger), true);

  output_stream.Write("HELLO");
  output_stream.Write("WORLD");
  const char* buf = "Hello World";
  output_stream.Write(buf, 11);

  BOOST_CHECK_EQUAL(sut->str(), "HELLO\nWORLD\nHello World");
  BOOST_CHECK_EQUAL(log->str(), "HELLO\nWORLD\nHello World");
}

BOOST_AUTO_TEST_CASE(TestHarnessIStreamWorks) {

  stringstream* sut = new stringstream();
  stringstream* log = new stringstream();

  *sut << "FOO" << endl;
  *sut << "BAR" << endl;
  const char* buf = "Foo bar";
  sut->write(buf, 7);

  unique_ptr<istream> ifs(sut);
  TestHarnessIStream input_stream(move(ifs));
  unique_ptr<ostream> logger(log);
  input_stream.SetDebugLogStream(move(logger), true);

  string line;
  input_stream.Read(&line);
  BOOST_CHECK_EQUAL(line, "FOO");
  input_stream.Read(&line);
  BOOST_CHECK_EQUAL(line, "BAR");
  char input_buf[8];
  input_stream.Read(input_buf, 7);
  input_buf[7] = '\0';
  BOOST_CHECK_EQUAL(buf, "Foo bar");

  BOOST_CHECK_EQUAL(log->str(), "FOO\nBAR\nFoo bar");

}

ext: cc

max_stars_repo_name: nathanawmk/SPARTA

max_issues_repo_name: CianLevy/Modified-HEtest

max_forks_repo_name: CianLevy/Modified-HEtest