<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "init.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
#endif

#include <stdint.h>

#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"

using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
using namespace std;

Value getinfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getinfo\n"
            "Returns an object containing various state info.\n"
            "\nResult:\n"
            "{\n"
            "  \"version\": xxxxx,           (numeric) the server version\n"
            "  \"protocolversion\": xxxxx,   (numeric) the protocol version\n"
            "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
            "  \"balance\": xxxxxxx,         (numeric) the total Dogecoin balance of the wallet\n"
            "  \"blocks\": xxxxxx,           (numeric) the current number of blocks processed in the server\n"
            "  \"timeoffset\": xxxxx,        (numeric) the time offset\n"
            "  \"connections\": xxxxx,       (numeric) the number of connections\n"
            "  \"proxy\": \"host:port\",     (string, optional) the proxy used by the server\n"
            "  \"difficulty\": xxxxxx,       (numeric) the current difficulty\n"
            "  \"testnet\": true|false,      (boolean) if the server is using testnet or not\n"
            "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
            "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
            "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in doge/kb\n"
            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in doge/kb\n"
            "  \"errors\": \"...\"           (string) any error messages\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getinfo", "")
            + HelpExampleRpc("getinfo", "")
        );

    proxyType proxy;
    GetProxy(NET_IPV4, proxy);

    Object obj;
    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
        obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
    }
#endif
    obj.push_back(Pair("blocks",        (int)chainActive.Height()));
    obj.push_back(Pair("timeoffset",    GetTimeOffset()));
    obj.push_back(Pair("connections",   (int)vNodes.size()));
    obj.push_back(Pair("proxy",         (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("testnet",       Params().NetworkID() == CChainParams::TESTNET));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
        obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
    }
    if (pwalletMain && pwalletMain->IsCrypted())
        obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
    obj.push_back(Pair("paytxfee",      ValueFromAmount(payTxFee.GetFeePerK())));
#endif
    obj.push_back(Pair("relayfee",      ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK())));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    return obj;
}

#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
public:
    Object operator()(const CNoDestination &dest) const { return Object(); }

    Object operator()(const CKeyID &keyID) const {
        Object obj;
        CPubKey vchPubKey;
        pwalletMain->GetPubKey(keyID, vchPubKey);
        obj.push_back(Pair("isscript", false));
        obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
        obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
        return obj;
    }

    Object operator()(const CScriptID &scriptID) const {
        Object obj;
        obj.push_back(Pair("isscript", true));
        CScript subscript;
        pwalletMain->GetCScript(scriptID, subscript);
        std::vector<CTxDestination> addresses;
        txnouttype whichType;
        int nRequired;
        ExtractDestinations(subscript, whichType, addresses, nRequired);
        obj.push_back(Pair("script", GetTxnOutputType(whichType)));
        obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
        Array a;
        BOOST_FOREACH(const CTxDestination& addr, addresses)
            a.push_back(CBitcoinAddress(addr).ToString());
        obj.push_back(Pair("addresses", a));
        if (whichType == TX_MULTISIG)
            obj.push_back(Pair("sigsrequired", nRequired));
        return obj;
    }
};
#endif

Value validateaddress(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "validateaddress \"dogecoinaddress\"\n"
            "\nReturn information about the given dogecoin address.\n"
            "\nArguments:\n"
            "1. \"dogecoinaddress\"     (string, required) The dogecoin address to validate\n"
            "\nResult:\n"
            "{\n"
            "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
            "  \"address\" : \"dogecoinaddress\", (string) The dogecoin address validated\n"
            "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
            "  \"isscript\" : true|false,        (boolean) If the key is a script\n"
            "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key\n"
            "  \"iscompressed\" : true|false,    (boolean) If the address is compressed\n"
            "  \"account\" : \"account\"         (string) The account associated with the address, \"\" is the default account\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
            + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
        );

    CBitcoinAddress address(params[0].get_str());
    bool isValid = address.IsValid();

    Object ret;
    ret.push_back(Pair("isvalid", isValid));
    if (isValid)
    {
        CTxDestination dest = address.Get();
        string currentAddress = address.ToString();
        ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
        bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
        ret.push_back(Pair("ismine", fMine));
        if (fMine) {
            Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
            ret.insert(ret.end(), detail.begin(), detail.end());
        }
        if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
            ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
    }
    return ret;
}

//
// Used by addmultisigaddress / createmultisig:
//
CScript _createmultisig_redeemScript(const Array& params)
{
    int nRequired = params[0].get_int();
    const Array& keys = params[1].get_array();

    // Gather public keys
    if (nRequired < 1)
        throw runtime_error("a multisignature address must require at least one key to redeem");
    if ((int)keys.size() < nRequired)
        throw runtime_error(
            strprintf("not enough keys supplied "
                      "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
    std::vector<CPubKey> pubkeys;
    pubkeys.resize(keys.size());
    for (unsigned int i = 0; i < keys.size(); i++)
    {
        const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
        // Case 1: Dogecoin address and we have full public key:
        CBitcoinAddress address(ks);
        if (pwalletMain && address.IsValid())
        {
            CKeyID keyID;
            if (!address.GetKeyID(keyID))
                throw runtime_error(
                    strprintf("%s does not refer to a key",ks));
            CPubKey vchPubKey;
            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                throw runtime_error(
                    strprintf("no full public key for address %s",ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }

        // Case 2: hex public key
        else
#endif
        if (IsHex(ks))
        {
            CPubKey vchPubKey(ParseHex(ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }
        else
        {
            throw runtime_error(" Invalid public key: "+ks);
        }
    }
    CScript result;
    result.SetMultisig(nRequired, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
        throw runtime_error(
                strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));

    return result;
}

Value createmultisig(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 2)
    {
        string msg = "createmultisig nrequired [\"key\",...]\n"
            "\nCreates a multi-signature address with n signature of m keys required.\n"
            "It returns a json object with the address and redeemScript.\n"

            "\nArguments:\n"
            "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
            "2. \"keys\"       (string, required) A json array of keys which are dogecoin addresses or hex-encoded public keys\n"
            "     [\n"
            "       \"key\"    (string) dogecoin address or hex-encoded public key\n"
            "       ,...\n"
            "     ]\n"

            "\nResult:\n"
            "{\n"
            "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
            "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
            "}\n"

            "\nExamples:\n"
            "\nCreate a multisig address from 2 addresses\n"
            + HelpExampleCli("createmultisig", "2 \"[\\\"D9fLaux2pNqp9w4BnU6Rj51PovyzbUaBpk\\\",\\\"DSYgpp3zaDj5wq5Tz1CYEif1QB98zbC2V3\\\"]\"") +
            "\nAs a json rpc call\n"
            + HelpExampleRpc("createmultisig", "2, \"[\\\"D9fLaux2pNqp9w4BnU6Rj51PovyzbUaBpk\\\",\\\"DSYgpp3zaDj5wq5Tz1CYEif1QB98zbC2V3\\\"]\"")
        ;
        throw runtime_error(msg);
    }

    // Construct using pay-to-script-hash:
    CScript inner = _createmultisig_redeemScript(params);
    CScriptID innerID = inner.GetID();
    CBitcoinAddress address(innerID);

    Object result;
    result.push_back(Pair("address", address.ToString()));
    result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));

    return result;
}

Value verifymessage(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 3)
        throw runtime_error(
            "verifymessage \"dogecoinaddress\" \"signature\" \"message\"\n"
            "\nVerify a signed message\n"
            "\nArguments:\n"
            "1. \"dogecoinaddress\"  (string, required) The dogecoin address to use for the signature.\n"
            "2. \"signature\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
            "3. \"message\"         (string, required) The message that was signed.\n"
            "\nResult:\n"
            "true|false   (boolean) If the signature is verified or not.\n"
            "\nExamples:\n"
            "\nUnlock the wallet for 30 seconds\n"
            + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
            "\nCreate the signature\n"
            + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
            "\nVerify the signature\n"
            + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
            "\nAs json rpc\n"
            + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
        );

    string strAddress  = params[0].get_str();
    string strSign     = params[1].get_str();
    string strMessage  = params[2].get_str();

    CBitcoinAddress addr(strAddress);
    if (!addr.IsValid())
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");

    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");

    bool fInvalid = false;
    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);

    if (fInvalid)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");

    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey;
    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
        return false;

    return (pubkey.GetID() == keyID);
}
<commit_msg>Add warning comment to getinfo<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "init.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
#endif

#include <stdint.h>

#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"

using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
using namespace std;

/**
 * @note Do not add or change anything in the information returned by this
 * method. `getinfo` exists for backwards-compatibilty only. It combines
 * information from wildly different sources in the program, which is a mess,
 * and is thus planned to be deprecated eventually.
 *
 * Based on the source of the information, new information should be added to:
 * - `getblockchaininfo`,
 * - `getnetworkinfo` or
 * - `getwalletinfo`
 *
 * Or alternatively, create a specific query method for the information.
 **/
Value getinfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getinfo\n"
            "Returns an object containing various state info.\n"
            "\nResult:\n"
            "{\n"
            "  \"version\": xxxxx,           (numeric) the server version\n"
            "  \"protocolversion\": xxxxx,   (numeric) the protocol version\n"
            "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
            "  \"balance\": xxxxxxx,         (numeric) the total Dogecoin balance of the wallet\n"
            "  \"blocks\": xxxxxx,           (numeric) the current number of blocks processed in the server\n"
            "  \"timeoffset\": xxxxx,        (numeric) the time offset\n"
            "  \"connections\": xxxxx,       (numeric) the number of connections\n"
            "  \"proxy\": \"host:port\",     (string, optional) the proxy used by the server\n"
            "  \"difficulty\": xxxxxx,       (numeric) the current difficulty\n"
            "  \"testnet\": true|false,      (boolean) if the server is using testnet or not\n"
            "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
            "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
            "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in doge/kb\n"
            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in doge/kb\n"
            "  \"errors\": \"...\"           (string) any error messages\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getinfo", "")
            + HelpExampleRpc("getinfo", "")
        );

    proxyType proxy;
    GetProxy(NET_IPV4, proxy);

    Object obj;
    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
        obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
    }
#endif
    obj.push_back(Pair("blocks",        (int)chainActive.Height()));
    obj.push_back(Pair("timeoffset",    GetTimeOffset()));
    obj.push_back(Pair("connections",   (int)vNodes.size()));
    obj.push_back(Pair("proxy",         (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("testnet",       Params().NetworkID() == CChainParams::TESTNET));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
        obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
    }
    if (pwalletMain && pwalletMain->IsCrypted())
        obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
    obj.push_back(Pair("paytxfee",      ValueFromAmount(payTxFee.GetFeePerK())));
#endif
    obj.push_back(Pair("relayfee",      ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK())));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    return obj;
}

#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
public:
    Object operator()(const CNoDestination &dest) const { return Object(); }

    Object operator()(const CKeyID &keyID) const {
        Object obj;
        CPubKey vchPubKey;
        pwalletMain->GetPubKey(keyID, vchPubKey);
        obj.push_back(Pair("isscript", false));
        obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
        obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
        return obj;
    }

    Object operator()(const CScriptID &scriptID) const {
        Object obj;
        obj.push_back(Pair("isscript", true));
        CScript subscript;
        pwalletMain->GetCScript(scriptID, subscript);
        std::vector<CTxDestination> addresses;
        txnouttype whichType;
        int nRequired;
        ExtractDestinations(subscript, whichType, addresses, nRequired);
        obj.push_back(Pair("script", GetTxnOutputType(whichType)));
        obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
        Array a;
        BOOST_FOREACH(const CTxDestination& addr, addresses)
            a.push_back(CBitcoinAddress(addr).ToString());
        obj.push_back(Pair("addresses", a));
        if (whichType == TX_MULTISIG)
            obj.push_back(Pair("sigsrequired", nRequired));
        return obj;
    }
};
#endif

Value validateaddress(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "validateaddress \"dogecoinaddress\"\n"
            "\nReturn information about the given dogecoin address.\n"
            "\nArguments:\n"
            "1. \"dogecoinaddress\"     (string, required) The dogecoin address to validate\n"
            "\nResult:\n"
            "{\n"
            "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
            "  \"address\" : \"dogecoinaddress\", (string) The dogecoin address validated\n"
            "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
            "  \"isscript\" : true|false,        (boolean) If the key is a script\n"
            "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key\n"
            "  \"iscompressed\" : true|false,    (boolean) If the address is compressed\n"
            "  \"account\" : \"account\"         (string) The account associated with the address, \"\" is the default account\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
            + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
        );

    CBitcoinAddress address(params[0].get_str());
    bool isValid = address.IsValid();

    Object ret;
    ret.push_back(Pair("isvalid", isValid));
    if (isValid)
    {
        CTxDestination dest = address.Get();
        string currentAddress = address.ToString();
        ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
        bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
        ret.push_back(Pair("ismine", fMine));
        if (fMine) {
            Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
            ret.insert(ret.end(), detail.begin(), detail.end());
        }
        if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
            ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
    }
    return ret;
}

//
// Used by addmultisigaddress / createmultisig:
//
CScript _createmultisig_redeemScript(const Array& params)
{
    int nRequired = params[0].get_int();
    const Array& keys = params[1].get_array();

    // Gather public keys
    if (nRequired < 1)
        throw runtime_error("a multisignature address must require at least one key to redeem");
    if ((int)keys.size() < nRequired)
        throw runtime_error(
            strprintf("not enough keys supplied "
                      "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
    std::vector<CPubKey> pubkeys;
    pubkeys.resize(keys.size());
    for (unsigned int i = 0; i < keys.size(); i++)
    {
        const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
        // Case 1: Dogecoin address and we have full public key:
        CBitcoinAddress address(ks);
        if (pwalletMain && address.IsValid())
        {
            CKeyID keyID;
            if (!address.GetKeyID(keyID))
                throw runtime_error(
                    strprintf("%s does not refer to a key",ks));
            CPubKey vchPubKey;
            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                throw runtime_error(
                    strprintf("no full public key for address %s",ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }

        // Case 2: hex public key
        else
#endif
        if (IsHex(ks))
        {
            CPubKey vchPubKey(ParseHex(ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }
        else
        {
            throw runtime_error(" Invalid public key: "+ks);
        }
    }
    CScript result;
    result.SetMultisig(nRequired, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
        throw runtime_error(
                strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));

    return result;
}

Value createmultisig(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 2)
    {
        string msg = "createmultisig nrequired [\"key\",...]\n"
            "\nCreates a multi-signature address with n signature of m keys required.\n"
            "It returns a json object with the address and redeemScript.\n"

            "\nArguments:\n"
            "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
            "2. \"keys\"       (string, required) A json array of keys which are dogecoin addresses or hex-encoded public keys\n"
            "     [\n"
            "       \"key\"    (string) dogecoin address or hex-encoded public key\n"
            "       ,...\n"
            "     ]\n"

            "\nResult:\n"
            "{\n"
            "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
            "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
            "}\n"

            "\nExamples:\n"
            "\nCreate a multisig address from 2 addresses\n"
            + HelpExampleCli("createmultisig", "2 \"[\\\"D9fLaux2pNqp9w4BnU6Rj51PovyzbUaBpk\\\",\\\"DSYgpp3zaDj5wq5Tz1CYEif1QB98zbC2V3\\\"]\"") +
            "\nAs a json rpc call\n"
            + HelpExampleRpc("createmultisig", "2, \"[\\\"D9fLaux2pNqp9w4BnU6Rj51PovyzbUaBpk\\\",\\\"DSYgpp3zaDj5wq5Tz1CYEif1QB98zbC2V3\\\"]\"")
        ;
        throw runtime_error(msg);
    }

    // Construct using pay-to-script-hash:
    CScript inner = _createmultisig_redeemScript(params);
    CScriptID innerID = inner.GetID();
    CBitcoinAddress address(innerID);

    Object result;
    result.push_back(Pair("address", address.ToString()));
    result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));

    return result;
}

Value verifymessage(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 3)
        throw runtime_error(
            "verifymessage \"dogecoinaddress\" \"signature\" \"message\"\n"
            "\nVerify a signed message\n"
            "\nArguments:\n"
            "1. \"dogecoinaddress\"  (string, required) The dogecoin address to use for the signature.\n"
            "2. \"signature\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
            "3. \"message\"         (string, required) The message that was signed.\n"
            "\nResult:\n"
            "true|false   (boolean) If the signature is verified or not.\n"
            "\nExamples:\n"
            "\nUnlock the wallet for 30 seconds\n"
            + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
            "\nCreate the signature\n"
            + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
            "\nVerify the signature\n"
            + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
            "\nAs json rpc\n"
            + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
        );

    string strAddress  = params[0].get_str();
    string strSign     = params[1].get_str();
    string strMessage  = params[2].get_str();

    CBitcoinAddress addr(strAddress);
    if (!addr.IsValid())
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");

    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");

    bool fInvalid = false;
    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);

    if (fInvalid)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");

    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey;
    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
        return false;

    return (pubkey.GetID() == keyID);
}
<|endoftext|>


<commit_before>// Copyright 2008 Paul Hodge

#include "branch.h"
#include "introspection.h"
#include "runtime.h"
#include "function.h"
#include "parser.h"
#include "type.h"
#include "values.h"

namespace circa {

bool check_valid_type(Function &func, int index, Term* term)
{
    // TODO: Also check types for variableArgs functions
    if (func.variableArgs)
        return true;

    Term* expectedType = func.inputTypes[index];

    if (expectedType == ANY_TYPE)
        return true;

    return term->type == expectedType;
}

void evaluate_term(Term* term)
{
    if (term == NULL)
        throw std::runtime_error("term is NULL");

    term->clearError();

    // Check function
    if (term->function == NULL) {
        error_occured(term, "Function is NULL");
        return;
    }

    if (!is_function(term->function)) {
        error_occured(term, "term->function is not a function");
        return;
    }

    Function& func = as_function(term->function);

    if (func.evaluate == NULL) {
        std::stringstream message;
        message << "Function '" << func.name << "' has no evaluate function";
        error_occured(term, message.str());
        return;
    }

    // Check each input. Make sure:
    //  1) it is not null
    //  2) it is up-to-date
    //  3) it has a non-null value
    //  4) it has no errors
    //  5) it has the correct type
    for (unsigned int inputIndex=0; inputIndex < term->inputs.count(); inputIndex++)
    {
        int effectiveIndex = inputIndex;
        if (func.variableArgs)
            effectiveIndex = 0;

        Term* input = term->inputs[inputIndex];
        Function::InputProperties inputProps = func.getInputProperties(effectiveIndex);

        if (input == NULL) {
            std::stringstream message;
            message << "Input " << inputIndex << " is NULL";
            error_occured(term, message.str());
            return;
        }

        if (input->value == NULL) {
            std::stringstream message;
            message << "Input " << inputIndex << " has NULL value";
            error_occured(term, message.str());
            return;
        }

        if (input->hasError() && !inputProps.meta) {
            std::stringstream message;
            message << "Input " << inputIndex << " has an error";
            error_occured(term, message.str());
            return;
        }

        // Check type
        if (!check_valid_type(func, effectiveIndex, input)) {
            std::stringstream message;
            message << "Runtime type error: input " << inputIndex << " has type "
                << as_type(input->type).name;
            error_occured(term, message.str());
            return;
        }

        if (input->needsUpdate)
            evaluate_term(input);
    }

    // Make sure we have an allocated value. Allocate one if necessary
    if (term->value == NULL) {
        term->value = alloc_from_type(term->type);
    }

    try {
        func.evaluate(term);
        term->needsUpdate = false;
    }
    catch (std::exception const& err)
    {
        std::stringstream message;
        message << "An exception occured while executing " + func.name << ": "
            << err.what();
        error_occured(term, message.str());
    }
}

void evaluate_branch(Branch& branch, Term* errorListener)
{
    int count = branch.numTerms();
    for (int index=0; index < count; index++) {
		Term* term = branch.get(index);
        evaluate_term(term);

        if (term->hasError()) {
            error_occured(errorListener, term->getErrorMessage());
            return;
        }
    }
}

Branch* evaluate_file(std::string const& filename)
{
    Branch *branch = new Branch();

    Branch temp_branch;
    temp_branch.bindName(string_var(temp_branch, filename), "filename");
    std::string file_contents = as_string(eval_statement(temp_branch,
                "read-text-file(filename)"));

    token_stream::TokenStream tokens(file_contents);
    ast::StatementList *statementList = parser::statementList(tokens);

    statementList->createTerms(*branch);

    delete statementList;

    return branch;
}

void error_occured(Term* errorTerm, std::string const& message)
{
    if (errorTerm == NULL)
        throw std::runtime_error(message);

    errorTerm->pushError(message);
}

Term* create_term(Branch* branch, Term* function, ReferenceList const& inputs)
{
    //if (branch == NULL)
    //    throw std::runtime_error("in create_term, branch is NULL");
    if (!is_function(function))
        throw std::runtime_error("in create_term, 2nd arg to create_term must be a function");

    Term* term = new Term();

    if (branch != NULL)
        branch->append(term);

    term->function = function;
    register_pointer(term, function);

    Function& functionData = as_function(function);

    Term* outputType = functionData.outputType;
    register_pointer(term, outputType);

    Term* stateType = functionData.stateType;
    register_pointer(term, stateType);

    if (outputType == NULL)
        throw std::runtime_error("outputType is NULL");

    if (!is_type(outputType))
        throw std::runtime_error(outputType->name + " is not a type");

    if (stateType != NULL && !is_type(stateType))
        throw std::runtime_error(outputType->name + " is not a type");

    change_type(term, outputType);

    // Create state (if a state type is defined)
    if (stateType != NULL) {
        term->state = create_var(NULL, stateType);
    }
    else
        term->state = NULL;

    set_inputs(term, inputs);

    // Run the function's initialize (if it has one)
    if (functionData.initialize != NULL) {
        functionData.initialize(term);
    }

    return term;
}

void set_inputs(Term* term, ReferenceList const& inputs)
{
    assert_good(term);

    term->inputs = inputs;

    for (unsigned int i=0; i < inputs.count(); i++)
        register_pointer(term, inputs[i]);
}

void set_input(Term* term, int index, Term* input)
{
    assert_good(term);

    term->inputs.setAt(index, input);

    register_pointer(term, input);
}

void register_pointer(Term* pointer, Term* pointee)
{
    assert_good(pointer);

    if (pointee == NULL)
        return;

    Branch* pointeeBranch = pointee->owningBranch;

    if (pointeeBranch == NULL)
        return;

    if (pointeeBranch->permanent)
        return;

    // todo: handle external pointers
}

Term* create_var(Branch* branch, Term* type)
{
    Term *term = create_term(branch, get_var_function(*branch, type), ReferenceList());
    term->stealingOk = false;
    return term;
}

Term* apply_function(Branch& branch, Term* function, ReferenceList const& _inputs)
{
    // Make a local copy of _inputs
    ReferenceList inputs = _inputs;

    if (function->needsUpdate)
        evaluate_term(function);

    // Check if 'function' is actually a type
    if (is_type(function))
    {
        if (inputs.count() != 0)
            throw std::runtime_error("Multiple inputs in constructor not supported");

        function = get_var_function(branch, function);
    }

    // If 'function' is not really a function, see if we can treat it like a function
    else if (!is_function(function)) {

        Type& type = as_type(function->type);

        if (!type.memberFunctions.contains(""))
            throw std::runtime_error(std::string("Term ") + function->toString()
                    + " is not a type, and has no default function");

        ReferenceList memberFunctionInputs;
        memberFunctionInputs.append(function);
        memberFunctionInputs.appendAll(inputs);

        function = type.memberFunctions[""];
        inputs = memberFunctionInputs;
    }

    // Attempt to re-use an existing term
    Term* existing = find_equivalent(function, inputs);

    if (existing != NULL)
        return existing;

    // Create the term
    return create_term(&branch, function, inputs);
}

Term* eval_function(Branch& branch, Term* function, ReferenceList const& inputs)
{
    Term* result = apply_function(branch, function, inputs);
    evaluate_term(result);
    return result;
}

Term* eval_function(Branch& branch, std::string const& functionName,
        ReferenceList const &inputs)
{
    Term* function = branch.findNamed(functionName);
    if (function == NULL)
        throw std::runtime_error(std::string("function not found: ")+functionName);

    return eval_function(branch, function, inputs);
}

void change_function(Term* term, Term* new_function)
{
    assert_good(term);

    assert_type(new_function, FUNCTION_TYPE);

    term->function = new_function;
    register_pointer(term, new_function);
}

void remap_pointers(Term* term, ReferenceMap const& map)
{
    assert_good(term);

    // make sure this map doesn't try to remap NULL, because such a thing
    // would almost definitely lead to errors.
    assert(!map.contains(NULL));

    term->inputs.remapPointers(map);
    for (unsigned int i=0; i < term->inputs.count(); i++)
        register_pointer(term, term->inputs[i]);

    term->function = map.getRemapped(term->function);
    register_pointer(term, term->function);

    if ((term->value != NULL) && (as_type(term->type).remapPointers != NULL))
        as_type(term->type).remapPointers(term, map);

    term->type = map.getRemapped(term->type);
    register_pointer(term, term->type);
}

void visit_pointers(Term* term, PointerVisitor &visitor)
{
    Type& type = as_type(term->type);

    term->inputs.visitPointers(visitor);
    visitor.visitPointer(term->function);
    visitor.visitPointer(term->type);

    if (type.visitPointers != NULL)
        type.visitPointers(term, visitor);
}

void remap_pointers(Term* term, Term* original, Term* replacement)
{
    assert_good(term);
    assert_good(original);

    ReferenceMap map;
    map[original] = replacement;
    remap_pointers(term, map);
}

} // namespace circa
<commit_msg>Fix type checking on vararg functions<commit_after>// Copyright 2008 Paul Hodge

#include "branch.h"
#include "introspection.h"
#include "runtime.h"
#include "function.h"
#include "parser.h"
#include "type.h"
#include "values.h"

namespace circa {

bool check_valid_type(Function &func, int index, Term* term)
{
    Term* expectedType = func.inputTypes[index];

    if (expectedType == ANY_TYPE)
        return true;

    return term->type == expectedType;
}

void evaluate_term(Term* term)
{
    if (term == NULL)
        throw std::runtime_error("term is NULL");

    term->clearError();

    // Check function
    if (term->function == NULL) {
        error_occured(term, "Function is NULL");
        return;
    }

    if (!is_function(term->function)) {
        error_occured(term, "term->function is not a function");
        return;
    }

    Function& func = as_function(term->function);

    if (func.evaluate == NULL) {
        std::stringstream message;
        message << "Function '" << func.name << "' has no evaluate function";
        error_occured(term, message.str());
        return;
    }

    // Check each input. Make sure:
    //  1) it is not null
    //  2) it is up-to-date
    //  3) it has a non-null value
    //  4) it has no errors
    //  5) it has the correct type
    for (unsigned int inputIndex=0; inputIndex < term->inputs.count(); inputIndex++)
    {
        int effectiveIndex = inputIndex;
        if (func.variableArgs)
            effectiveIndex = 0;

        Term* input = term->inputs[inputIndex];
        Function::InputProperties inputProps = func.getInputProperties(effectiveIndex);

        if (input == NULL) {
            std::stringstream message;
            message << "Input " << inputIndex << " is NULL";
            error_occured(term, message.str());
            return;
        }

        if (input->value == NULL) {
            std::stringstream message;
            message << "Input " << inputIndex << " has NULL value";
            error_occured(term, message.str());
            return;
        }

        if (input->hasError() && !inputProps.meta) {
            std::stringstream message;
            message << "Input " << inputIndex << " has an error";
            error_occured(term, message.str());
            return;
        }

        // Check type
        if (!check_valid_type(func, effectiveIndex, input)) {
            std::stringstream message;
            message << "Runtime type error: input " << inputIndex << " has type "
                << as_type(input->type).name;
            error_occured(term, message.str());
            return;
        }

        if (input->needsUpdate)
            evaluate_term(input);
    }

    // Make sure we have an allocated value. Allocate one if necessary
    if (term->value == NULL) {
        term->value = alloc_from_type(term->type);
    }

    try {
        func.evaluate(term);
        term->needsUpdate = false;
    }
    catch (std::exception const& err)
    {
        std::stringstream message;
        message << "An exception occured while executing " + func.name << ": "
            << err.what();
        error_occured(term, message.str());
    }
}

void evaluate_branch(Branch& branch, Term* errorListener)
{
    int count = branch.numTerms();
    for (int index=0; index < count; index++) {
		Term* term = branch.get(index);
        evaluate_term(term);

        if (term->hasError()) {
            error_occured(errorListener, term->getErrorMessage());
            return;
        }
    }
}

Branch* evaluate_file(std::string const& filename)
{
    Branch *branch = new Branch();

    Branch temp_branch;
    temp_branch.bindName(string_var(temp_branch, filename), "filename");
    std::string file_contents = as_string(eval_statement(temp_branch,
                "read-text-file(filename)"));

    token_stream::TokenStream tokens(file_contents);
    ast::StatementList *statementList = parser::statementList(tokens);

    statementList->createTerms(*branch);

    delete statementList;

    return branch;
}

void error_occured(Term* errorTerm, std::string const& message)
{
    if (errorTerm == NULL)
        throw std::runtime_error(message);

    errorTerm->pushError(message);
}

Term* create_term(Branch* branch, Term* function, ReferenceList const& inputs)
{
    //if (branch == NULL)
    //    throw std::runtime_error("in create_term, branch is NULL");
    if (!is_function(function))
        throw std::runtime_error("in create_term, 2nd arg to create_term must be a function");

    Term* term = new Term();

    if (branch != NULL)
        branch->append(term);

    term->function = function;
    register_pointer(term, function);

    Function& functionData = as_function(function);

    Term* outputType = functionData.outputType;
    register_pointer(term, outputType);

    Term* stateType = functionData.stateType;
    register_pointer(term, stateType);

    if (outputType == NULL)
        throw std::runtime_error("outputType is NULL");

    if (!is_type(outputType))
        throw std::runtime_error(outputType->name + " is not a type");

    if (stateType != NULL && !is_type(stateType))
        throw std::runtime_error(outputType->name + " is not a type");

    change_type(term, outputType);

    // Create state (if a state type is defined)
    if (stateType != NULL) {
        term->state = create_var(NULL, stateType);
    }
    else
        term->state = NULL;

    set_inputs(term, inputs);

    // Run the function's initialize (if it has one)
    if (functionData.initialize != NULL) {
        functionData.initialize(term);
    }

    return term;
}

void set_inputs(Term* term, ReferenceList const& inputs)
{
    assert_good(term);

    term->inputs = inputs;

    for (unsigned int i=0; i < inputs.count(); i++)
        register_pointer(term, inputs[i]);
}

void set_input(Term* term, int index, Term* input)
{
    assert_good(term);

    term->inputs.setAt(index, input);

    register_pointer(term, input);
}

void register_pointer(Term* pointer, Term* pointee)
{
    assert_good(pointer);

    if (pointee == NULL)
        return;

    Branch* pointeeBranch = pointee->owningBranch;

    if (pointeeBranch == NULL)
        return;

    if (pointeeBranch->permanent)
        return;

    // todo: handle external pointers
}

Term* create_var(Branch* branch, Term* type)
{
    Term *term = create_term(branch, get_var_function(*branch, type), ReferenceList());
    term->stealingOk = false;
    return term;
}

Term* apply_function(Branch& branch, Term* function, ReferenceList const& _inputs)
{
    // Make a local copy of _inputs
    ReferenceList inputs = _inputs;

    if (function->needsUpdate)
        evaluate_term(function);

    // Check if 'function' is actually a type
    if (is_type(function))
    {
        if (inputs.count() != 0)
            throw std::runtime_error("Multiple inputs in constructor not supported");

        function = get_var_function(branch, function);
    }

    // If 'function' is not really a function, see if we can treat it like a function
    else if (!is_function(function)) {

        Type& type = as_type(function->type);

        if (!type.memberFunctions.contains(""))
            throw std::runtime_error(std::string("Term ") + function->toString()
                    + " is not a type, and has no default function");

        ReferenceList memberFunctionInputs;
        memberFunctionInputs.append(function);
        memberFunctionInputs.appendAll(inputs);

        function = type.memberFunctions[""];
        inputs = memberFunctionInputs;
    }

    // Attempt to re-use an existing term
    Term* existing = find_equivalent(function, inputs);

    if (existing != NULL)
        return existing;

    // Create the term
    return create_term(&branch, function, inputs);
}

Term* eval_function(Branch& branch, Term* function, ReferenceList const& inputs)
{
    Term* result = apply_function(branch, function, inputs);
    evaluate_term(result);
    return result;
}

Term* eval_function(Branch& branch, std::string const& functionName,
        ReferenceList const &inputs)
{
    Term* function = branch.findNamed(functionName);
    if (function == NULL)
        throw std::runtime_error(std::string("function not found: ")+functionName);

    return eval_function(branch, function, inputs);
}

void change_function(Term* term, Term* new_function)
{
    assert_good(term);

    assert_type(new_function, FUNCTION_TYPE);

    term->function = new_function;
    register_pointer(term, new_function);
}

void remap_pointers(Term* term, ReferenceMap const& map)
{
    assert_good(term);

    // make sure this map doesn't try to remap NULL, because such a thing
    // would almost definitely lead to errors.
    assert(!map.contains(NULL));

    term->inputs.remapPointers(map);
    for (unsigned int i=0; i < term->inputs.count(); i++)
        register_pointer(term, term->inputs[i]);

    term->function = map.getRemapped(term->function);
    register_pointer(term, term->function);

    if ((term->value != NULL) && (as_type(term->type).remapPointers != NULL))
        as_type(term->type).remapPointers(term, map);

    term->type = map.getRemapped(term->type);
    register_pointer(term, term->type);
}

void visit_pointers(Term* term, PointerVisitor &visitor)
{
    Type& type = as_type(term->type);

    term->inputs.visitPointers(visitor);
    visitor.visitPointer(term->function);
    visitor.visitPointer(term->type);

    if (type.visitPointers != NULL)
        type.visitPointers(term, visitor);
}

void remap_pointers(Term* term, Term* original, Term* replacement)
{
    assert_good(term);
    assert_good(original);

    ReferenceMap map;
    map[original] = replacement;
    remap_pointers(term, map);
}

} // namespace circa
<|endoftext|>


<commit_before>#include "sampler.hpp"

namespace vg {

pos_t Sampler::position(void) {
    uniform_int_distribution<size_t> xdist(1, xgidx->seq_length);
    size_t offset = xdist(rng);
    id_t id = xgidx->node_at_seq_pos(offset);
    uniform_int_distribution<size_t> flip(0, 1);
    bool rev = flip(rng);
    // 1-0 base conversion
    size_t node_offset = offset - xgidx->node_start(id) - 1;
    return make_pos_t(id, rev, node_offset);
}

string Sampler::sequence(size_t length) {
    pos_t pos = position();
    cerr << pos << endl;
    string seq;
    while (seq.size() < length) {
        auto nextc = next_pos_chars(pos);
        if (nextc.empty()) break;
        vector<pos_t> nextp;
        for (auto& n : nextc) nextp.push_back(n.first);
        // pick one at random
        uniform_int_distribution<int> next_dist(0, nextc.size()-1);
        // update our position
        pos = nextp.at(next_dist(rng));
        // append to our sequence
        seq += nextc[pos];
    }
    return seq;
}

vector<Edit> Sampler::mutate_edit(const Edit& edit,
                                  const pos_t& position,
                                  double base_error,
                                  double indel_error,
                                  const string& bases,
                                  uniform_real_distribution<double>& rprob,
                                  uniform_int_distribution<int>& rbase) {

    // we will build up a mapping representing the modified edit
    Mapping new_mapping;
    //*new_mapping.mutable_position() = make_position(position);
    // determine to-length of edit
    size_t to_length = edit.to_length();
    // we will keep track of the current base using this
    pos_t curr_pos = position;
    /// TODO we should punt if we aren't a pure edit
    // as in, we are something with mixed to and from lengths; like a block sub with an indel
    if (edit_is_match(edit) || edit_is_sub(edit)
        || edit_is_insertion(edit)) {
        // distribute mutations across this length
        for (size_t k = 0; k < to_length; ++k) {
            char c = 'N'; // in the case that we are in an insertion
            if (!edit_is_insertion(edit)) {
                c = pos_char(curr_pos);
                ++get_offset(curr_pos);
            }
            if (rprob(rng) <= base_error) {
                // pick another base than what c is
                char n;
                do {
                    n = bases[rbase(rng)];
                } while (n == c);
                // make the edit for the sub
                Edit* e = new_mapping.add_edit();
                string s(1, c);
                e->set_sequence(s);
                e->set_from_length(1);
                e->set_to_length(1);
            // if we've got a indel
            // note that we're using a simple geometric indel dsitribution here
            } else if (rprob(rng) <= indel_error) {
                if (rprob(rng) < 0.5) {
                    char n = bases[rbase(rng)];
                    Edit* e = new_mapping.add_edit();
                    string s(1, c);
                    e->set_sequence(s);
                    e->set_to_length(1);
                } else {
                    Edit* e = new_mapping.add_edit();
                    e->set_from_length(1);
                }
            } else {
                // make the edit for the 1bp match
                Edit* e = new_mapping.add_edit();
                e->set_from_length(1);
                e->set_to_length(1);
            }

        }
    } else if (edit_is_deletion(edit)) {
        // special case: 0 (deletion)
        // maybe we do nothing; as there is no length in the read
    }
    // simplify the mapping
    new_mapping = simplify(new_mapping);
    // copy the new edits
    vector<Edit> new_edits;
    for (size_t i = 0; i < new_mapping.edit_size(); ++i) {
        new_edits.push_back(new_mapping.edit(i));
    }
    // and send them back
    return new_edits;
}

Alignment Sampler::mutate(const Alignment& aln,
                          double base_error,
                          double indel_error) {

    if (base_error == 0 && indel_error == 0) return aln;

    string bases = "ATGC";
    uniform_real_distribution<double> rprob(0, 1);
    uniform_int_distribution<int> rbase(0, 3);

    Alignment mutaln;
    for (size_t i = 0; i < aln.path().mapping_size(); ++i) {
        auto& orig_mapping = aln.path().mapping(i);
        Mapping* new_mapping = mutaln.mutable_path()->add_mapping();
        *new_mapping->mutable_position() = orig_mapping.position();
        // for each edit in the mapping
        for (size_t j = 0; j < orig_mapping.edit_size(); ++j) {
            auto& orig_edit = orig_mapping.edit(j);
            auto new_edits = mutate_edit(orig_edit, make_pos_t(orig_mapping.position()),
                                         base_error, indel_error,
                                         bases, rprob, rbase);
            for (auto& edit : new_edits) {
                *new_mapping->add_edit() = edit;
            }
        }
    }
    // re-derive the alignment's sequence
    mutaln = simplify(mutaln);
    mutaln.set_sequence(alignment_seq(mutaln));
    return mutaln;
}

string Sampler::alignment_seq(const Alignment& aln) {
    // get the graph corresponding to the alignment path
    Graph sub;
    for (int i = 0; i < aln.path().mapping_size(); ++ i) {
        auto& m = aln.path().mapping(i);
        if (m.has_position() && m.position().node_id()) {
            auto id = aln.path().mapping(i).position().node_id();
            xgidx->neighborhood(id, 2, sub);
        }
    }
    VG g; g.extend(sub);
    return g.path_string(aln.path());
}

// generates a perfect alignment from the graph
Alignment Sampler::alignment(size_t length) {
    string seq;
    Alignment aln;
    Path* path = aln.mutable_path();
    pos_t pos = position();
    char c = pos_char(pos);
    // we do something wildly inefficient but conceptually clean
    // for each position in the mapping we add a mapping
    // at the end we will simplify the alignment, merging redundant mappings
    do {
        // add in the char for the current position
        seq += c;
        Mapping* mapping = path->add_mapping();
        *mapping->mutable_position() = make_position(pos);
        Edit* edit = mapping->add_edit();
        edit->set_from_length(1);
        edit->set_to_length(1);
        // decide the next position
        auto nextc = next_pos_chars(pos);
        // no new positions mean we are done; we've reached the end of the graph
        if (nextc.empty()) break;
        // what positions do we go to next?
        vector<pos_t> nextp;
        for (auto& n : nextc) nextp.push_back(n.first);
        // pick one at random
        uniform_int_distribution<int> next_dist(0, nextc.size()-1);
        // update our position
        pos = nextp.at(next_dist(rng));
        // update our char
        c = nextc[pos];
    } while (seq.size() < length);
    // save our sequence in the alignment
    aln.set_sequence(seq);
    // and simplify it
    return simplify(aln);
}

Alignment Sampler::alignment_with_error(size_t length,
                                        double base_error,
                                        double indel_error) {
    size_t maxiter = 100;
    Alignment aln;
    if (base_error || indel_error) {
        // sample a longer-than necessary alignment, then trim
        size_t iter = 0;
        while (iter++ < maxiter) {
            aln = alignment(length + 2 * ((double) length * indel_error));
            if (aln.sequence().size() == length) {
                break;
            } else if (aln.sequence().size() > length) {
                aln = strip_from_end(aln, aln.sequence().size() - length);
                break;
            }
        }
        if (iter == maxiter) {
            cerr << "[vg::Sampler] Warning: could not generate alignment of sufficient length. "
                 << "Graph may be too small, or indel rate too high." << endl;
        }
    } else {
        aln = alignment(length);
    }
    return aln;
}

char Sampler::pos_char(pos_t pos) {
    return xgidx->pos_char(id(pos), is_rev(pos), offset(pos));
}

map<pos_t, char> Sampler::next_pos_chars(pos_t pos) {
    map<pos_t, char> nexts;
    Node node = xgidx->node(id(pos));
    // if we are still in the node, return the next position and character
    if (offset(pos) < node.sequence().size()-1) {
        ++get_offset(pos);
        nexts[pos] = pos_char(pos);
    } else {
        // look at the next positions we could reach
        if (!is_rev(pos)) {
            // we are on the forward strand, the next things from this node come off the end
            for (auto& edge : xgidx->edges_on_end(id(pos))) {
                if (edge.from() == id(pos)) {
                    pos_t p = make_pos_t(edge.to(), edge.to_end(), 0);
                    nexts[p] = pos_char(p);
                } else if (edge.from_start() && edge.to_end() && edge.to() == id(pos)) {
                    // doubly inverted, should be normalized to forward but we handle here for safety
                    pos_t p = make_pos_t(edge.from(), false, 0);
                    nexts[p] = pos_char(p);
                }
            }
        } else {
            // we are on the reverse strand, the next things from this node come off the start
            for (auto& edge : xgidx->edges_on_start(id(pos))) {
                if (edge.to() == id(pos)) {
                    pos_t p = make_pos_t(edge.from(), !edge.from_start(), 0);
                    nexts[p] = pos_char(p);
                } else if (edge.from_start() && edge.to_end() && edge.from() == id(pos)) {
                    // doubly inverted, should be normalized to forward but we handle here for safety
                    pos_t p = make_pos_t(edge.to(), true, 0);
                    nexts[p] = pos_char(p);
                }
            }
        }
    }
    return nexts;
}

}
<commit_msg>fixes sampler to simulate errorful reads again<commit_after>#include "sampler.hpp"

namespace vg {

pos_t Sampler::position(void) {
    uniform_int_distribution<size_t> xdist(1, xgidx->seq_length);
    size_t offset = xdist(rng);
    id_t id = xgidx->node_at_seq_pos(offset);
    uniform_int_distribution<size_t> flip(0, 1);
    bool rev = flip(rng);
    // 1-0 base conversion
    size_t node_offset = offset - xgidx->node_start(id) - 1;
    return make_pos_t(id, rev, node_offset);
}

string Sampler::sequence(size_t length) {
    pos_t pos = position();
    cerr << pos << endl;
    string seq;
    while (seq.size() < length) {
        auto nextc = next_pos_chars(pos);
        if (nextc.empty()) break;
        vector<pos_t> nextp;
        for (auto& n : nextc) nextp.push_back(n.first);
        // pick one at random
        uniform_int_distribution<int> next_dist(0, nextc.size()-1);
        // update our position
        pos = nextp.at(next_dist(rng));
        // append to our sequence
        seq += nextc[pos];
    }
    return seq;
}

vector<Edit> Sampler::mutate_edit(const Edit& edit,
                                  const pos_t& position,
                                  double base_error,
                                  double indel_error,
                                  const string& bases,
                                  uniform_real_distribution<double>& rprob,
                                  uniform_int_distribution<int>& rbase) {

    // we will build up a mapping representing the modified edit
    Mapping new_mapping;
    //*new_mapping.mutable_position() = make_position(position);
    // determine to-length of edit
    size_t to_length = edit.to_length();
    // we will keep track of the current base using this
    pos_t curr_pos = position;
    /// TODO we should punt if we aren't a pure edit
    // as in, we are something with mixed to and from lengths; like a block sub with an indel
    if (edit_is_match(edit) || edit_is_sub(edit)
        || edit_is_insertion(edit)) {
        // distribute mutations across this length
        for (size_t k = 0; k < to_length; ++k) {
            char c = 'N'; // in the case that we are in an insertion
            if (!edit_is_insertion(edit)) {
                c = pos_char(curr_pos);
                ++get_offset(curr_pos);
            }
            if (rprob(rng) <= base_error) {
                // pick another base than what c is
                char n;
                do {
                    n = bases[rbase(rng)];
                } while (n == c);
                // make the edit for the sub
                Edit* e = new_mapping.add_edit();
                string s(1, c);
                e->set_sequence(s);
                e->set_from_length(1);
                e->set_to_length(1);
            // if we've got a indel
            // note that we're using a simple geometric indel dsitribution here
            } else if (rprob(rng) <= indel_error) {
                if (rprob(rng) < 0.5) {
                    char n = bases[rbase(rng)];
                    Edit* e = new_mapping.add_edit();
                    string s(1, c);
                    e->set_sequence(s);
                    e->set_to_length(1);
                } else {
                    Edit* e = new_mapping.add_edit();
                    e->set_from_length(1);
                }
            } else {
                // make the edit for the 1bp match
                Edit* e = new_mapping.add_edit();
                e->set_from_length(1);
                e->set_to_length(1);
            }

        }
    } else if (edit_is_deletion(edit)) {
        // special case: 0 (deletion)
        // maybe we do nothing; as there is no length in the read
    }
    // simplify the mapping
    new_mapping = simplify(new_mapping);
    // copy the new edits
    vector<Edit> new_edits;
    for (size_t i = 0; i < new_mapping.edit_size(); ++i) {
        new_edits.push_back(new_mapping.edit(i));
    }
    // and send them back
    return new_edits;
}

Alignment Sampler::mutate(const Alignment& aln,
                          double base_error,
                          double indel_error) {

    if (base_error == 0 && indel_error == 0) return aln;

    string bases = "ATGC";
    uniform_real_distribution<double> rprob(0, 1);
    uniform_int_distribution<int> rbase(0, 3);

    Alignment mutaln;
    for (size_t i = 0; i < aln.path().mapping_size(); ++i) {
        auto& orig_mapping = aln.path().mapping(i);
        Mapping* new_mapping = mutaln.mutable_path()->add_mapping();
        *new_mapping->mutable_position() = orig_mapping.position();
        // for each edit in the mapping
        for (size_t j = 0; j < orig_mapping.edit_size(); ++j) {
            auto& orig_edit = orig_mapping.edit(j);
            auto new_edits = mutate_edit(orig_edit, make_pos_t(orig_mapping.position()),
                                         base_error, indel_error,
                                         bases, rprob, rbase);
            for (auto& edit : new_edits) {
                *new_mapping->add_edit() = edit;
            }
        }
    }
    // re-derive the alignment's sequence
    mutaln = simplify(mutaln);
    mutaln.set_sequence(alignment_seq(mutaln));
    return mutaln;
}

string Sampler::alignment_seq(const Alignment& aln) {
    // get the graph corresponding to the alignment path
    Graph sub;
    for (int i = 0; i < aln.path().mapping_size(); ++ i) {
        auto& m = aln.path().mapping(i);
        if (m.has_position() && m.position().node_id()) {
            auto id = aln.path().mapping(i).position().node_id();
            xgidx->neighborhood(id, 2, sub);
        }
    }
    VG g; g.extend(sub);
    return g.path_string(aln.path());
}

// generates a perfect alignment from the graph
Alignment Sampler::alignment(size_t length) {
    string seq;
    Alignment aln;
    Path* path = aln.mutable_path();
    pos_t pos = position();
    char c = pos_char(pos);
    // we do something wildly inefficient but conceptually clean
    // for each position in the mapping we add a mapping
    // at the end we will simplify the alignment, merging redundant mappings
    do {
        // add in the char for the current position
        seq += c;
        Mapping* mapping = path->add_mapping();
        *mapping->mutable_position() = make_position(pos);
        Edit* edit = mapping->add_edit();
        edit->set_from_length(1);
        edit->set_to_length(1);
        // decide the next position
        auto nextc = next_pos_chars(pos);
        // no new positions mean we are done; we've reached the end of the graph
        if (nextc.empty()) break;
        // what positions do we go to next?
        vector<pos_t> nextp;
        for (auto& n : nextc) nextp.push_back(n.first);
        // pick one at random
        uniform_int_distribution<int> next_dist(0, nextc.size()-1);
        // update our position
        pos = nextp.at(next_dist(rng));
        // update our char
        c = nextc[pos];
    } while (seq.size() < length);
    // save our sequence in the alignment
    aln.set_sequence(seq);
    // and simplify it
    return simplify(aln);
}

Alignment Sampler::alignment_with_error(size_t length,
                                        double base_error,
                                        double indel_error) {
    size_t maxiter = 100;
    Alignment aln;
    if (base_error > 0 || indel_error > 0) {
        // sample a longer-than necessary alignment, then trim
        size_t iter = 0;
        while (iter++ < maxiter) {
            aln = mutate(
                alignment(length + 2 * ((double) length * indel_error)),
                base_error, indel_error);
            if (aln.sequence().size() == length) {
                break;
            } else if (aln.sequence().size() > length) {
                aln = strip_from_end(aln, aln.sequence().size() - length);
                break;
            }
        }
        if (iter == maxiter) {
            cerr << "[vg::Sampler] Warning: could not generate alignment of sufficient length. "
                 << "Graph may be too small, or indel rate too high." << endl;
        }
    } else {
        aln = alignment(length);
    }
    return aln;
}

char Sampler::pos_char(pos_t pos) {
    return xgidx->pos_char(id(pos), is_rev(pos), offset(pos));
}

map<pos_t, char> Sampler::next_pos_chars(pos_t pos) {
    map<pos_t, char> nexts;
    Node node = xgidx->node(id(pos));
    // if we are still in the node, return the next position and character
    if (offset(pos) < node.sequence().size()-1) {
        ++get_offset(pos);
        nexts[pos] = pos_char(pos);
    } else {
        // look at the next positions we could reach
        if (!is_rev(pos)) {
            // we are on the forward strand, the next things from this node come off the end
            for (auto& edge : xgidx->edges_on_end(id(pos))) {
                if (edge.from() == id(pos)) {
                    pos_t p = make_pos_t(edge.to(), edge.to_end(), 0);
                    nexts[p] = pos_char(p);
                } else if (edge.from_start() && edge.to_end() && edge.to() == id(pos)) {
                    // doubly inverted, should be normalized to forward but we handle here for safety
                    pos_t p = make_pos_t(edge.from(), false, 0);
                    nexts[p] = pos_char(p);
                }
            }
        } else {
            // we are on the reverse strand, the next things from this node come off the start
            for (auto& edge : xgidx->edges_on_start(id(pos))) {
                if (edge.to() == id(pos)) {
                    pos_t p = make_pos_t(edge.from(), !edge.from_start(), 0);
                    nexts[p] = pos_char(p);
                } else if (edge.from_start() && edge.to_end() && edge.from() == id(pos)) {
                    // doubly inverted, should be normalized to forward but we handle here for safety
                    pos_t p = make_pos_t(edge.to(), true, 0);
                    nexts[p] = pos_char(p);
                }
            }
        }
    }
    return nexts;
}

}
<|endoftext|>


<commit_before>/** @file

  Record compatibility definitions

  @section license License

  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 "libts.h"
#include "P_RecFile.h"
#include "P_RecDefs.h"
#include "P_RecUtils.h"

//-------------------------------------------------------------------------
// RecFileOpenR
//-------------------------------------------------------------------------

RecHandle
RecFileOpenR(const char *file)
{
  RecHandle h_file;
  return ((h_file =::open(file, O_RDONLY)) <= 0) ? REC_HANDLE_INVALID : h_file;
}

//-------------------------------------------------------------------------
// RecFileOpenW
//-------------------------------------------------------------------------

RecHandle
RecFileOpenW(const char *file)
{
  RecHandle h_file;

  if ((h_file =::open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
    return REC_HANDLE_INVALID;
  }
  fcntl(h_file, F_SETFD, 1);
  return h_file;
}

//-------------------------------------------------------------------------
// RecFileSync
//-------------------------------------------------------------------------

int RecFileSync(RecHandle h_file)
{
  return (fsync(h_file) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL;
}

//-------------------------------------------------------------------------
// RecFileClose
//-------------------------------------------------------------------------

int
RecFileClose(RecHandle h_file)
{
  return (close(h_file) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL;
}

//-------------------------------------------------------------------------
// RecFileRead
//-------------------------------------------------------------------------

int
RecFileRead(RecHandle h_file, char *buf, int size, int *bytes_read)
{
  if ((*bytes_read =::read(h_file, buf, size)) <= 0) {
    *bytes_read = 0;
    return REC_ERR_FAIL;
  }
  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecFileWrite
//-------------------------------------------------------------------------

int
RecFileWrite(RecHandle h_file, char *buf, int size, int *bytes_written)
{
  if ((*bytes_written =::write(h_file, buf, size)) < 0) {
    *bytes_written = 0;
    return REC_ERR_FAIL;
  }
  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecFileGetSize
//-------------------------------------------------------------------------

int
RecFileGetSize(RecHandle h_file)
{
  struct stat fileStats;
  fstat(h_file, &fileStats);
  return (int) fileStats.st_size;
}

//-------------------------------------------------------------------------
// RecFileExists
//-------------------------------------------------------------------------

int
RecFileExists(const char *file)
{
  RecHandle h_file;
  if ((h_file = RecFileOpenR(file)) == REC_HANDLE_INVALID) {
    return REC_ERR_FAIL;
  }
  RecFileClose(h_file);
  return REC_ERR_OKAY;

}

//-------------------------------------------------------------------------
// RecPipeCreate
//-------------------------------------------------------------------------

RecHandle
RecPipeCreate(const char *base_path, const char *name)
{

  RecHandle listenfd;
  RecHandle acceptfd;
  struct sockaddr_un servaddr;
  struct sockaddr_un cliaddr;
  int servaddr_len;
  socklen_t cliaddr_len;

  // first, let's disable SIGPIPE (move out later!)
  struct sigaction act, oact;
  act.sa_handler = SIG_IGN;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  act.sa_flags |= SA_RESTART;
  sigaction(SIGPIPE, &act, &oact);

  // construct a path/filename for the pipe
#define SEPERATOR "/"
  char path[PATH_NAME_MAX];
  snprintf(path, sizeof(path), "%s%s%s", base_path, SEPERATOR, name);
#undef SEPERATOR
  if (strlen(path) > (sizeof(servaddr.sun_path) - 1)) {
    RecLog(DL_Warning, "[RecPipeCreate] Path name too long; exiting\n");
    return REC_HANDLE_INVALID;
  }

  unlink(path);

  if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] socket error\n");
    return REC_HANDLE_INVALID;
  }
  // set so that child process doesn't inherit our fd
  if (fcntl(listenfd, F_SETFD, 1) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] fcntl error\n");
    return REC_HANDLE_INVALID;
  }

  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sun_family = AF_UNIX;
  ink_strlcpy(servaddr.sun_path, path, sizeof(servaddr.sun_path));

  int optval = 1;
  if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof(int)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] setsockopt error\n");
    return REC_HANDLE_INVALID;
  }

  servaddr_len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);
  if ((bind(listenfd, (struct sockaddr *) &servaddr, servaddr_len)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] bind error\n");
    return REC_HANDLE_INVALID;
  }
  // listen, backlog of 1 (expecting only one client)
  if ((listen(listenfd, 1)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] listen error\n");
    return REC_HANDLE_INVALID;
  }
  // block until we get a connection from the other side
  cliaddr_len = sizeof(cliaddr);
  if ((acceptfd = accept(listenfd, (struct sockaddr *) &cliaddr,
                         &cliaddr_len)) < 0) {
    return REC_HANDLE_INVALID;
  }

  close(listenfd);

  return acceptfd;
}

//-------------------------------------------------------------------------
// RecPipeConnect
//-------------------------------------------------------------------------

RecHandle
RecPipeConnect(const char *base_path, const char *name)
{

  RecHandle sockfd;
  struct sockaddr_un servaddr;
  int servaddr_len;

  // construct a path/filename for the pipe
#define SEPERATOR "/"
  char path[PATH_NAME_MAX];
  snprintf(path, sizeof(path), "%s%s%s", base_path, SEPERATOR, name);
#undef SEPERATOR
  if (strlen(path) > (sizeof(servaddr.sun_path) - 1)) {
    RecLog(DL_Warning, "[RecPipeConnect] Path name too long\n");
    return REC_HANDLE_INVALID;
  }
  // Setup Connection to LocalManager */
  memset((char *) &servaddr, 0, sizeof(servaddr));
  servaddr.sun_family = AF_UNIX;
  ink_strlcpy(servaddr.sun_path, path, sizeof(servaddr.sun_path));
  servaddr_len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);

  if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    RecLog(DL_Warning, "[RecPipeConnect] socket error\n");
    return REC_HANDLE_INVALID;
  }
  // set so that child process doesn't inherit our fd
  if (fcntl(sockfd, F_SETFD, 1) < 0) {
    RecLog(DL_Warning, "[RecPipeConnect] fcntl error\n");
    return REC_HANDLE_INVALID;
  }
  // blocking connect
  if ((connect(sockfd, (struct sockaddr *) &servaddr, servaddr_len)) < 0) {
    RecLog(DL_Warning, "[RecPipeConnect] connect error\n");
    return REC_HANDLE_INVALID;
  }

  return sockfd;
}

//-------------------------------------------------------------------------
// RecPipeRead
//-------------------------------------------------------------------------

int
RecPipeRead(RecHandle h_pipe, char *buf, int size)
{
  int bytes_read = 0;
  int bytes_wanted = size;
  char *p = buf;
  while (bytes_wanted > 0) {
    bytes_read = read(h_pipe, p, bytes_wanted);
    if (bytes_read < 0) {
      // FIXME: something more intelligent please!
      return REC_ERR_FAIL;
    }
    bytes_wanted -= bytes_read;
    p += bytes_read;
  }
  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecPipeWrite
//-------------------------------------------------------------------------

int
RecPipeWrite(RecHandle h_pipe, char *buf, int size)
{
  int bytes_written = 0;
  int bytes_to_write = size;
  char *p = buf;
  while (bytes_to_write > 0) {
    bytes_written = write(h_pipe, p, bytes_to_write);
    if (bytes_written < 0) {
      // FIXME: something more intelligent please!
      return REC_ERR_FAIL;
    }
    bytes_to_write -= bytes_written;
    p += bytes_written;
  }

  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecPipeClose
//-------------------------------------------------------------------------

int
RecPipeClose(RecHandle h_pipe)
{
  return (close(h_pipe) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL;
}
<commit_msg>TS-1475: Coverity 1021828 Resource leak<commit_after>/** @file

  Record compatibility definitions

  @section license License

  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 "libts.h"
#include "P_RecFile.h"
#include "P_RecDefs.h"
#include "P_RecUtils.h"

//-------------------------------------------------------------------------
// RecFileOpenR
//-------------------------------------------------------------------------

RecHandle
RecFileOpenR(const char *file)
{
  RecHandle h_file;
  return ((h_file =::open(file, O_RDONLY)) <= 0) ? REC_HANDLE_INVALID : h_file;
}

//-------------------------------------------------------------------------
// RecFileOpenW
//-------------------------------------------------------------------------

RecHandle
RecFileOpenW(const char *file)
{
  RecHandle h_file;

  if ((h_file =::open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
    return REC_HANDLE_INVALID;
  }
  fcntl(h_file, F_SETFD, 1);
  return h_file;
}

//-------------------------------------------------------------------------
// RecFileSync
//-------------------------------------------------------------------------

int RecFileSync(RecHandle h_file)
{
  return (fsync(h_file) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL;
}

//-------------------------------------------------------------------------
// RecFileClose
//-------------------------------------------------------------------------

int
RecFileClose(RecHandle h_file)
{
  return (close(h_file) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL;
}

//-------------------------------------------------------------------------
// RecFileRead
//-------------------------------------------------------------------------

int
RecFileRead(RecHandle h_file, char *buf, int size, int *bytes_read)
{
  if ((*bytes_read =::read(h_file, buf, size)) <= 0) {
    *bytes_read = 0;
    return REC_ERR_FAIL;
  }
  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecFileWrite
//-------------------------------------------------------------------------

int
RecFileWrite(RecHandle h_file, char *buf, int size, int *bytes_written)
{
  if ((*bytes_written =::write(h_file, buf, size)) < 0) {
    *bytes_written = 0;
    return REC_ERR_FAIL;
  }
  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecFileGetSize
//-------------------------------------------------------------------------

int
RecFileGetSize(RecHandle h_file)
{
  struct stat fileStats;
  fstat(h_file, &fileStats);
  return (int) fileStats.st_size;
}

//-------------------------------------------------------------------------
// RecFileExists
//-------------------------------------------------------------------------

int
RecFileExists(const char *file)
{
  RecHandle h_file;
  if ((h_file = RecFileOpenR(file)) == REC_HANDLE_INVALID) {
    return REC_ERR_FAIL;
  }
  RecFileClose(h_file);
  return REC_ERR_OKAY;

}

//-------------------------------------------------------------------------
// RecPipeCreate
//-------------------------------------------------------------------------

RecHandle
RecPipeCreate(const char *base_path, const char *name)
{

  RecHandle listenfd;
  RecHandle acceptfd;
  struct sockaddr_un servaddr;
  struct sockaddr_un cliaddr;
  int servaddr_len;
  socklen_t cliaddr_len;

  // first, let's disable SIGPIPE (move out later!)
  struct sigaction act, oact;
  act.sa_handler = SIG_IGN;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  act.sa_flags |= SA_RESTART;
  sigaction(SIGPIPE, &act, &oact);

  // construct a path/filename for the pipe
#define SEPERATOR "/"
  char path[PATH_NAME_MAX];
  snprintf(path, sizeof(path), "%s%s%s", base_path, SEPERATOR, name);
#undef SEPERATOR
  if (strlen(path) > (sizeof(servaddr.sun_path) - 1)) {
    RecLog(DL_Warning, "[RecPipeCreate] Path name too long; exiting\n");
    return REC_HANDLE_INVALID;
  }

  unlink(path);

  if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] socket error\n");
    return REC_HANDLE_INVALID;
  }
  // set so that child process doesn't inherit our fd
  if (fcntl(listenfd, F_SETFD, 1) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] fcntl error\n");
    return REC_HANDLE_INVALID;
  }

  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sun_family = AF_UNIX;
  ink_strlcpy(servaddr.sun_path, path, sizeof(servaddr.sun_path));

  int optval = 1;
  if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof(int)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] setsockopt error\n");
    return REC_HANDLE_INVALID;
  }

  servaddr_len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);
  if ((bind(listenfd, (struct sockaddr *) &servaddr, servaddr_len)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] bind error\n");
    return REC_HANDLE_INVALID;
  }
  // listen, backlog of 1 (expecting only one client)
  if ((listen(listenfd, 1)) < 0) {
    RecLog(DL_Warning, "[RecPipeCreate] listen error\n");
    return REC_HANDLE_INVALID;
  }
  // block until we get a connection from the other side
  cliaddr_len = sizeof(cliaddr);
  if ((acceptfd = accept(listenfd, (struct sockaddr *) &cliaddr,
                         &cliaddr_len)) < 0) {
    return REC_HANDLE_INVALID;
  }

  close(listenfd);

  return acceptfd;
}

//-------------------------------------------------------------------------
// RecPipeConnect
//-------------------------------------------------------------------------

RecHandle
RecPipeConnect(const char *base_path, const char *name)
{

  RecHandle sockfd;
  struct sockaddr_un servaddr;
  int servaddr_len;

  // construct a path/filename for the pipe
#define SEPERATOR "/"
  char path[PATH_NAME_MAX];
  snprintf(path, sizeof(path), "%s%s%s", base_path, SEPERATOR, name);
#undef SEPERATOR
  if (strlen(path) > (sizeof(servaddr.sun_path) - 1)) {
    RecLog(DL_Warning, "[RecPipeConnect] Path name too long\n");
    return REC_HANDLE_INVALID;
  }
  // Setup Connection to LocalManager */
  memset((char *) &servaddr, 0, sizeof(servaddr));
  servaddr.sun_family = AF_UNIX;
  ink_strlcpy(servaddr.sun_path, path, sizeof(servaddr.sun_path));
  servaddr_len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);

  if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    RecLog(DL_Warning, "[RecPipeConnect] socket error\n");
    return REC_HANDLE_INVALID;
  }
  // set so that child process doesn't inherit our fd
  if (fcntl(sockfd, F_SETFD, 1) < 0) {
    RecLog(DL_Warning, "[RecPipeConnect] fcntl error\n");
    close(sockfd);
    return REC_HANDLE_INVALID;
  }
  // blocking connect
  if ((connect(sockfd, (struct sockaddr *) &servaddr, servaddr_len)) < 0) {
    RecLog(DL_Warning, "[RecPipeConnect] connect error\n");
    close(sockfd);
    return REC_HANDLE_INVALID;
  }

  return sockfd;
}

//-------------------------------------------------------------------------
// RecPipeRead
//-------------------------------------------------------------------------

int
RecPipeRead(RecHandle h_pipe, char *buf, int size)
{
  int bytes_read = 0;
  int bytes_wanted = size;
  char *p = buf;
  while (bytes_wanted > 0) {
    bytes_read = read(h_pipe, p, bytes_wanted);
    if (bytes_read < 0) {
      // FIXME: something more intelligent please!
      return REC_ERR_FAIL;
    }
    bytes_wanted -= bytes_read;
    p += bytes_read;
  }
  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecPipeWrite
//-------------------------------------------------------------------------

int
RecPipeWrite(RecHandle h_pipe, char *buf, int size)
{
  int bytes_written = 0;
  int bytes_to_write = size;
  char *p = buf;
  while (bytes_to_write > 0) {
    bytes_written = write(h_pipe, p, bytes_to_write);
    if (bytes_written < 0) {
      // FIXME: something more intelligent please!
      return REC_ERR_FAIL;
    }
    bytes_to_write -= bytes_written;
    p += bytes_written;
  }

  return REC_ERR_OKAY;
}

//-------------------------------------------------------------------------
// RecPipeClose
//-------------------------------------------------------------------------

int
RecPipeClose(RecHandle h_pipe)
{
  return (close(h_pipe) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL;
}
<|endoftext|>


<commit_before>#include <cassert>
#include <climits>
#include <cstring>

#include <vector>
#include <algorithm>

#include <omp.h>

#include "../CSR.hpp"

using namespace std;

void getInversePerm(int *inversePerm, const int *perm, int n);

// compute prefix sum of levels
static void prefixSumOfLevels(
  int *prefixSum,
  const CSR *A, const int *levels, int numLevels)
{
  int *local_count = new int[omp_get_max_threads()*numLevels];
  memset(local_count, 0, sizeof(int)*omp_get_max_threads()*numLevels);

/*#pragma omp parallel
  {
    int nthreads = omp_get_num_threads();
    int tid = omp_get_thread_num();*/

//#pragma omp for
    for (int i = 0; i < A->m; ++i) {
      ++local_count[/*tid*numLevels + */levels[i]];
    }

/*#pragma omp for
    for (int i = 0; i < levels; ++i) {
      for (int j = 1; j < nthreads; ++j) {
        local_count[i] += local_count[tid*numLevels + i];
      }
    }*/

//#pragma omp master
    {
      prefixSum[0] = 0;
      for (int i = 1; i <= numLevels; ++i) {
        prefixSum[i] = prefixSum[i - 1] + local_count[i - 1];
      }
    }
  //}

  delete[] local_count;
  assert(prefixSum[numLevels] == A->m);
}

int bfs(const CSR *A, int source, int *levels) {
  int numLevels = 0;
  levels[source] = numLevels;
  numLevels++;

  vector<int> q, nextQ;
  q.push_back(source);

  while (!q.empty()) {
    for (int u : q) {
      int index = nextQ.size();
      assert(levels[u] == numLevels - 1);

      for (int j = A->rowPtr[u]; j < A->rowPtr[u + 1]; ++j) {
        int v = A->colIdx[j];
        if (levels[v] > levels[u] + 1) {
          levels[v] = levels[u] + 1;
          nextQ.push_back(v);
        }
      }
    } // for each u in current level

    q.clear();
    q.swap(nextQ);
    ++numLevels;
  } // while !q.empty()

  return numLevels;
}

void CSR::getRCMPermutationNew(int *perm, int *inversePerm, int source /*=-1*/) const
{
  // 1. Start vertex
  // TODO: pseudo diameter heuristic
  assert(source >= 0 && source < m);

  // 2. BFS
  int *levels = new int[m];
  for (int i = 0; i < m; ++i) {
    levels[i] = INT_MAX;
  }

  int numLevels = bfs(this, source, levels);

  // 3. Reorder
  int *prefixSum = new int[numLevels + 1];
  prefixSumOfLevels(prefixSum, this, levels, numLevels);

  inversePerm[0] = source;
  int read_offset = 0;
  int write_offset = 1;

  for (int l = 0; l < numLevels; ++l) {
    while (read_offset != prefixSum[l + 1]) {
      int u = inversePerm[read_offset];
      ++read_offset;
      vector<int> children;
      for (int j = rowPtr[u]; j < rowPtr[u + 1]; ++j) {
        int v = colIdx[j];
        if (levels[v] == l + 1) {
          children.push_back(v);
          levels[v] = -1;
        }
      }
      sort(children.begin(), children.end());
      for (int c : children) {
        inversePerm[write_offset] = c;
        ++write_offset;
      }
    }
  } // for each level
  delete[] levels;

  int *temp = new int[m];
  reverse_copy(inversePerm, inversePerm + m, temp);
  copy(temp, temp + m, inversePerm);
  delete[] temp;

  getInversePerm(perm, inversePerm, n);
}
<commit_msg>parallelizing prefix sum<commit_after>#include <cassert>
#include <climits>
#include <cstring>

#include <vector>
#include <algorithm>

#include <omp.h>

#include "../CSR.hpp"

using namespace std;

void getInversePerm(int *inversePerm, const int *perm, int n);

// compute prefix sum of levels
static void prefixSumOfLevels(
  int *prefixSum,
  const CSR *A, const int *levels, int numLevels)
{
  int *local_count = new int[omp_get_max_threads()*numLevels];
  int *local_sum_array = new int[omp_get_max_threads() + 1];

#pragma omp parallel
  {
    int nthreads = omp_get_num_threads();
    int tid = omp_get_thread_num();

    memset(local_count + tid*numLevels, 0, sizeof(int)*numLevels);

#pragma omp for
    for (int i = 0; i < A->m; ++i) {
      ++local_count[tid*numLevels + levels[i]];
    }

    int lPerThread = (numLevels + nthreads - 1)/nthreads;
    int lBegin = min(lPerThread*tid, numLevels);
    int lEnd = min(lBegin + lPerThread, numLevels);

    int local_sum = 0;

    for (int l = lBegin; l < lEnd; ++l) {
      prefixSum[l] = local_sum;
      for (int t = 0; t < nthreads; ++t) {
        local_sum += local_count[t*numLevels + l];
      }
    }

    local_sum_array[tid + 1] = local_sum;

#pragma omp barrier
    if (0 == tid)
    {
      for (int t = 1; t <= nthreads; ++t) {
        local_sum_array[t + 1] += local_sum_array[t];
      }
      assert(local_sum_array[nthreads] == A->m);
      prefixSum[numLevels] = A->m;
    }
#pragma omp barrier

    if (tid > 0) {
      local_sum = local_sum_array[tid];
      for (int l = lBegin; l < lEnd; ++l) {
        prefixSum[l] += local_sum;
      }
    }
  } // omp parallel

  delete[] local_count;
  delete[] local_sum_array;
}

int bfs(const CSR *A, int source, int *levels) {
  int numLevels = 0;
  levels[source] = numLevels;
  numLevels++;

  int *q = new int[A->m];
  int *nextQ = new int[A->m];
  q[0] = source;
  int qTail = 1;
  int nextQTail;

  while (qTail) {
    nextQTail = 0;
    for (int i = 0; i < qTail; ++i) {
      int u = q[i];
      assert(levels[u] == numLevels - 1);

      for (int j = A->rowPtr[u]; j < A->rowPtr[u + 1]; ++j) {
        int v = A->colIdx[j];
        if (levels[v] == INT_MAX) {
          levels[v] = levels[u] + 1;
          nextQ[nextQTail] = v;
          ++nextQTail;
        }
      }
    } // for each u in current level

    swap(q, nextQ);
    qTail = nextQTail;
    ++numLevels;
  } // while q not empty

  delete[] q;
  delete[] nextQ;

  return numLevels;
}

void CSR::getRCMPermutationNew(int *perm, int *inversePerm, int source /*=-1*/) const
{
  // 1. Start vertex
  // TODO: pseudo diameter heuristic
  assert(source >= 0 && source < m);

  // 2. BFS
  int *levels = new int[m];
#pragma omp parallel for
  for (int i = 0; i < m; ++i) {
    levels[i] = INT_MAX;
  }

  int numLevels = bfs(this, source, levels);

  // 3. Reorder
  int *prefixSum = new int[numLevels + 1];
  prefixSumOfLevels(prefixSum, this, levels, numLevels);

  inversePerm[0] = source;
  int read_offset = 0;
  int write_offset = 1;

  for (int l = 0; l < numLevels; ++l) {
    while (read_offset != prefixSum[l + 1]) {
      int u = inversePerm[read_offset];
      ++read_offset;
      vector<int> children;
      for (int j = rowPtr[u]; j < rowPtr[u + 1]; ++j) {
        int v = colIdx[j];
        if (levels[v] == l + 1) {
          children.push_back(v);
          levels[v] = -1;
        }
      }
      sort(children.begin(), children.end());
      for (int c : children) {
        inversePerm[write_offset] = c;
        ++write_offset;
      }
    }
  } // for each level
  delete[] levels;

  int *temp = new int[m];
  reverse_copy(inversePerm, inversePerm + m, temp);
  copy(temp, temp + m, inversePerm);
  delete[] temp;

  getInversePerm(perm, inversePerm, n);
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <utility>

#include "../inc/model.hpp"
#include "../inc/dual.hpp"
#include "../inc/quat.hpp"

namespace Model {
	template<typename R>
	unsigned int model<R>::nextID = 0;

	template<class C> std::ostream& operator<<(std::ostream& lhs,
			std::vector<std::pair<const char*,C>> const& rhs) {
		for(auto p : rhs) {
			if(p.first) {
				std::string fstr(p.first);
				if(fstr.size() > 0) {
					lhs << "\r\n" << fstr << "\r\n";
				}
			}
			lhs << "\t" << p.second << "\r\n";
		}
		return lhs << std::endl;
	}

	int test(void) {
		float theta = 30 * M_PI/180,
			  rw = float(cos(theta/2)),
			  rz = float(sin(theta/2));
		dual<float> u = {1,{0,0,0.5,0}},
			T = {1,{0,0.5}},
			R = {{rw,0,0,rz},0};

		std::vector<std::pair<const char*,dual<float>>> ds{
			{"u (origin)", u},

			{"T (translates by <1,0,0>)", T},
			{"T u ~T", T(u)},

			{"R (rotates by 30 around <0,0,1>)", R},
			{"R u ~R", R(u)},

			{"R T", R*T},
			{"R (T u ~T) ~R = (R T) u ~(R T)",
				R(T(u))}, {"", (R*T)(u)},

			{"T R", T*R},
			{"T (R u ~R) ~T = (T R) u ~(R T)",
				T(R(u))}, {"", (T*R)(u)},
			{"1/(T R)", 1/(T*R)}
		};
		std::cout << ds << std::endl;

		/*model<float> root, a, b;
		root.subs.emplace(a, T);
		root.subs.emplace(b, R);
		std::cout << root << std::endl;*/
	}
}
<commit_msg>Began refactoring for proper move semantics (in progress)<commit_after>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <utility>

#include "../inc/model.hpp"
#include "../inc/dual.hpp"
#include "../inc/quat.hpp"

namespace Model {
	template<typename R>
	unsigned int model<R>::nextID = 0;

	template<class C> std::ostream& operator<<(std::ostream& lhs,
			std::vector<std::pair<const char*,C>> const& rhs) {
		for(auto p : rhs) {
			if(p.first) {
				std::string fstr(p.first);
				if(fstr.size() > 0) {
					lhs << "\r\n" << fstr << "\r\n";
				}
			}
			lhs << "\t" << p.second << "\r\n";
		}
		return lhs << std::endl;
	}

	int test(void) {
		std::cout << "A" << std::endl;
		dual<float> a(1);
		std::cout << "\r\nB" << std::endl;
		dual<float> b = {1};
		std::cout << "\r\nC" << std::endl;
		dual<float> c = std::move(a);
		std::cout << "\r\n" << std::endl;

		dual<float> extra(c.u, c.v);
		extra.u += extra.u;

		std::vector<dual<float>*> lst = {
			&a, &b, &c, &extra};
		std::cout << "\r\nDump:" << std::endl;
		for(auto d : lst) {std::cout << *d << std::endl;}

		/*float theta = 30 * M_PI/180,
			  rw = float(cos(theta/2)),
			  rz = float(sin(theta/2));
		dual<float> u = 1,
			T(1,0,0,0,0,0.5,0,0),
			R(rw,0,0,rz,0,0,0,0);

		std::vector<std::pair<const char*,dual<float>>> ds{
			{"u (origin)", u},

			{"T (translates by <1,0,0>)", T},
			{"T u ~T", T(u)},

			{"R (rotates by 30 around <0,0,1>)", R},
			{"R u ~R", R(u)},

			{"R T", R*T},
			{"R (T u ~T) ~R = (R T) u ~(R T)",
				R(T(u))}, {"", (R*T)(u)},

			{"T R", T*R},
			{"T (R u ~R) ~T = (T R) u ~(R T)",
				T(R(u))}, {"", (T*R)(u)},
			{"1/(T R)", dual<float>(1)/(T*R)}
		};
		std::cout << ds << std::endl;*/
	}
}
<|endoftext|>