<commit_before>// Copyright (c) 2015 The TX developers
// Copyright (c) 2009-2012 The Darkcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bignum.h"
#include "sync.h"
#include "net.h"
#include "key.h"
#include "util.h"
#include "script.h"
#include "base58.h"
#include "protocol.h"
#include "spork.h"
#include "main.h"
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;

class CSporkMessage;
class CSporkManager;

CSporkManager sporkManager;

std::map<uint256, CSporkMessage> mapSporks;
std::map<int, CSporkMessage> mapSporksActive;

void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
    if(fLiteMode) return; //disable all darksend/masternode related functionality

    if (strCommand == "spork")
    {
        //LogPrintf("ProcessSpork::spork\n");
        CDataStream vMsg(vRecv);
        CSporkMessage spork;
        vRecv >> spork;

        if(pindexBest == NULL) return;

        uint256 hash = spork.GetHash();
        if(mapSporksActive.count(spork.nSporkID)) {
            if(mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned){
                if(fDebug) LogPrintf("spork - seen %s block %d \n", hash.ToString().c_str(), pindexBest->nHeight);
                return;
            } else {
                if(fDebug) LogPrintf("spork - got updated spork %s block %d \n", hash.ToString().c_str(), pindexBest->nHeight);
            }
        }

        LogPrintf("spork - new %s ID %d Time %d bestHeight %d\n", hash.ToString().c_str(), spork.nSporkID, spork.nValue, pindexBest->nHeight);

        if(!sporkManager.CheckSignature(spork)){
            LogPrintf("spork - invalid signature\n");
            Misbehaving(pfrom->GetId(), 100);
            return;
        }

        mapSporks[hash] = spork;
        mapSporksActive[spork.nSporkID] = spork;
        sporkManager.Relay(spork);

        //does a task if needed
        ExecuteSpork(spork.nSporkID, spork.nValue);
    }
    if (strCommand == "getsporks")
    {
        std::map<int, CSporkMessage>::iterator it = mapSporksActive.begin();

        while(it != mapSporksActive.end()) {
            pfrom->PushMessage("spork", it->second);
            it++;
        }
    }

}

// grab the spork, otherwise say it's off
bool IsSporkActive(int nSporkID)
{
    int64_t r = -1;

    if(mapSporksActive.count(nSporkID)){
        r = mapSporksActive[nSporkID].nValue;
    } else {
        if(nSporkID == SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT) r = SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
        if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
        if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
        if(nSporkID == SPORK_6_REPLAY_BLOCKS) r = SPORK_6_REPLAY_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING;
        if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
        if(nSporkID == SPORK_11_RESET_BUDGET_DEFAULT) r = SPORK_11_RESET_BUDGET_DEFAULT;
        if(nSporkID == SPORK_12_RECONSIDER_BLOCKS_DEFAULT) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

        if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
    }
    if(r == -1) r = 4070908800; //return 2099-1-1 by default

    return r < GetTime();
}

// grab the value of the spork on the network, or the default
int64_t GetSporkValue(int nSporkID)
{
    int64_t r = -1;

    if(mapSporksActive.count(nSporkID)){
        r = mapSporksActive[nSporkID].nValue;
    } else {
        if(nSporkID == SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT) r = SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
        if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
        if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
        if(nSporkID == SPORK_6_REPLAY_BLOCKS) r = SPORK_6_REPLAY_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING;
        if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
        if(nSporkID == SPORK_11_RESET_BUDGET_DEFAULT) r = SPORK_11_RESET_BUDGET_DEFAULT;
        if(nSporkID == SPORK_12_RECONSIDER_BLOCKS_DEFAULT) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

        if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
    }

    return r;
}

void ExecuteSpork(int nSporkID, int nValue)
{
}

/*void ReprocessBlocks(int nBlocks)
{
    std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin();
    while(it != mapRejectedBlocks.end()){
        //use a window twice as large as is usual for the nBlocks we want to reset
        if((*it).second  > GetTime() - (nBlocks*60*5)) {
            BlockMap::iterator mi = mapBlockIndex.find((*it).first);
            if (mi != mapBlockIndex.end() && (*mi).second) {
                LOCK(cs_main);

                CBlockIndex* pindex = (*mi).second;
                LogPrintf("ReprocessBlocks - %s\n", (*it).first.ToString());

                CValidationState state;
                ReconsiderBlock(state, pindex);
            }
        }
        ++it;
    }

    CValidationState state;
    {
        LOCK(cs_main);
        DisconnectBlocksAndReprocess(nBlocks);
    }

    if (state.IsValid()) {
        ActivateBestChain(state);
    }
}*/

bool CSporkManager::CheckSignature(CSporkMessage& spork)
{
    //note: need to investigate why this is failing
    std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);
    std::string strPubKey = strMainPubKey;
    CPubKey pubkey(ParseHex(strPubKey));

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

    return true;
}

bool CSporkManager::Sign(CSporkMessage& spork)
{
    std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);

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

    if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
    {
        LogPrintf("CMasternodePayments::Sign - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
        return false;
    }

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

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

    return true;
}

bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue)
{

    CSporkMessage msg;
    msg.nSporkID = nSporkID;
    msg.nValue = nValue;
    msg.nTimeSigned = GetTime();

    if(Sign(msg)){
        Relay(msg);
        mapSporks[msg.GetHash()] = msg;
        mapSporksActive[nSporkID] = msg;
        return true;
    }

    return false;
}

void CSporkManager::Relay(CSporkMessage& msg)
{
    CInv inv(MSG_SPORK, msg.GetHash());

    RelayInventory(inv);
}

bool CSporkManager::SetPrivKey(std::string strPrivKey)
{
    CSporkMessage msg;

    // Test signing successful, proceed
    strMasterPrivKey = strPrivKey;

    Sign(msg);

    if(CheckSignature(msg)){
        LogPrintf("CSporkManager::SetPrivKey - Successfully initialized as spork signer\n");
        return true;
    } else {
        return false;
    }
}

int CSporkManager::GetSporkIDByName(std::string strName)
{
    if(strName == "SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT") return SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT;
    if(strName == "SPORK_2_INSTANTX") return SPORK_2_INSTANTX;
    if(strName == "SPORK_3_INSTANTX_BLOCK_FILTERING") return SPORK_3_INSTANTX_BLOCK_FILTERING;
    if(strName == "SPORK_5_MAX_VALUE") return SPORK_5_MAX_VALUE;
    if(strName == "SPORK_6_REPLAY_BLOCKS") return SPORK_6_REPLAY_BLOCKS;
    if(strName == "SPORK_7_MASTERNODE_SCANNING") return SPORK_7_MASTERNODE_SCANNING;
    if(strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
    if(strName == "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT") return SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
    if(strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
    if(strName == "SPORK_11_RESET_BUDGET_DEFAULT") return SPORK_11_RESET_BUDGET_DEFAULT;
    if(strName == "SPORK_12_RECONSIDER_BLOCKS_DEFAULT") return SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
    if(strName == "SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT") return SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

    return -1;
}

std::string CSporkManager::GetSporkNameByID(int id)
{
    if(id == SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT) return "SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT";
    if(id == SPORK_2_INSTANTX) return "SPORK_2_INSTANTX";
    if(id == SPORK_3_INSTANTX_BLOCK_FILTERING) return "SPORK_3_INSTANTX_BLOCK_FILTERING";
    if(id == SPORK_5_MAX_VALUE) return "SPORK_5_MAX_VALUE";
    if(id == SPORK_6_REPLAY_BLOCKS) return "SPORK_6_REPLAY_BLOCKS";
    if(id == SPORK_7_MASTERNODE_SCANNING) return "SPORK_7_MASTERNODE_SCANNING";
    if(strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
    if(strName == "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT") return SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
    if(strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
    if(strName == "SPORK_11_RESET_BUDGET_DEFAULT") return SPORK_11_RESET_BUDGET_DEFAULT;
    if(strName == "SPORK_12_RECONSIDER_BLOCKS_DEFAULT") return SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
    if(strName == "SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT") return SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

    return "Unknown";
}
<commit_msg>fix spork again<commit_after>// Copyright (c) 2015 The TX developers
// Copyright (c) 2009-2012 The Darkcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bignum.h"
#include "sync.h"
#include "net.h"
#include "key.h"
#include "util.h"
#include "script.h"
#include "base58.h"
#include "protocol.h"
#include "spork.h"
#include "main.h"
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;

class CSporkMessage;
class CSporkManager;

CSporkManager sporkManager;

std::map<uint256, CSporkMessage> mapSporks;
std::map<int, CSporkMessage> mapSporksActive;

void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
    if(fLiteMode) return; //disable all darksend/masternode related functionality

    if (strCommand == "spork")
    {
        //LogPrintf("ProcessSpork::spork\n");
        CDataStream vMsg(vRecv);
        CSporkMessage spork;
        vRecv >> spork;

        if(pindexBest == NULL) return;

        uint256 hash = spork.GetHash();
        if(mapSporksActive.count(spork.nSporkID)) {
            if(mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned){
                if(fDebug) LogPrintf("spork - seen %s block %d \n", hash.ToString().c_str(), pindexBest->nHeight);
                return;
            } else {
                if(fDebug) LogPrintf("spork - got updated spork %s block %d \n", hash.ToString().c_str(), pindexBest->nHeight);
            }
        }

        LogPrintf("spork - new %s ID %d Time %d bestHeight %d\n", hash.ToString().c_str(), spork.nSporkID, spork.nValue, pindexBest->nHeight);

        if(!sporkManager.CheckSignature(spork)){
            LogPrintf("spork - invalid signature\n");
            Misbehaving(pfrom->GetId(), 100);
            return;
        }

        mapSporks[hash] = spork;
        mapSporksActive[spork.nSporkID] = spork;
        sporkManager.Relay(spork);

        //does a task if needed
        ExecuteSpork(spork.nSporkID, spork.nValue);
    }
    if (strCommand == "getsporks")
    {
        std::map<int, CSporkMessage>::iterator it = mapSporksActive.begin();

        while(it != mapSporksActive.end()) {
            pfrom->PushMessage("spork", it->second);
            it++;
        }
    }

}

// grab the spork, otherwise say it's off
bool IsSporkActive(int nSporkID)
{
    int64_t r = -1;

    if(mapSporksActive.count(nSporkID)){
        r = mapSporksActive[nSporkID].nValue;
    } else {
        if(nSporkID == SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT) r = SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
        if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
        if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
        if(nSporkID == SPORK_6_REPLAY_BLOCKS) r = SPORK_6_REPLAY_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING;
        if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
        if(nSporkID == SPORK_11_RESET_BUDGET_DEFAULT) r = SPORK_11_RESET_BUDGET_DEFAULT;
        if(nSporkID == SPORK_12_RECONSIDER_BLOCKS_DEFAULT) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

        if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
    }
    if(r == -1) r = 4070908800; //return 2099-1-1 by default

    return r < GetTime();
}

// grab the value of the spork on the network, or the default
int64_t GetSporkValue(int nSporkID)
{
    int64_t r = -1;

    if(mapSporksActive.count(nSporkID)){
        r = mapSporksActive[nSporkID].nValue;
    } else {
        if(nSporkID == SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT) r = SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
        if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
        if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
        if(nSporkID == SPORK_6_REPLAY_BLOCKS) r = SPORK_6_REPLAY_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING;
        if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
        if(nSporkID == SPORK_11_RESET_BUDGET_DEFAULT) r = SPORK_11_RESET_BUDGET_DEFAULT;
        if(nSporkID == SPORK_12_RECONSIDER_BLOCKS_DEFAULT) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
        if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

        if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
    }

    return r;
}

void ExecuteSpork(int nSporkID, int nValue)
{
}

/*void ReprocessBlocks(int nBlocks)
{
    std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin();
    while(it != mapRejectedBlocks.end()){
        //use a window twice as large as is usual for the nBlocks we want to reset
        if((*it).second  > GetTime() - (nBlocks*60*5)) {
            BlockMap::iterator mi = mapBlockIndex.find((*it).first);
            if (mi != mapBlockIndex.end() && (*mi).second) {
                LOCK(cs_main);

                CBlockIndex* pindex = (*mi).second;
                LogPrintf("ReprocessBlocks - %s\n", (*it).first.ToString());

                CValidationState state;
                ReconsiderBlock(state, pindex);
            }
        }
        ++it;
    }

    CValidationState state;
    {
        LOCK(cs_main);
        DisconnectBlocksAndReprocess(nBlocks);
    }

    if (state.IsValid()) {
        ActivateBestChain(state);
    }
}*/

bool CSporkManager::CheckSignature(CSporkMessage& spork)
{
    //note: need to investigate why this is failing
    std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);
    std::string strPubKey = strMainPubKey;
    CPubKey pubkey(ParseHex(strPubKey));

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

    return true;
}

bool CSporkManager::Sign(CSporkMessage& spork)
{
    std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);

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

    if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
    {
        LogPrintf("CMasternodePayments::Sign - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
        return false;
    }

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

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

    return true;
}

bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue)
{

    CSporkMessage msg;
    msg.nSporkID = nSporkID;
    msg.nValue = nValue;
    msg.nTimeSigned = GetTime();

    if(Sign(msg)){
        Relay(msg);
        mapSporks[msg.GetHash()] = msg;
        mapSporksActive[nSporkID] = msg;
        return true;
    }

    return false;
}

void CSporkManager::Relay(CSporkMessage& msg)
{
    CInv inv(MSG_SPORK, msg.GetHash());

    RelayInventory(inv);
}

bool CSporkManager::SetPrivKey(std::string strPrivKey)
{
    CSporkMessage msg;

    // Test signing successful, proceed
    strMasterPrivKey = strPrivKey;

    Sign(msg);

    if(CheckSignature(msg)){
        LogPrintf("CSporkManager::SetPrivKey - Successfully initialized as spork signer\n");
        return true;
    } else {
        return false;
    }
}

int CSporkManager::GetSporkIDByName(std::string strName)
{
    if(strName == "SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT") return SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT;
    if(strName == "SPORK_2_INSTANTX") return SPORK_2_INSTANTX;
    if(strName == "SPORK_3_INSTANTX_BLOCK_FILTERING") return SPORK_3_INSTANTX_BLOCK_FILTERING;
    if(strName == "SPORK_5_MAX_VALUE") return SPORK_5_MAX_VALUE;
    if(strName == "SPORK_6_REPLAY_BLOCKS") return SPORK_6_REPLAY_BLOCKS;
    if(strName == "SPORK_7_MASTERNODE_SCANNING") return SPORK_7_MASTERNODE_SCANNING;
    if(strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
    if(strName == "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT") return SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
    if(strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
    if(strName == "SPORK_11_RESET_BUDGET_DEFAULT") return SPORK_11_RESET_BUDGET_DEFAULT;
    if(strName == "SPORK_12_RECONSIDER_BLOCKS_DEFAULT") return SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
    if(strName == "SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT") return SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;

    return -1;
}

std::string CSporkManager::GetSporkNameByID(int id)
{
    if(id == SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT) return "SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT";
    if(id == SPORK_2_INSTANTX) return "SPORK_2_INSTANTX";
    if(id == SPORK_3_INSTANTX_BLOCK_FILTERING) return "SPORK_3_INSTANTX_BLOCK_FILTERING";
    if(id == SPORK_5_MAX_VALUE) return "SPORK_5_MAX_VALUE";
    if(id == SPORK_6_REPLAY_BLOCKS) return "SPORK_6_REPLAY_BLOCKS";
    if(id == SPORK_7_MASTERNODE_SCANNING) return "SPORK_7_MASTERNODE_SCANNING";
    if(id == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT) return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT";
    if(id == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT) return "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT";
    if(id == SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT) return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT";
    if(id == SPORK_11_RESET_BUDGET_DEFAULT) return "SPORK_11_RESET_BUDGET_DEFAULT";
    if(id == SPORK_12_RECONSIDER_BLOCKS_DEFAULT) return "SPORK_12_RECONSIDER_BLOCKS_DEFAULT";
    if(id == SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT) return "SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT";

    return "Unknown";
}<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace dll {

template <typename Augment>
struct augmenter;

template <std::size_t C>
struct augmenter <copy<C>> {
    template <typename Input, typename Output>
    static void apply(Output& result, const Input& input) {
        for(std::size_t c = 0; c < C; ++c){
            // Simply create a copy
            result.push_back(input);
        }
    }

    static void concat_name(std::string& name) {
        name += " copy<" + std::to_string(C) + ">";
    }
};

template <std::size_t C, std::size_t K>
struct augmenter <elastic<C, K>> {
    static_assert(K % 2 == 1, "The kernel size must be odd");

    template<typename W>
    static void gaussian_blur(const etl::dyn_matrix<W>& d, etl::dyn_matrix<W>& d_blur){
        auto kernel_size = K;
        auto mid = kernel_size / 2;

        double sigma = 0.8 + 0.3 * ((kernel_size - 1) * 0.5 - 1);

        const std::size_t width = d.dim(0);
        const std::size_t height = d.dim(1);

        etl::dyn_matrix<W> kernel(kernel_size, kernel_size);

        auto gaussian = [](double x, double y, double sigma) {
            auto Z = 2.0 * M_PI * sigma * sigma;
            return (1.0 / Z) * std::exp(-((x * x + y * y) / (2.0 * sigma * sigma)));
        };

        for (std::size_t i = 0; i < kernel_size; ++i) {
            for (std::size_t j = 0; j < kernel_size; ++j) {
                kernel(i, j) = gaussian(double(i) - mid, double(j) - mid, sigma);;
            }
        }

        for (std::size_t j = 0; j < width; ++j) {
            for (std::size_t k = 0; k < height; ++k) {
                W sum(0.0);

                for (std::size_t p = 0; p < kernel_size; ++p) {
                    if (long(j) + p - mid >= 0 && long(j) + p - mid < width) {
                        for (std::size_t q = 0; q < kernel_size; ++q) {
                            if (long(k) + q - mid >= 0 && long(k) + q - mid < height) {
                                sum += kernel(p, q) * d(j + p - mid, k + q - mid);
                            }
                        }
                    }
                }

                d_blur(j, k) = d(j, k) - (sum / (kernel_size * kernel_size));
            }
        }
    }

    template <typename Input, typename Output>
    static void apply(Output& output, const Input& input) {
        for(std::size_t c = 0; c < C; ++c){
            // Create a copy of the same type
            auto result = input;

            using weight = etl::value_t<Input>;

            const std::size_t width = input.dim(1);
            const std::size_t height = input.dim(2);

            // 0. Generate random displacement fields

            etl::dyn_matrix<weight> d_x(width, height);
            etl::dyn_matrix<weight> d_y(width, height);

            d_x = etl::uniform_generator(-1.0, 1.0);
            d_y = etl::uniform_generator(-1.0, 1.0);

            // 1. Gaussian blur the displacement fields

            etl::dyn_matrix<weight> d_x_blur(width, height);
            etl::dyn_matrix<weight> d_y_blur(width, height);

            gaussian_blur(d_x, d_x_blur);
            gaussian_blur(d_y, d_y_blur);

            // 2. Normalize the displacement field

            d_x_blur /= sum(d_x_blur);
            d_y_blur /= sum(d_y_blur);

            // 3. Scale the displacement field

            weight alpha(8);

            d_x_blur *= alpha;
            d_y_blur *= alpha;

            // 4. Apply the displacement field (using bilinear interpolation)

            auto safe = [&](std::size_t channel, weight x, weight y) {
                if (x < 0 || y < 0 || x > width - 1 || y > height - 1) {
                    return input(channel, 0, 0);
                } else {
                    return input(channel, x, y);
                }
            };

            for (std::size_t channel = 0; channel < etl::dim<0>(input); ++channel) {
                for (int x = 0; x < int(width); ++x) {
                    for (int y = 0; y < int(height); ++y) {
                        auto dx = d_x_blur(x, y);
                        auto dy = d_y_blur(x, y);

                        weight px = x + dx;
                        weight py = y + dy;

                        weight a = safe(channel, std::floor(px), std::floor(py));
                        weight b = safe(channel, std::ceil(px), std::floor(py));
                        weight c = safe(channel, std::ceil(px), std::ceil(py));
                        weight d = safe(channel, std::floor(px), std::ceil(py));

                        auto e = a * (1.0 - (px - std::floor(px))) + d * (px - std::floor(px));
                        auto f = b * (1.0 - (px - std::floor(px))) + c * (px - std::floor(px));

                        auto value = e * (1.0 - (py - std::floor(py))) + f * (py - std::floor(py));

                        result(channel, x, y) = value;;
                    }
                }
            }

            output.push_back(result);
        }
    }

    static void concat_name(std::string& name) {
        name += " elastic<" + std::to_string(C) + ", " + std::to_string(K) + ">";
    }
};

} //end of dll namespace
<commit_msg>Fix double ;; issues<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace dll {

template <typename Augment>
struct augmenter;

template <std::size_t C>
struct augmenter <copy<C>> {
    template <typename Input, typename Output>
    static void apply(Output& result, const Input& input) {
        for(std::size_t c = 0; c < C; ++c){
            // Simply create a copy
            result.push_back(input);
        }
    }

    static void concat_name(std::string& name) {
        name += " copy<" + std::to_string(C) + ">";
    }
};

template <std::size_t C, std::size_t K>
struct augmenter <elastic<C, K>> {
    static_assert(K % 2 == 1, "The kernel size must be odd");

    template<typename W>
    static void gaussian_blur(const etl::dyn_matrix<W>& d, etl::dyn_matrix<W>& d_blur){
        auto kernel_size = K;
        auto mid = kernel_size / 2;

        double sigma = 0.8 + 0.3 * ((kernel_size - 1) * 0.5 - 1);

        const std::size_t width = d.dim(0);
        const std::size_t height = d.dim(1);

        etl::dyn_matrix<W> kernel(kernel_size, kernel_size);

        auto gaussian = [](double x, double y, double sigma) {
            auto Z = 2.0 * M_PI * sigma * sigma;
            return (1.0 / Z) * std::exp(-((x * x + y * y) / (2.0 * sigma * sigma)));
        };

        for (std::size_t i = 0; i < kernel_size; ++i) {
            for (std::size_t j = 0; j < kernel_size; ++j) {
                kernel(i, j) = gaussian(double(i) - mid, double(j) - mid, sigma);
            }
        }

        for (std::size_t j = 0; j < width; ++j) {
            for (std::size_t k = 0; k < height; ++k) {
                W sum(0.0);

                for (std::size_t p = 0; p < kernel_size; ++p) {
                    if (long(j) + p - mid >= 0 && long(j) + p - mid < width) {
                        for (std::size_t q = 0; q < kernel_size; ++q) {
                            if (long(k) + q - mid >= 0 && long(k) + q - mid < height) {
                                sum += kernel(p, q) * d(j + p - mid, k + q - mid);
                            }
                        }
                    }
                }

                d_blur(j, k) = d(j, k) - (sum / (kernel_size * kernel_size));
            }
        }
    }

    template <typename Input, typename Output>
    static void apply(Output& output, const Input& input) {
        for(std::size_t c = 0; c < C; ++c){
            // Create a copy of the same type
            auto result = input;

            using weight = etl::value_t<Input>;

            const std::size_t width = input.dim(1);
            const std::size_t height = input.dim(2);

            // 0. Generate random displacement fields

            etl::dyn_matrix<weight> d_x(width, height);
            etl::dyn_matrix<weight> d_y(width, height);

            d_x = etl::uniform_generator(-1.0, 1.0);
            d_y = etl::uniform_generator(-1.0, 1.0);

            // 1. Gaussian blur the displacement fields

            etl::dyn_matrix<weight> d_x_blur(width, height);
            etl::dyn_matrix<weight> d_y_blur(width, height);

            gaussian_blur(d_x, d_x_blur);
            gaussian_blur(d_y, d_y_blur);

            // 2. Normalize the displacement field

            d_x_blur /= sum(d_x_blur);
            d_y_blur /= sum(d_y_blur);

            // 3. Scale the displacement field

            weight alpha(8);

            d_x_blur *= alpha;
            d_y_blur *= alpha;

            // 4. Apply the displacement field (using bilinear interpolation)

            auto safe = [&](std::size_t channel, weight x, weight y) {
                if (x < 0 || y < 0 || x > width - 1 || y > height - 1) {
                    return input(channel, 0, 0);
                } else {
                    return input(channel, x, y);
                }
            };

            for (std::size_t channel = 0; channel < etl::dim<0>(input); ++channel) {
                for (int x = 0; x < int(width); ++x) {
                    for (int y = 0; y < int(height); ++y) {
                        auto dx = d_x_blur(x, y);
                        auto dy = d_y_blur(x, y);

                        weight px = x + dx;
                        weight py = y + dy;

                        weight a = safe(channel, std::floor(px), std::floor(py));
                        weight b = safe(channel, std::ceil(px), std::floor(py));
                        weight c = safe(channel, std::ceil(px), std::ceil(py));
                        weight d = safe(channel, std::floor(px), std::ceil(py));

                        auto e = a * (1.0 - (px - std::floor(px))) + d * (px - std::floor(px));
                        auto f = b * (1.0 - (px - std::floor(px))) + c * (px - std::floor(px));

                        auto value = e * (1.0 - (py - std::floor(py))) + f * (py - std::floor(py));

                        result(channel, x, y) = value;
                    }
                }
            }

            output.push_back(result);
        }
    }

    static void concat_name(std::string& name) {
        name += " elastic<" + std::to_string(C) + ", " + std::to_string(K) + ">";
    }
};

} //end of dll namespace
<|endoftext|>


<commit_before>// Copyright 2014, Max Planck Institute for Intelligent Systems.
// Distributed under the BSD 3-Clause license.
// (See accompanying file LICENSE.txt or copy at
// http://opensource.org/licenses/BSD-3-Clause)

#ifndef ROBUST_PCA_TEST_MAIN_HPP__
#define ROBUST_PCA_TEST_MAIN_HPP__

#include <boost/random/mersenne_twister.hpp>
#include <boost/numeric/ublas/matrix.hpp>
// generating data randomly
#include <boost/random/uniform_real_distribution.hpp>

#include <fstream>

// random number generator
extern boost::random::mt19937 rng;

//#define FLUSH_MATRIX_TO_FILE
const int DATA_DIMENSION=500;

// Fixture for the tests
struct fixture_simple_matrix_creation
{
  typedef boost::numeric::ublas::matrix<double> matrix_t;

  static const int nb_elements;// = 1000;
  static const int dimensions;// = 5;
  matrix_t mat_data;

  boost::random::uniform_real_distribution<double> dist;

  fixture_simple_matrix_creation() : dist(-1000, 1000)
  {
    // creating some data, 1000 lines of a vector of length 5
    mat_data.resize(nb_elements, dimensions);

    // default seed for reproductible sequences
    rng.seed();

    //std::cout << "current seed : " << ;
#ifdef FLUSH_MATRIX_TO_FILE
    const std::string filename = "./toto.txt";
    std::ofstream ff(filename.c_str());

    BOOST_REQUIRE(ff.is_open());
#endif

    for(int i = 0; i < nb_elements; i++)
    {
      for(int j = 0; j < dimensions; j++)
      {
        mat_data(i, j) = dist(rng);
#ifdef FLUSH_MATRIX_TO_FILE
        ff << mat_data(i, j) << " ";
#endif
      }
#ifdef FLUSH_MATRIX_TO_FILE
      ff << std::endl;
#endif
    }

  }
};

#endif /* ROBUST_PCA_TEST_MAIN_HPP__ */
<commit_msg>500 dimension for tests<commit_after>// Copyright 2014, Max Planck Institute for Intelligent Systems.
// Distributed under the BSD 3-Clause license.
// (See accompanying file LICENSE.txt or copy at
// http://opensource.org/licenses/BSD-3-Clause)

#ifndef ROBUST_PCA_TEST_MAIN_HPP__
#define ROBUST_PCA_TEST_MAIN_HPP__

#include <boost/random/mersenne_twister.hpp>
#include <boost/numeric/ublas/matrix.hpp>
// generating data randomly
#include <boost/random/uniform_real_distribution.hpp>

#include <fstream>

// random number generator
extern boost::random::mt19937 rng;

//#define FLUSH_MATRIX_TO_FILE
const int DATA_DIMENSION=100;

// Fixture for the tests
struct fixture_simple_matrix_creation
{
  typedef boost::numeric::ublas::matrix<double> matrix_t;

  static const int nb_elements;// = 1000;
  static const int dimensions;// = 5;
  matrix_t mat_data;

  boost::random::uniform_real_distribution<double> dist;

  fixture_simple_matrix_creation() : dist(-1000, 1000)
  {
    // creating some data, 1000 lines of a vector of length 5
    mat_data.resize(nb_elements, dimensions);

    // default seed for reproductible sequences
    rng.seed();

    //std::cout << "current seed : " << ;
#ifdef FLUSH_MATRIX_TO_FILE
    const std::string filename = "./toto.txt";
    std::ofstream ff(filename.c_str());

    BOOST_REQUIRE(ff.is_open());
#endif

    for(int i = 0; i < nb_elements; i++)
    {
      for(int j = 0; j < dimensions; j++)
      {
        mat_data(i, j) = dist(rng);
#ifdef FLUSH_MATRIX_TO_FILE
        ff << mat_data(i, j) << " ";
#endif
      }
#ifdef FLUSH_MATRIX_TO_FILE
      ff << std::endl;
#endif
    }

  }
};

#endif /* ROBUST_PCA_TEST_MAIN_HPP__ */
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/visualization/software-license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

/**
ACKNOWLEDGMENTS:
  This software was written in 2012-2013 by Hal Canary
  <cs.unc.edu/~hal>, based off of the MADAIEmulator program (Copyright
  2009-2012 Duke University) by C.Coleman-Smith <cec24@phy.duke.edu>
  in 2010-2012 while working for the MADAI project <http://madai.us/>.
*/

#include <iostream>
#include <fstream>

#include "ApplicationUtilities.h"
#include "GaussianProcessEmulator.h"
#include "GaussianDistribution.h"
#include "GaussianProcessEmulatorDirectoryReader.h"
#include "GaussianProcessEmulatorSingleFileReader.h"
#include "RuntimeParameterFileReader.h"
#include "UniformDistribution.h"
#include "Paths.h"
#include "Defaults.h"

using madai::Paths;

std::ostream & operator <<(std::ostream & o, const madai::Distribution * d) {
  const madai::UniformDistribution * uniformPriorDist
    = dynamic_cast<const madai::UniformDistribution *>(d);
  const madai::GaussianDistribution * gaussianPriorDist
    = dynamic_cast<const madai::GaussianDistribution *>(d);
  if (uniformPriorDist != NULL) {
    return o << "UNIFORM" << '\t'
      << uniformPriorDist->GetMinimum() << '\t'
      << uniformPriorDist->GetMaximum();
  } else if (gaussianPriorDist != NULL) {
    return o << "GAUSSIAN" << '\t'
      << gaussianPriorDist->GetMean() << '\t'
      << gaussianPriorDist->GetStandardDeviation();
  } else {
    assert(false);
    return o << "UNKNOWN_PRIOR_TYPE\t0\t1\n";
  }
}

std::ostream & operator <<(std::ostream & o, const madai::Parameter & param) {
  return o << param.m_Name << '\t' << param.GetPriorDistribution();
}

/**
   The meat of the program.  Interactive query of the model. */
bool Interact(
    madai::GaussianProcessEmulator & gpme,
    std::istream & input,
    std::ostream & output,
    bool writeHeader )
{
  unsigned int p = gpme.m_NumberParameters;
  unsigned int t = gpme.m_NumberOutputs;
  std::vector< double > the_point(p,0.0);
  std::vector< double > the_mean(t,0.0);
  std::vector< double > the_covariance((t * t),0.0);

  output.precision(17);
  if ( writeHeader ) {
    output
      << "VERSION 1\n"
      << "PARAMETERS\n"
      << p << '\n';
    for(unsigned int i = 0; i < p; i++) {
      output << gpme.m_Parameters[i] << '\n';
    }
    output <<"OUTPUTS\n" << t << '\n';

    for(unsigned int i = 0; i < t; i++) {
      output << gpme.m_OutputNames[i] << '\n';
    }
    output << "COVARIANCE\n" << "TRIANGULAR_MATRIX\n"
           << ((t * (t + 1)) / 2) << '\n';
    /*
      For example, a 5x5 symmetric matrix can be represented with
      (5*(5+1)/2)=15 numbers.  If the layout of the matrix is:
          1 2 3 4 5
          2 6 7 8 9
          3 7 a b c
          4 8 b d e
          5 9 c e f
      Then we will serialize it as:
          1 2 3 4 5 6 7 8 9 a b c d e f
      To save time.
    */
    output << "END_OF_HEADER\n";
  }
  output.flush();

  while (input.good()) {
    for(unsigned int i =0; i < p; i++) {
      if (!(input >> the_point[i]))
        return (input.eof());
    }
    if (! gpme.GetEmulatorOutputsAndCovariance (
            the_point, the_mean, the_covariance))
      return false;
    for(unsigned int i =0; i < t; i++) {
      output << the_mean[i] << '\n';
    }
    for(unsigned int i = 0; i < t; i++) {
      for(unsigned int j = (i); j < t; j++) {
        output << the_covariance[(i*t)+j] << '\n';
      }
    }
    output.flush();
  }
  return (input.eof());
}

int main(int argc, char ** argv) {
  if ( argc < 2 ) {
    std::cerr << "Usage:\n"
              << "    " << argv[0] << " <StatisticsDirectory>\n"
              << "\n"
              << "This program provides a pipe interface to a trained \n"
              << "emulator. \n"
              << "\n"
              << "<StatisticsDirectory> is the directory in which all \n"
              << "statistics data are stored. It contains the parameter file "
              << Paths::RUNTIME_PARAMETER_FILE << "\n"
              << "\n"
              << "Format of entries in " << Paths::RUNTIME_PARAMETER_FILE
              << ":\n\n"
              << "MODEL_OUTPUT_DIRECTORY <value> (default: "
              << madai::Defaults::MODEL_OUTPUT_DIRECTORY << ")\n"
              << "EXPERIMENTAL_RESULTS_FILE <value> (default: "
              << madai::Defaults::EXPERIMENTAL_RESULTS_FILE << ")\n"
              << "EMULATE_QUIET <value> ("
              << madai::Defaults::EMULATE_QUIET << ")\n"
              << "READER_VERBOSE <value> (default: "
              << madai::Defaults::READER_VERBOSE << ")\n";

    return EXIT_FAILURE;
  }
  std::string statisticsDirectory( argv[1] );
  madai::EnsurePathSeparatorAtEnd( statisticsDirectory );

  madai::RuntimeParameterFileReader settings;
  std::string settingsFile = statisticsDirectory + madai::Paths::RUNTIME_PARAMETER_FILE;
  if ( !settings.ParseFile( settingsFile ) ) {
    std::cerr << "Could not open runtime parameter file '" << settingsFile << "'\n";
    return EXIT_FAILURE;
  }

  std::string modelOutputDirectory =
    madai::GetModelOutputDirectory( statisticsDirectory, settings );
  std::string experimentalResultsFile =
    madai::GetExperimentalResultsFile( statisticsDirectory, settings );

  bool emulatorWriteHeader = madai::Defaults::EMULATE_WRITE_HEADER;
  if ( settings.HasOption( "EMULATE_WRITE_HEADER" ) ) {
    emulatorWriteHeader = ( settings.GetOption( "EMULATE_WRITE_HEADER" ) == "true" );
  }

  madai::GaussianProcessEmulator gpe;
  madai::GaussianProcessEmulatorDirectoryReader directoryReader;
  bool verbose = settings.GetOptionAsBool(
      "READER_VERBOSE", madai::Defaults::READER_VERBOSE );
  directoryReader.SetVerbose( verbose );

  if ( !directoryReader.LoadTrainingData( &gpe,
                                          modelOutputDirectory,
                                          statisticsDirectory,
                                          experimentalResultsFile ) ) {
    std::cerr << "Error loading training data.\n";
    return EXIT_FAILURE;
  }

  if ( !directoryReader.LoadPCA( &gpe, statisticsDirectory ) ) {
    std::cerr << "Error loading PCA data.\n";
    return EXIT_FAILURE;
  }

  if ( !directoryReader.LoadEmulator( &gpe, statisticsDirectory ) ) {
    std::cerr << "Error loading the emulator state data.\n";
    return EXIT_FAILURE;
  }

  if ( gpe.GetStatus() != madai::GaussianProcessEmulator::READY ) {
    return EXIT_FAILURE;
  }

  if ( Interact( gpe, std::cin, std::cout, emulatorWriteHeader ) ) {
    return EXIT_SUCCESS;
  } else {
    return EXIT_FAILURE;
  }
}
<commit_msg>GetOptions Default in madai_emulate<commit_after>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/visualization/software-license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

/**
ACKNOWLEDGMENTS:
  This software was written in 2012-2013 by Hal Canary
  <cs.unc.edu/~hal>, based off of the MADAIEmulator program (Copyright
  2009-2012 Duke University) by C.Coleman-Smith <cec24@phy.duke.edu>
  in 2010-2012 while working for the MADAI project <http://madai.us/>.
*/

#include <iostream>
#include <fstream>

#include "ApplicationUtilities.h"
#include "GaussianProcessEmulator.h"
#include "GaussianDistribution.h"
#include "GaussianProcessEmulatorDirectoryReader.h"
#include "GaussianProcessEmulatorSingleFileReader.h"
#include "RuntimeParameterFileReader.h"
#include "UniformDistribution.h"
#include "Paths.h"
#include "Defaults.h"

using madai::Paths;

std::ostream & operator <<(std::ostream & o, const madai::Distribution * d) {
  const madai::UniformDistribution * uniformPriorDist
    = dynamic_cast<const madai::UniformDistribution *>(d);
  const madai::GaussianDistribution * gaussianPriorDist
    = dynamic_cast<const madai::GaussianDistribution *>(d);
  if (uniformPriorDist != NULL) {
    return o << "UNIFORM" << '\t'
      << uniformPriorDist->GetMinimum() << '\t'
      << uniformPriorDist->GetMaximum();
  } else if (gaussianPriorDist != NULL) {
    return o << "GAUSSIAN" << '\t'
      << gaussianPriorDist->GetMean() << '\t'
      << gaussianPriorDist->GetStandardDeviation();
  } else {
    assert(false);
    return o << "UNKNOWN_PRIOR_TYPE\t0\t1\n";
  }
}

std::ostream & operator <<(std::ostream & o, const madai::Parameter & param) {
  return o << param.m_Name << '\t' << param.GetPriorDistribution();
}

/**
   The meat of the program.  Interactive query of the model. */
bool Interact(
    madai::GaussianProcessEmulator & gpme,
    std::istream & input,
    std::ostream & output,
    bool writeHeader )
{
  unsigned int p = gpme.m_NumberParameters;
  unsigned int t = gpme.m_NumberOutputs;
  std::vector< double > the_point(p,0.0);
  std::vector< double > the_mean(t,0.0);
  std::vector< double > the_covariance((t * t),0.0);

  output.precision(17);
  if ( writeHeader ) {
    output
      << "VERSION 1\n"
      << "PARAMETERS\n"
      << p << '\n';
    for(unsigned int i = 0; i < p; i++) {
      output << gpme.m_Parameters[i] << '\n';
    }
    output <<"OUTPUTS\n" << t << '\n';

    for(unsigned int i = 0; i < t; i++) {
      output << gpme.m_OutputNames[i] << '\n';
    }
    output << "COVARIANCE\n" << "TRIANGULAR_MATRIX\n"
           << ((t * (t + 1)) / 2) << '\n';
    /*
      For example, a 5x5 symmetric matrix can be represented with
      (5*(5+1)/2)=15 numbers.  If the layout of the matrix is:
          1 2 3 4 5
          2 6 7 8 9
          3 7 a b c
          4 8 b d e
          5 9 c e f
      Then we will serialize it as:
          1 2 3 4 5 6 7 8 9 a b c d e f
      To save time.
    */
    output << "END_OF_HEADER\n";
  }
  output.flush();

  while (input.good()) {
    for(unsigned int i =0; i < p; i++) {
      if (!(input >> the_point[i]))
        return (input.eof());
    }
    if (! gpme.GetEmulatorOutputsAndCovariance (
            the_point, the_mean, the_covariance))
      return false;
    for(unsigned int i =0; i < t; i++) {
      output << the_mean[i] << '\n';
    }
    for(unsigned int i = 0; i < t; i++) {
      for(unsigned int j = (i); j < t; j++) {
        output << the_covariance[(i*t)+j] << '\n';
      }
    }
    output.flush();
  }
  return (input.eof());
}

int main(int argc, char ** argv) {
  if ( argc < 2 ) {
    std::cerr << "Usage:\n"
              << "    " << argv[0] << " <StatisticsDirectory>\n"
              << "\n"
              << "This program provides a pipe interface to a trained \n"
              << "emulator. \n"
              << "\n"
              << "<StatisticsDirectory> is the directory in which all \n"
              << "statistics data are stored. It contains the parameter file "
              << Paths::RUNTIME_PARAMETER_FILE << "\n"
              << "\n"
              << "Format of entries in " << Paths::RUNTIME_PARAMETER_FILE
              << ":\n\n"
              << "MODEL_OUTPUT_DIRECTORY <value> (default: "
              << madai::Defaults::MODEL_OUTPUT_DIRECTORY << ")\n"
              << "EXPERIMENTAL_RESULTS_FILE <value> (default: "
              << madai::Defaults::EXPERIMENTAL_RESULTS_FILE << ")\n"
              << "EMULATE_QUIET <value> ("
              << madai::Defaults::EMULATE_QUIET << ")\n"
              << "READER_VERBOSE <value> (default: "
              << madai::Defaults::READER_VERBOSE << ")\n";

    return EXIT_FAILURE;
  }
  std::string statisticsDirectory( argv[1] );
  madai::EnsurePathSeparatorAtEnd( statisticsDirectory );

  madai::RuntimeParameterFileReader settings;
  std::string settingsFile = statisticsDirectory + madai::Paths::RUNTIME_PARAMETER_FILE;
  if ( !settings.ParseFile( settingsFile ) ) {
    std::cerr << "Could not open runtime parameter file '" << settingsFile << "'\n";
    return EXIT_FAILURE;
  }

  std::string modelOutputDirectory =
    madai::GetModelOutputDirectory( statisticsDirectory, settings );
  std::string experimentalResultsFile =
    madai::GetExperimentalResultsFile( statisticsDirectory, settings );

  bool emulatorWriteHeader = settings.GetOptionAsBool(
      "EMULATE_WRITE_HEADER",
      madai::Defaults::EMULATE_WRITE_HEADER);

  madai::GaussianProcessEmulator gpe;
  madai::GaussianProcessEmulatorDirectoryReader directoryReader;
  bool verbose = settings.GetOptionAsBool(
      "READER_VERBOSE", madai::Defaults::READER_VERBOSE );
  directoryReader.SetVerbose( verbose );

  if ( !directoryReader.LoadTrainingData( &gpe,
                                          modelOutputDirectory,
                                          statisticsDirectory,
                                          experimentalResultsFile ) ) {
    std::cerr << "Error loading training data.\n";
    return EXIT_FAILURE;
  }

  if ( !directoryReader.LoadPCA( &gpe, statisticsDirectory ) ) {
    std::cerr << "Error loading PCA data.\n";
    return EXIT_FAILURE;
  }

  if ( !directoryReader.LoadEmulator( &gpe, statisticsDirectory ) ) {
    std::cerr << "Error loading the emulator state data.\n";
    return EXIT_FAILURE;
  }

  if ( gpe.GetStatus() != madai::GaussianProcessEmulator::READY ) {
    return EXIT_FAILURE;
  }

  if ( Interact( gpe, std::cin, std::cout, emulatorWriteHeader ) ) {
    return EXIT_SUCCESS;
  } else {
    return EXIT_FAILURE;
  }
}
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "../bse.hh"
#include "v8bse.cc"
#include <node.h>
#include <uv.h>

// v8pp binding for Bse
static V8stub *bse_v8stub = NULL;

// event loop integration
static uv_poll_t                         bse_uv_watcher;
static Rapicorn::Aida::ClientConnectionP bse_client_connection;
static Bse::ServerH                      bse_server;

// register bindings and start Bse
static void
v8bse_register_module (v8::Local<v8::Object> exports)
{
  assert (bse_v8stub == NULL);
  v8::Isolate *const isolate = v8::Isolate::GetCurrent();
  v8::HandleScope scope (isolate);

  // start Bse
  Bse::String bseoptions = Bse::string_format ("debug-extensions=%d", 0);
  Bse::init_async (NULL, NULL, "BEAST", Bse::string_split (bseoptions, ":"));

  // fetch server handle
  assert (bse_server == NULL);
  assert (bse_client_connection == NULL);
  bse_client_connection = Bse::init_server_connection();
  assert (bse_client_connection != NULL);
  bse_server = Bse::init_server_instance();
  assert (bse_server != NULL);

  // hook BSE connection into libuv event loop
  uv_loop_t *loop = uv_default_loop();
  uv_poll_init (loop, &bse_uv_watcher, bse_client_connection->notify_fd());
  auto bse_uv_callback = [] (uv_poll_t *watcher, int status, int revents) {
    if (bse_client_connection && bse_client_connection->pending())
      bse_client_connection->dispatch();
  };
  uv_poll_start (&bse_uv_watcher, UV_READABLE, bse_uv_callback);

  // hook BSE connection into GLib event loop
  Bse::AidaGlibSource *source = Bse::AidaGlibSource::create (bse_client_connection.get());
  g_source_set_priority (source, G_PRIORITY_DEFAULT);
  g_source_attach (source, g_main_context_default());

  // register v8stub
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  bse_v8stub = new V8stub (isolate);
  v8::Local<v8::Object> module_instance = bse_v8stub->module_.new_instance();
  v8::Maybe<bool> ok = exports->SetPrototype (context, module_instance);
  assert (ok.FromJust() == true);

  // export server handle
  V8ppType_BseServer &class_ = bse_v8stub->BseServer_class_;
  v8::Local<v8::Object> v8_server = class_.import_external (isolate, new Bse::ServerH (bse_server));
  module_instance->DefineOwnProperty (context, v8pp::to_v8 (isolate, "server"),
                                      v8_server, v8::PropertyAttribute (v8::ReadOnly | v8::DontDelete));
}

// node.js registration
NODE_MODULE (v8bse, v8bse_register_module);
<commit_msg>V8BSE: add inactive debugging aid<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "../bse.hh"
#include "v8bse.cc"
#include <node.h>
#include <uv.h>

// v8pp binding for Bse
static V8stub *bse_v8stub = NULL;

// event loop integration
static uv_poll_t                         bse_uv_watcher;
static Rapicorn::Aida::ClientConnectionP bse_client_connection;
static Bse::ServerH                      bse_server;

// register bindings and start Bse
static void
v8bse_register_module (v8::Local<v8::Object> exports)
{
  assert (bse_v8stub == NULL);
  v8::Isolate *const isolate = v8::Isolate::GetCurrent();
  v8::HandleScope scope (isolate);

  // start Bse
  Bse::String bseoptions = Bse::string_format ("debug-extensions=%d", 0);
  Bse::init_async (NULL, NULL, "BEAST", Bse::string_split (bseoptions, ":"));

  // fetch server handle
  assert (bse_server == NULL);
  assert (bse_client_connection == NULL);
  bse_client_connection = Bse::init_server_connection();
  assert (bse_client_connection != NULL);
  bse_server = Bse::init_server_instance();
  assert (bse_server != NULL);

  // hook BSE connection into libuv event loop
  uv_loop_t *loop = uv_default_loop();
  uv_poll_init (loop, &bse_uv_watcher, bse_client_connection->notify_fd());
  auto bse_uv_callback = [] (uv_poll_t *watcher, int status, int revents) {
    if (bse_client_connection && bse_client_connection->pending())
      bse_client_connection->dispatch();
  };
  uv_poll_start (&bse_uv_watcher, UV_READABLE, bse_uv_callback);

  // hook BSE connection into GLib event loop
  Bse::AidaGlibSource *source = Bse::AidaGlibSource::create (bse_client_connection.get());
  g_source_set_priority (source, G_PRIORITY_DEFAULT);
  g_source_attach (source, g_main_context_default());

  // register v8stub
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  bse_v8stub = new V8stub (isolate);
  v8::Local<v8::Object> module_instance = bse_v8stub->module_.new_instance();
  v8::Maybe<bool> ok = exports->SetPrototype (context, module_instance);
  assert (ok.FromJust() == true);

  // export server handle
  V8ppType_BseServer &class_ = bse_v8stub->BseServer_class_;
  v8::Local<v8::Object> v8_server = class_.import_external (isolate, new Bse::ServerH (bse_server));
  module_instance->DefineOwnProperty (context, v8pp::to_v8 (isolate, "server"),
                                      v8_server, v8::PropertyAttribute (v8::ReadOnly | v8::DontDelete));

  // debugging aids:
  if (0)
    printerr ("gdb %s %u -ex 'catch catch' -ex 'catch throw'\n", program_invocation_name, Rapicorn::ThisThread::process_pid());
}

// node.js registration
NODE_MODULE (v8bse, v8bse_register_module);
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "master/quota.hpp"

#include <string>

#include <mesos/mesos.hpp>
#include <mesos/quota/quota.hpp>
#include <mesos/resource_quantities.hpp>
#include <mesos/resources.hpp>
#include <mesos/roles.hpp>
#include <mesos/values.hpp>

#include <stout/error.hpp>
#include <stout/option.hpp>
#include <stout/set.hpp>

#include "common/protobuf_utils.hpp"
#include "common/resources_utils.hpp"
#include "common/validation.hpp"

#include "master/constants.hpp"

using google::protobuf::Map;
using google::protobuf::RepeatedPtrField;

using mesos::quota::QuotaConfig;
using mesos::quota::QuotaInfo;
using mesos::quota::QuotaRequest;

using std::string;

namespace mesos {
namespace internal {
namespace master {
namespace quota {

UpdateQuota::UpdateQuota(
    const google::protobuf::RepeatedPtrField<QuotaConfig>& quotaConfigs)
  : configs(quotaConfigs) {}

Try<bool> UpdateQuota::perform(
    Registry* registry, hashset<SlaveID>* /*slaveIDs*/)
{
  google::protobuf::RepeatedPtrField<QuotaConfig>& registryConfigs =
    *registry->mutable_quota_configs();

  foreach (const QuotaConfig& config, configs) {
    // Check if there is already quota stored for the role.
    int configIndex = find_if(
        registryConfigs.begin(),
        registryConfigs.end(),
        [&](const QuotaConfig& registryConfig) {
          return registryConfig.role() == config.role();
        }) -
        registryConfigs.begin();

    if (Quota(config) == DEFAULT_QUOTA) {
      // Erase if present, otherwise no-op.
      if (configIndex < registryConfigs.size()) {
        registryConfigs.DeleteSubrange(configIndex, 1);
      }
    } else {
      // Modify if present, otherwise insert.
      if (configIndex < registryConfigs.size()) {
        // TODO(mzhu): Check if we are setting quota to the same value.
        // If so, no need to mutate.
        *registryConfigs.Mutable(configIndex) = config;
      } else {
        *registryConfigs.Add() = config;
      }
    }

    // Remove the old `QuotaInfo` entries if any.

    google::protobuf::RepeatedPtrField<Registry::Quota>& quotas =
      *registry->mutable_quotas();

    int quotaIndex = find_if(
        quotas.begin(),
        quotas.end(),
        [&](const Registry::Quota& quota) {
        return quota.info().role() == config.role();
        }) -
        quotas.begin();

    if (quotaIndex < quotas.size()) {
      quotas.DeleteSubrange(quotaIndex, 1);
    }
  }

  // Update the minimum capability.
  if (!registryConfigs.empty()) {
    protobuf::master::addMinimumCapability(
        registry->mutable_minimum_capabilities(),
        MasterInfo::Capability::QUOTA_V2);
  } else {
    protobuf::master::removeMinimumCapability(
        registry->mutable_minimum_capabilities(),
        MasterInfo::Capability::QUOTA_V2);
  }

  // We always return true here since there is currently
  // no optimization for no mutation case.
  return true;
}

namespace {

QuotaInfo createQuotaInfo(
    const string& role,
    const RepeatedPtrField<Resource>& guarantee)
{
  QuotaInfo quota;

  quota.set_role(role);
  quota.mutable_guarantee()->CopyFrom(guarantee);

  return quota;
}

} // namespace {

QuotaInfo createQuotaInfo(const QuotaRequest& request)
{
  return createQuotaInfo(request.role(), request.guarantee());
}

namespace validation {

Option<Error> quotaInfo(const QuotaInfo& quotaInfo)
{
  if (!quotaInfo.has_role()) {
    return Error("QuotaInfo must specify a role");
  }

  // Check the provided role is valid.
  Option<Error> roleError = roles::validate(quotaInfo.role());
  if (roleError.isSome()) {
    return Error("QuotaInfo with invalid role: " + roleError->message);
  }

  // Check that `QuotaInfo` contains at least one guarantee.
  // TODO(alexr): Relaxing this may make sense once quota is the
  // only way that we offer non-revocable resources. Setting quota
  // with an empty guarantee would mean the role is not entitled to
  // get non-revocable offers.
  if (quotaInfo.guarantee().empty()) {
    return Error("QuotaInfo with empty 'guarantee'");
  }

  hashset<string> names;

  foreach (const Resource& resource, quotaInfo.guarantee()) {
    // Check that `resource` does not contain fields that are
    // irrelevant for quota.
    if (resource.reservations_size() > 0) {
      return Error("QuotaInfo must not contain any ReservationInfo");
    }

    if (resource.has_disk()) {
      return Error("QuotaInfo must not contain DiskInfo");
    }

    if (resource.has_revocable()) {
      return Error("QuotaInfo must not contain RevocableInfo");
    }

    if (resource.type() != Value::SCALAR) {
      return Error("QuotaInfo must not include non-scalar resources");
    }

    // Check that resource names do not repeat.
    if (names.contains(resource.name())) {
      return Error("QuotaInfo contains duplicate resource name"
                   " '" + resource.name() + "'");
    }

    names.insert(resource.name());
  }

  return None();
}

} // namespace validation {

Option<Error> validate(const QuotaConfig& config)
{
  if (!config.has_role()) {
    return Error("'QuotaConfig.role' must be set");
  }

  // Check the provided role is valid.
  Option<Error> error = roles::validate(config.role());
  if (error.isSome()) {
    return Error("Invalid 'QuotaConfig.role': " + error->message);
  }

  // Validate scalar values.
  foreach (auto&& guarantee, config.guarantees()) {
    Option<Error> error =
      common::validation::validateInputScalarValue(guarantee.second.value());

    if (error.isSome()) {
      return Error(
          "Invalid guarantee configuration {'" + guarantee.first + "': " +
          stringify(guarantee.second) + "}: " + error->message);
    }
  }

  foreach (auto&& limit, config.limits()) {
    Option<Error> error =
      common::validation::validateInputScalarValue(limit.second.value());

    if (error.isSome()) {
      return Error(
          "Invalid limit configuration {'" + limit.first + "': " +
          stringify(limit.second) + "}: " + error->message);
    }
  }

  // Validate guarantees <= limits.
  ResourceLimits limits{config.limits()};
  ResourceQuantities guarantees{config.guarantees()};

  if (!limits.contains(guarantees)) {
    return Error(
        "'QuotaConfig.guarantees' " + stringify(config.guarantees()) +
        " is not contained within the 'QuotaConfig.limits' " +
        stringify(config.limits()));
  }

  return None();
}

} // namespace quota {
} // namespace master {
} // namespace internal {

Quota::Quota(const QuotaConfig& config)
{
  guarantees = ResourceQuantities(config.guarantees());
  limits = ResourceLimits(config.limits());
}

Quota::Quota(const QuotaInfo& info)
{
  guarantees = ResourceQuantities::fromScalarResources(info.guarantee());

  // For legacy `QuotaInfo`, guarantee also acts as limit.
  limits = [&info]() {
    google::protobuf::Map<string, Value::Scalar> limits;
    foreach (const Resource& r, info.guarantee()) {
      limits[r.name()] = r.scalar();
    }
    return ResourceLimits(limits);
  }();
}

Quota::Quota(const QuotaRequest& request)
{
  guarantees = ResourceQuantities::fromScalarResources(request.guarantee());

  // For legacy `QuotaInfo`, guarantee also acts as limit.
  limits = [&request]() {
    google::protobuf::Map<string, Value::Scalar> limits;
    foreach (const Resource& r, request.guarantee()) {
      limits[r.name()] = r.scalar();
    }
    return ResourceLimits(limits);
  }();
}

bool Quota::operator==(const Quota& that) const
{
  return guarantees == that.guarantees && limits == that.limits;
}

bool Quota::operator!=(const Quota& that) const
{
  return guarantees != that.guarantees || limits != that.limits;
}

} // namespace mesos {
<commit_msg>Added quota config validation for large numbers.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "master/quota.hpp"

#include <string>

#include <mesos/mesos.hpp>
#include <mesos/quota/quota.hpp>
#include <mesos/resource_quantities.hpp>
#include <mesos/resources.hpp>
#include <mesos/roles.hpp>
#include <mesos/values.hpp>

#include <stout/error.hpp>
#include <stout/option.hpp>
#include <stout/set.hpp>

#include "common/protobuf_utils.hpp"
#include "common/resources_utils.hpp"
#include "common/validation.hpp"

#include "master/constants.hpp"

using google::protobuf::Map;
using google::protobuf::RepeatedPtrField;

using mesos::quota::QuotaConfig;
using mesos::quota::QuotaInfo;
using mesos::quota::QuotaRequest;

using std::string;

namespace mesos {
namespace internal {
namespace master {
namespace quota {

UpdateQuota::UpdateQuota(
    const google::protobuf::RepeatedPtrField<QuotaConfig>& quotaConfigs)
  : configs(quotaConfigs) {}

Try<bool> UpdateQuota::perform(
    Registry* registry, hashset<SlaveID>* /*slaveIDs*/)
{
  google::protobuf::RepeatedPtrField<QuotaConfig>& registryConfigs =
    *registry->mutable_quota_configs();

  foreach (const QuotaConfig& config, configs) {
    // Check if there is already quota stored for the role.
    int configIndex = find_if(
        registryConfigs.begin(),
        registryConfigs.end(),
        [&](const QuotaConfig& registryConfig) {
          return registryConfig.role() == config.role();
        }) -
        registryConfigs.begin();

    if (Quota(config) == DEFAULT_QUOTA) {
      // Erase if present, otherwise no-op.
      if (configIndex < registryConfigs.size()) {
        registryConfigs.DeleteSubrange(configIndex, 1);
      }
    } else {
      // Modify if present, otherwise insert.
      if (configIndex < registryConfigs.size()) {
        // TODO(mzhu): Check if we are setting quota to the same value.
        // If so, no need to mutate.
        *registryConfigs.Mutable(configIndex) = config;
      } else {
        *registryConfigs.Add() = config;
      }
    }

    // Remove the old `QuotaInfo` entries if any.

    google::protobuf::RepeatedPtrField<Registry::Quota>& quotas =
      *registry->mutable_quotas();

    int quotaIndex = find_if(
        quotas.begin(),
        quotas.end(),
        [&](const Registry::Quota& quota) {
        return quota.info().role() == config.role();
        }) -
        quotas.begin();

    if (quotaIndex < quotas.size()) {
      quotas.DeleteSubrange(quotaIndex, 1);
    }
  }

  // Update the minimum capability.
  if (!registryConfigs.empty()) {
    protobuf::master::addMinimumCapability(
        registry->mutable_minimum_capabilities(),
        MasterInfo::Capability::QUOTA_V2);
  } else {
    protobuf::master::removeMinimumCapability(
        registry->mutable_minimum_capabilities(),
        MasterInfo::Capability::QUOTA_V2);
  }

  // We always return true here since there is currently
  // no optimization for no mutation case.
  return true;
}

namespace {

QuotaInfo createQuotaInfo(
    const string& role,
    const RepeatedPtrField<Resource>& guarantee)
{
  QuotaInfo quota;

  quota.set_role(role);
  quota.mutable_guarantee()->CopyFrom(guarantee);

  return quota;
}

} // namespace {

QuotaInfo createQuotaInfo(const QuotaRequest& request)
{
  return createQuotaInfo(request.role(), request.guarantee());
}

namespace validation {

Option<Error> quotaInfo(const QuotaInfo& quotaInfo)
{
  if (!quotaInfo.has_role()) {
    return Error("QuotaInfo must specify a role");
  }

  // Check the provided role is valid.
  Option<Error> roleError = roles::validate(quotaInfo.role());
  if (roleError.isSome()) {
    return Error("QuotaInfo with invalid role: " + roleError->message);
  }

  // Check that `QuotaInfo` contains at least one guarantee.
  // TODO(alexr): Relaxing this may make sense once quota is the
  // only way that we offer non-revocable resources. Setting quota
  // with an empty guarantee would mean the role is not entitled to
  // get non-revocable offers.
  if (quotaInfo.guarantee().empty()) {
    return Error("QuotaInfo with empty 'guarantee'");
  }

  hashset<string> names;

  foreach (const Resource& resource, quotaInfo.guarantee()) {
    // Check that `resource` does not contain fields that are
    // irrelevant for quota.
    if (resource.reservations_size() > 0) {
      return Error("QuotaInfo must not contain any ReservationInfo");
    }

    if (resource.has_disk()) {
      return Error("QuotaInfo must not contain DiskInfo");
    }

    if (resource.has_revocable()) {
      return Error("QuotaInfo must not contain RevocableInfo");
    }

    if (resource.type() != Value::SCALAR) {
      return Error("QuotaInfo must not include non-scalar resources");
    }

    // Check that resource names do not repeat.
    if (names.contains(resource.name())) {
      return Error("QuotaInfo contains duplicate resource name"
                   " '" + resource.name() + "'");
    }

    names.insert(resource.name());
  }

  return None();
}

} // namespace validation {

Option<Error> validate(const QuotaConfig& config)
{
  if (!config.has_role()) {
    return Error("'QuotaConfig.role' must be set");
  }

  // Check the provided role is valid.
  Option<Error> error = roles::validate(config.role());
  if (error.isSome()) {
    return Error("Invalid 'QuotaConfig.role': " + error->message);
  }

  // Before we validate the scalars, we need to check for
  // our maximum supported quota values. Otherwise, they
  // will surface as a generic overflow error in the scalar
  // validation below.
  //
  // The underlying fixed precision logic used for
  // Value::Scalar overflows between:
  //
  //   9,223,372,036,854,774 and (ditto) + 1.0
  //
  //   double d = 9223372036854774;
  //   d += 1.0;
  //   Value::scalar s, zero;
  //   s.set_value(d);
  //   s < zero == true; // overflow!
  //
  // This works out to ~9 zettabytes (given we use megabytes
  // as the base unit), we set a limit of 1 exabyte, and we
  // can increase this later if needed.
  //
  // We also impose a limit on cpu, ports and other types of
  // 1 trillion.

  const int64_t exabyteInMegabytes = 1024ll * 1024ll * 1024ll * 1024ll;
  const int64_t otherLimit = 1000ll * 1000ll * 1000ll * 1000ll;

  auto validateTooLarge = [&](
      const Map<string, Value::Scalar>& m) -> Option<Error> {
    foreach (auto&& pair, m) {
      if (pair.first == "mem" || pair.first == "disk") {
        if (pair.second.value() > exabyteInMegabytes) {
          return Error(
              "{'" + pair.first + "': " + stringify(pair.second) + "}"
              " is invalid: values greater than 1 exabyte"
              " (" + stringify(exabyteInMegabytes) + ") are not supported");
        }
      } else if (pair.second.value() > otherLimit) {
        return Error(
            "{'" + pair.first + "': " + stringify(pair.second) + "}"
            " is invalid: values greater than 1 trillion"
            " (" + stringify(otherLimit) + ") are not supported");
      }
    }

    return None();
  };

  error = validateTooLarge(config.guarantees());
  if (error.isSome()) {
    return Error("Invalid 'QuotaConfig.guarantees': " + error->message);
  }

  error = validateTooLarge(config.limits());
  if (error.isSome()) {
    return Error("Invalid 'QuotaConfig.limits': " + error->message);
  }

  // Validate scalar values.
  foreach (auto&& guarantee, config.guarantees()) {
    Option<Error> error =
      common::validation::validateInputScalarValue(guarantee.second.value());

    if (error.isSome()) {
      return Error(
          "Invalid guarantee configuration {'" + guarantee.first + "': " +
          stringify(guarantee.second) + "}: " + error->message);
    }
  }

  foreach (auto&& limit, config.limits()) {
    Option<Error> error =
      common::validation::validateInputScalarValue(limit.second.value());

    if (error.isSome()) {
      return Error(
          "Invalid limit configuration {'" + limit.first + "': " +
          stringify(limit.second) + "}: " + error->message);
    }
  }

  // Validate guarantees <= limits.
  ResourceLimits limits{config.limits()};
  ResourceQuantities guarantees{config.guarantees()};

  if (!limits.contains(guarantees)) {
    return Error(
        "'QuotaConfig.guarantees' " + stringify(config.guarantees()) +
        " is not contained within the 'QuotaConfig.limits' " +
        stringify(config.limits()));
  }

  return None();
}

} // namespace quota {
} // namespace master {
} // namespace internal {

Quota::Quota(const QuotaConfig& config)
{
  guarantees = ResourceQuantities(config.guarantees());
  limits = ResourceLimits(config.limits());
}

Quota::Quota(const QuotaInfo& info)
{
  guarantees = ResourceQuantities::fromScalarResources(info.guarantee());

  // For legacy `QuotaInfo`, guarantee also acts as limit.
  limits = [&info]() {
    google::protobuf::Map<string, Value::Scalar> limits;
    foreach (const Resource& r, info.guarantee()) {
      limits[r.name()] = r.scalar();
    }
    return ResourceLimits(limits);
  }();
}

Quota::Quota(const QuotaRequest& request)
{
  guarantees = ResourceQuantities::fromScalarResources(request.guarantee());

  // For legacy `QuotaInfo`, guarantee also acts as limit.
  limits = [&request]() {
    google::protobuf::Map<string, Value::Scalar> limits;
    foreach (const Resource& r, request.guarantee()) {
      limits[r.name()] = r.scalar();
    }
    return ResourceLimits(limits);
  }();
}

bool Quota::operator==(const Quota& that) const
{
  return guarantees == that.guarantees && limits == that.limits;
}

bool Quota::operator!=(const Quota& that) const
{
  return guarantees != that.guarantees || limits != that.limits;
}

} // namespace mesos {
<|endoftext|>


<commit_before>#include <glib.h>
#include <nan.h>

#include "closure.h"
#include "macros.h"
#include "loop.h"
#include "type.h"
#include "value.h"

using v8::Context;
using v8::Function;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Value;
using Nan::Persistent;

namespace GNodeJS {

GClosure *Closure::New(Local<Function> function, guint signalId) {
    Closure *closure = (Closure *) g_closure_new_simple (sizeof(Closure), NULL);
    closure->persistent.Reset(function);
    GClosure *gclosure = &closure->base;
    g_closure_set_marshal (gclosure, Closure::Marshal);
    g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
    return gclosure;
}

void Closure::Execute(const Nan::Persistent<v8::Function>& persFn, GValue *returnValue, uint nValues, const GValue *values) {
    Nan::HandleScope scope;
    auto fn = Nan::New<Function>(persFn);

    #ifndef __linux__
        Local<Value>* jsArgs = new Local<Value>[nValues];
    #else
        Local<Value> jsArgs[nValues];
    #endif

    for (uint i = 0; i < nValues; i++) {
        bool mustCopy = true; // TODO: get information about mustCopy
        jsArgs[i] = GValueToV8(&values[i], mustCopy);
    }

    Local<Object> self = fn;
    Local<Value> return_value;

    Nan::TryCatch try_catch;

    auto result = Nan::Call(fn, self, nValues, jsArgs);

    if (!try_catch.HasCaught()
            && result.ToLocal(&return_value)) {
        if (returnValue) {
            if (G_VALUE_TYPE(returnValue) == G_TYPE_INVALID)
                WARN ("Marshal: return value has invalid g_type");
            else if (!V8ToGValue (returnValue, return_value, true))
                WARN ("Marshal: could not convert return value");
        }
        CallMicrotaskHandlers();
    }
    else {
        GNodeJS::QuitLoopStack();
        Nan::FatalException(try_catch);
    }

    #ifndef __linux__
        delete[] jsArgs;
    #endif
}

void Closure::Marshal(GClosure     *base,
                      GValue       *g_return_value,
                      uint          n_param_values,
                      const GValue *param_values,
                      gpointer      invocation_hint,
                      gpointer      marshal_data) {
    auto closure = (Closure *) base;
    // We don't pass the implicit instance as first argument
    AsyncCallEnvironment* env = reinterpret_cast<AsyncCallEnvironment *>(Closure::asyncHandle.data);
    uv_thread_t thread = uv_thread_self();
    if (uv_thread_equal(&thread, &env->mainThread)) {
        Closure::Execute(closure->persistent, g_return_value, n_param_values - 1, param_values + 1);
    } else {
        CallbackWrapper* cb = new CallbackWrapper();
        cb->Prepare(&closure->persistent, g_return_value, n_param_values - 1, param_values + 1);

        uv_mutex_lock(&env->mutex);
        env->queue.push(cb);
        uv_mutex_unlock(&env->mutex);
        uv_async_send(&Closure::asyncHandle);

        cb->Wait();
    }
}

void Closure::Invalidated (gpointer data, GClosure *base) {
    Closure *closure = (Closure *) base;
    closure->~Closure();
}

// locking and signalling adapted from https://github.com/node-ffi-napi/node-ffi-napi
uv_async_t Closure::asyncHandle;

void Closure::QueueHandler(uv_async_t* handle) {
    AsyncCallEnvironment* data = reinterpret_cast<AsyncCallEnvironment *>(handle->data);
    uv_mutex_lock(&data->mutex);

    while (!data->queue.empty()) {
        CallbackWrapper* cb = data->queue.front();
        cb->Execute();
        data->queue.pop();
        delete cb;
    }

    uv_mutex_unlock(&data->mutex);
}

void Closure::Initialize() {
    auto& handle = Closure::asyncHandle;
    AsyncCallEnvironment* env = new AsyncCallEnvironment();
    handle.data = env;
    env->mainThread = uv_thread_self();
    uv_loop_t* loop = uv_default_loop();
    uv_async_init(loop, &handle, Closure::QueueHandler);
    uv_mutex_init(&env->mutex);
    uv_unref(reinterpret_cast<uv_handle_t *>(&handle));
    uv_async_send(&handle);
}

CallbackWrapper::CallbackWrapper() {
    uv_mutex_init(&mutex);
    uv_cond_init(&cond);
}

CallbackWrapper::~CallbackWrapper() {
    uv_cond_destroy(&cond);
    uv_mutex_destroy(&mutex);
}

void CallbackWrapper::Execute() {
    Closure::Execute(*persistent, returnValue, nValues, values);
    Done();
}
void CallbackWrapper::Prepare(const Nan::Persistent<v8::Function>* persistentIn, GValue* returnValueIn, uint nValuesIn, const GValue* valuesIn) {
    // copy values
    persistent = persistentIn;
    returnValue = returnValueIn;
    nValues = nValuesIn;
    values = new GValue[nValues];
    for (uint i = 0; i < nValues; ++i) {
        values[i] = G_VALUE_INIT;
        g_value_init(&values[i], G_VALUE_TYPE(&valuesIn[i]));
        g_value_copy(&valuesIn[i], &values[i]);
    }
}

void CallbackWrapper::Done() {
    uv_mutex_lock(&mutex);
    uv_cond_signal(&cond);
    uv_mutex_unlock(&mutex);
}
void CallbackWrapper::Wait() {
    uv_cond_wait(&cond, &mutex);
}

};
<commit_msg>Add locking of mutex<commit_after>#include <glib.h>
#include <nan.h>

#include "closure.h"
#include "macros.h"
#include "loop.h"
#include "type.h"
#include "value.h"

using v8::Context;
using v8::Function;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Value;
using Nan::Persistent;

namespace GNodeJS {

GClosure *Closure::New(Local<Function> function, guint signalId) {
    Closure *closure = (Closure *) g_closure_new_simple (sizeof(Closure), NULL);
    closure->persistent.Reset(function);
    GClosure *gclosure = &closure->base;
    g_closure_set_marshal (gclosure, Closure::Marshal);
    g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
    return gclosure;
}

void Closure::Execute(const Nan::Persistent<v8::Function>& persFn, GValue *returnValue, uint nValues, const GValue *values) {
    Nan::HandleScope scope;
    auto fn = Nan::New<Function>(persFn);

    #ifndef __linux__
        Local<Value>* jsArgs = new Local<Value>[nValues];
    #else
        Local<Value> jsArgs[nValues];
    #endif

    for (uint i = 0; i < nValues; i++) {
        bool mustCopy = true; // TODO: get information about mustCopy
        jsArgs[i] = GValueToV8(&values[i], mustCopy);
    }

    Local<Object> self = fn;
    Local<Value> return_value;

    Nan::TryCatch try_catch;

    auto result = Nan::Call(fn, self, nValues, jsArgs);

    if (!try_catch.HasCaught()
            && result.ToLocal(&return_value)) {
        if (returnValue) {
            if (G_VALUE_TYPE(returnValue) == G_TYPE_INVALID)
                WARN ("Marshal: return value has invalid g_type");
            else if (!V8ToGValue (returnValue, return_value, true))
                WARN ("Marshal: could not convert return value");
        }
        CallMicrotaskHandlers();
    }
    else {
        GNodeJS::QuitLoopStack();
        Nan::FatalException(try_catch);
    }

    #ifndef __linux__
        delete[] jsArgs;
    #endif
}

void Closure::Marshal(GClosure     *base,
                      GValue       *g_return_value,
                      uint          n_param_values,
                      const GValue *param_values,
                      gpointer      invocation_hint,
                      gpointer      marshal_data) {
    auto closure = (Closure *) base;
    // We don't pass the implicit instance as first argument
    AsyncCallEnvironment* env = reinterpret_cast<AsyncCallEnvironment *>(Closure::asyncHandle.data);
    uv_thread_t thread = uv_thread_self();
    if (uv_thread_equal(&thread, &env->mainThread)) {
        Closure::Execute(closure->persistent, g_return_value, n_param_values - 1, param_values + 1);
    } else {
        CallbackWrapper* cb = new CallbackWrapper();
        cb->Prepare(&closure->persistent, g_return_value, n_param_values - 1, param_values + 1);

        uv_mutex_lock(&env->mutex);
        env->queue.push(cb);
        uv_mutex_unlock(&env->mutex);
        uv_async_send(&Closure::asyncHandle);

        cb->Wait();
    }
}

void Closure::Invalidated (gpointer data, GClosure *base) {
    Closure *closure = (Closure *) base;
    closure->~Closure();
}

// locking and signalling adapted from https://github.com/node-ffi-napi/node-ffi-napi
uv_async_t Closure::asyncHandle;

void Closure::QueueHandler(uv_async_t* handle) {
    AsyncCallEnvironment* data = reinterpret_cast<AsyncCallEnvironment *>(handle->data);
    uv_mutex_lock(&data->mutex);

    while (!data->queue.empty()) {
        CallbackWrapper* cb = data->queue.front();
        cb->Execute();
        data->queue.pop();
        delete cb;
    }

    uv_mutex_unlock(&data->mutex);
}

void Closure::Initialize() {
    auto& handle = Closure::asyncHandle;
    AsyncCallEnvironment* env = new AsyncCallEnvironment();
    handle.data = env;
    env->mainThread = uv_thread_self();
    uv_loop_t* loop = uv_default_loop();
    uv_async_init(loop, &handle, Closure::QueueHandler);
    uv_mutex_init(&env->mutex);
    uv_unref(reinterpret_cast<uv_handle_t *>(&handle));
    uv_async_send(&handle);
}

CallbackWrapper::CallbackWrapper() {
    uv_mutex_init(&mutex);
    uv_mutex_lock(&mutex);
    uv_cond_init(&cond);
}

CallbackWrapper::~CallbackWrapper() {
    uv_mutex_unlock(&mutex);
    uv_cond_destroy(&cond);
    uv_mutex_destroy(&mutex);
}

void CallbackWrapper::Execute() {
    Closure::Execute(*persistent, returnValue, nValues, values);
    Done();
}
void CallbackWrapper::Prepare(const Nan::Persistent<v8::Function>* persistentIn, GValue* returnValueIn, uint nValuesIn, const GValue* valuesIn) {
    // copy values
    persistent = persistentIn;
    returnValue = returnValueIn;
    nValues = nValuesIn;
    values = new GValue[nValues];
    for (uint i = 0; i < nValues; ++i) {
        values[i] = G_VALUE_INIT;
        g_value_init(&values[i], G_VALUE_TYPE(&valuesIn[i]));
        g_value_copy(&valuesIn[i], &values[i]);
    }
}

void CallbackWrapper::Done() {
    uv_mutex_lock(&mutex);
    uv_cond_signal(&cond);
    uv_mutex_unlock(&mutex);
}
void CallbackWrapper::Wait() {
    uv_cond_wait(&cond, &mutex);
}

};
<|endoftext|>