text:
// Copyright (c) 2017-2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "addressbook.h"
#include "amount.h"
#include "base58.h"
#include "coincontrol.h"
#include "init.h"
#include "libzerocoin/Coin.h"
#include "net.h"
#include "rpc/server.h"
#include "spork.h"
#include "utilmoneystr.h"
#include "wallet.h"
#include "zpiv/deterministicmint.h"
#include "zpivchain.h"

#include <boost/assign/list_of.hpp>

#include <univalue.h>

UniValue getzerocoinbalance(const JSONRPCRequest& request)
{

    if (request.fHelp || request.params.size() != 0)
        throw std::runtime_error(
            "getzerocoinbalance\n"
            "\nReturn the wallet's total zPIV balance.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nResult:\n"
            "amount         (numeric) Total zPIV balance.\n"

            "\nExamples:\n" +
            HelpExampleCli("getzerocoinbalance", "") + HelpExampleRpc("getzerocoinbalance", ""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked(true);

    UniValue ret(UniValue::VOBJ);
    const UniValue& zcBalance = ValueFromAmount(pwalletMain->GetZerocoinBalance());
    ret.pushKV("Total", zcBalance);
    ret.pushKV("Mature", zcBalance);
    ret.pushKV("Unconfirmed", 0);
    ret.pushKV("Immature", 0);
    return ret;

}

UniValue listmintedzerocoins(const JSONRPCRequest& request)
{

    if (request.fHelp || request.params.size() > 2)
        throw std::runtime_error(
            "listmintedzerocoins (fVerbose) (fMatureOnly)\n"
            "\nList all zPIV mints in the wallet.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. fVerbose      (boolean, optional, default=false) Output mints metadata.\n"
            "2. fMatureOnly   (boolean, optional, default=false) List only mature mints.\n"
            "                 Set only if fVerbose is specified\n"

            "\nResult (with fVerbose=false):\n"
            "[\n"
            "  \"xxx\"      (string) Pubcoin in hex format.\n"
            "  ,...\n"
            "]\n"

            "\nResult (with fVerbose=true):\n"
            "[\n"
            "  {\n"
            "    \"serial hash\": \"xxx\",   (string) Mint serial hash in hex format.\n"
            "    \"version\": n,   (numeric) Zerocoin version number.\n"
            "    \"zPIV ID\": \"xxx\",   (string) Pubcoin in hex format.\n"
            "    \"denomination\": n,   (numeric) Coin denomination.\n"
            "    \"mint height\": n     (numeric) Height of the block containing this mint.\n"
            "    \"confirmations\": n   (numeric) Number of confirmations.\n"
            "    \"hash stake\": \"xxx\",   (string) Mint serialstake hash in hex format.\n"
            "  }\n"
            "  ,..."
            "]\n"

            "\nExamples:\n" +
            HelpExampleCli("listmintedzerocoins", "") + HelpExampleRpc("listmintedzerocoins", "") +
            HelpExampleCli("listmintedzerocoins", "true") + HelpExampleRpc("listmintedzerocoins", "true") +
            HelpExampleCli("listmintedzerocoins", "true true") + HelpExampleRpc("listmintedzerocoins", "true, true"));

    bool fVerbose = (request.params.size() > 0) ? request.params[0].get_bool() : false;
    bool fMatureOnly = (request.params.size() > 1) ? request.params[1].get_bool() : false;

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked(true);

    CWalletDB walletdb(pwalletMain->strWalletFile);
    std::set<CMintMeta> setMints = pwalletMain->zpivTracker->ListMints(true, fMatureOnly, true);

    int nBestHeight = chainActive.Height();

    UniValue jsonList(UniValue::VARR);
    if (fVerbose) {
        for (auto m : setMints) {
            // Construct mint object
            UniValue objMint(UniValue::VOBJ);
            objMint.pushKV("serial hash", m.hashSerial.GetHex());  // Serial hash
            objMint.pushKV("version", m.nVersion);                 // Zerocoin version
            objMint.pushKV("zPIV ID", m.hashPubcoin.GetHex());     // PubCoin
            int denom = libzerocoin::ZerocoinDenominationToInt(m.denom);
            objMint.pushKV("denomination", denom);                 // Denomination
            objMint.pushKV("mint height", m.nHeight);              // Mint Height
            int nConfirmations = (m.nHeight && nBestHeight > m.nHeight) ? nBestHeight - m.nHeight : 0;
            objMint.pushKV("confirmations", nConfirmations);       // Confirmations
            if (m.hashStake.IsNull()) {
                CZerocoinMint mint;
                if (pwalletMain->GetMint(m.hashSerial, mint)) {
                    uint256 hashStake = mint.GetSerialNumber().getuint256();
                    hashStake = Hash(hashStake.begin(), hashStake.end());
                    m.hashStake = hashStake;
                    pwalletMain->zpivTracker->UpdateState(m);
                }
            }
            objMint.pushKV("hash stake", m.hashStake.GetHex());    // hashStake
            // Push back mint object
            jsonList.push_back(objMint);
        }
    } else {
        for (const CMintMeta& m : setMints)
            // Push back PubCoin
            jsonList.push_back(m.hashPubcoin.GetHex());
    }
    return jsonList;
}

UniValue listzerocoinamounts(const JSONRPCRequest& request)
{

    if (request.fHelp || request.params.size() != 0)
        throw std::runtime_error(
            "listzerocoinamounts\n"
            "\nGet information about your zerocoin amounts.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nResult:\n"
            "[\n"
            "  {\n"
            "    \"denomination\": n,   (numeric) Denomination Value.\n"
            "    \"mints\": n           (numeric) Number of mints.\n"
            "  }\n"
            "  ,..."
            "]\n"

            "\nExamples:\n" +
            HelpExampleCli("listzerocoinamounts", "") + HelpExampleRpc("listzerocoinamounts", ""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked(true);

    CWalletDB walletdb(pwalletMain->strWalletFile);
    std::set<CMintMeta> setMints = pwalletMain->zpivTracker->ListMints(true, true, true);

    std::map<libzerocoin::CoinDenomination, CAmount> spread;
    for (const auto& denom : libzerocoin::zerocoinDenomList)
        spread.emplace(denom, 0);
    for (auto& meta : setMints) spread.at(meta.denom)++;

    UniValue ret(UniValue::VARR);
    for (const auto& m : libzerocoin::zerocoinDenomList) {
        UniValue val(UniValue::VOBJ);
        val.pushKV("denomination", libzerocoin::ZerocoinDenominationToInt(m));
        val.pushKV("mints", (int64_t)spread.at(m));
        ret.push_back(val);
    }
    return ret;
}

UniValue listspentzerocoins(const JSONRPCRequest& request)
{

    if (request.fHelp || request.params.size() != 0)
        throw std::runtime_error(
            "listspentzerocoins\n"
            "\nList all the spent zPIV mints in the wallet.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nResult:\n"
            "[\n"
            "  \"xxx\"      (string) Pubcoin in hex format.\n"
            "  ,...\n"
            "]\n"

            "\nExamples:\n" +
            HelpExampleCli("listspentzerocoins", "") + HelpExampleRpc("listspentzerocoins", ""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked(true);

    CWalletDB walletdb(pwalletMain->strWalletFile);
    std::list<CBigNum> listPubCoin = walletdb.ListSpentCoinsSerial();

    UniValue jsonList(UniValue::VARR);
    for (const CBigNum& pubCoinItem : listPubCoin) {
        jsonList.push_back(pubCoinItem.GetHex());
    }

    return jsonList;
}

UniValue mintzerocoin(const JSONRPCRequest& request)
{
    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
        throw std::runtime_error(
            "mintzerocoin amount ( utxos )\n"
            "\nMint the specified zPIV amount\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. amount      (numeric, required) Enter an amount of Piv to convert to zPIV\n"
            "2. utxos       (string, optional) A json array of objects.\n"
            "                   Each object needs the txid (string) and vout (numeric)\n"
            "  [\n"
            "    {\n"
            "      \"txid\":\"txid\",    (string) The transaction id\n"
            "      \"vout\": n         (numeric) The output number\n"
            "    }\n"
            "    ,...\n"
            "  ]\n"

            "\nResult:\n"
            "{\n"
            "   \"txid\": \"xxx\",       (string) Transaction ID.\n"
            "   \"time\": nnn            (numeric) Time to mint this transaction.\n"
            "   \"mints\":\n"
            "   [\n"
            "      {\n"
            "         \"denomination\": nnn,     (numeric) Minted denomination.\n"
            "         \"pubcoin\": \"xxx\",      (string) Pubcoin in hex format.\n"
            "         \"randomness\": \"xxx\",   (string) Hex encoded randomness.\n"
            "         \"serial\": \"xxx\",       (string) Serial in hex format.\n"
            "      },\n"
            "      ...\n"
            "   ]\n"
            "}\n"

            "\nExamples:\n"
            "\nMint 50 from anywhere\n" +
            HelpExampleCli("mintzerocoin", "50") +
            "\nMint 13 from a specific output\n" +
            HelpExampleCli("mintzerocoin", "13 \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
            "\nAs a json rpc call\n" +
            HelpExampleRpc("mintzerocoin", "13, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\""));

    if (!Params().IsRegTestNet())
        throw JSONRPCError(RPC_WALLET_ERROR, "zPIV minting is DISABLED");

    LOCK2(cs_main, pwalletMain->cs_wallet);

    if (request.params.size() == 1)
    {
        RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
    } else
    {
        RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)(UniValue::VARR));
    }

    int64_t nTime = GetTimeMillis();
    if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
        throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance.");

    EnsureWalletIsUnlocked(true);

    CAmount nAmount = request.params[0].get_int() * COIN;

    CWalletTx wtx;
    std::vector<CDeterministicMint> vDMints;
    std::string strError;
    std::vector<COutPoint> vOutpts;

    if (request.params.size() == 2)
    {
        UniValue outputs = request.params[1].get_array();
        for (unsigned int idx = 0; idx < outputs.size(); idx++) {
            const UniValue& output = outputs[idx];
            if (!output.isObject())
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
            const UniValue& o = output.get_obj();

            RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));

            std::string txid = find_value(o, "txid").get_str();
            if (!IsHex(txid))
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");

            int nOutput = find_value(o, "vout").get_int();
            if (nOutput < 0)
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");

            COutPoint outpt(uint256S(txid), nOutput);
            vOutpts.push_back(outpt);
        }
        strError = pwalletMain->MintZerocoinFromOutPoint(nAmount, wtx, vDMints, vOutpts);
    } else
    {
        strError = pwalletMain->MintZerocoin(nAmount, wtx, vDMints);
    }

    if (strError != "")
        throw JSONRPCError(RPC_WALLET_ERROR, strError);

    UniValue retObj(UniValue::VOBJ);
    retObj.pushKV("txid", wtx.GetHash().ToString());
    retObj.pushKV("time", GetTimeMillis() - nTime);
    UniValue arrMints(UniValue::VARR);
    for (CDeterministicMint dMint : vDMints) {
        UniValue m(UniValue::VOBJ);
        m.pushKV("denomination", ValueFromAmount(libzerocoin::ZerocoinDenominationToAmount(dMint.GetDenomination())));
        m.pushKV("pubcoinhash", dMint.GetPubcoinHash().GetHex());
        m.pushKV("serialhash", dMint.GetSerialHash().GetHex());
        m.pushKV("seedhash", dMint.GetSeedHash().GetHex());
        m.pushKV("count", (int64_t)dMint.GetCount());
        arrMints.push_back(m);
    }
    retObj.pushKV("mints", arrMints);

    return retObj;
}

UniValue DoZpivSpend(const CAmount nAmount, std::vector<CZerocoinMint>& vMintsSelected, std::string address_str)
{
    int64_t nTimeStart = GetTimeMillis();
    CTxDestination address{CNoDestination()}; // Optional sending address. Dummy initialization here.
    CWalletTx wtx;
    CZerocoinSpendReceipt receipt;
    bool fSuccess;

    std::list<std::pair<CTxDestination, CAmount>> outputs;
    if(address_str != "") { // Spend to supplied destination address
        bool isStaking = false;
        address = DecodeDestination(address_str, isStaking);
        if(!IsValidDestination(address) || isStaking)
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
        outputs.emplace_back(address, nAmount);
    }

    EnsureWalletIsUnlocked();
    fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, outputs, nullptr);

    if (!fSuccess)
        throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage());

    CAmount nValueIn = 0;
    UniValue arrSpends(UniValue::VARR);
    for (CZerocoinSpend spend : receipt.GetSpends()) {
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("denomination", spend.GetDenomination());
        obj.pushKV("pubcoin", spend.GetPubCoin().GetHex());
        obj.pushKV("serial", spend.GetSerial().GetHex());
        uint32_t nChecksum = spend.GetAccumulatorChecksum();
        obj.pushKV("acc_checksum", HexStr(BEGIN(nChecksum), END(nChecksum)));
        arrSpends.push_back(obj);
        nValueIn += libzerocoin::ZerocoinDenominationToAmount(spend.GetDenomination());
    }

    CAmount nValueOut = 0;
    UniValue vout(UniValue::VARR);
    for (unsigned int i = 0; i < wtx.vout.size(); i++) {
        const CTxOut& txout = wtx.vout[i];
        UniValue out(UniValue::VOBJ);
        out.pushKV("value", ValueFromAmount(txout.nValue));
        nValueOut += txout.nValue;

        CTxDestination dest;
        if(txout.IsZerocoinMint())
            out.pushKV("address", "zerocoinmint");
        else if(ExtractDestination(txout.scriptPubKey, dest))
            out.pushKV("address", EncodeDestination(dest));
        vout.push_back(out);
    }

    //construct JSON to return
    UniValue ret(UniValue::VOBJ);
    ret.pushKV("txid", wtx.GetHash().ToString());
    ret.pushKV("bytes", (int64_t)wtx.GetTotalSize());
    ret.pushKV("fee", ValueFromAmount(nValueIn - nValueOut));
    ret.pushKV("duration_millis", (GetTimeMillis() - nTimeStart));
    ret.pushKV("spends", arrSpends);
    ret.pushKV("outputs", vout);

    return ret;
}

UniValue spendzerocoin(const JSONRPCRequest& request)
{
    if (request.fHelp || request.params.size() > 2 || request.params.size() < 1)
        throw std::runtime_error(
            "spendzerocoin amount ( \"address\" )\n"
            "\nSpend zPIV to a PIV address.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. amount          (numeric, required) Amount to spend.\n"
            "2. \"address\"     (string, optional, default=change) Send to specified address or to a new change address.\n"
            "                       If there is change then an address is required\n"

            "\nResult:\n"
            "{\n"
            "  \"txid\": \"xxx\",             (string) Transaction hash.\n"
            "  \"bytes\": nnn,              (numeric) Transaction size.\n"
            "  \"fee\": amount,             (numeric) Transaction fee (if any).\n"
            "  \"spends\": [                (array) JSON array of input objects.\n"
            "    {\n"
            "      \"denomination\": nnn,   (numeric) Denomination value.\n"
            "      \"pubcoin\": \"xxx\",      (string) Pubcoin in hex format.\n"
            "      \"serial\": \"xxx\",       (string) Serial number in hex format.\n"
            "      \"acc_checksum\": \"xxx\", (string) Accumulator checksum in hex format.\n"
            "    }\n"
            "    ,...\n"
            "  ],\n"
            "  \"outputs\": [                 (array) JSON array of output objects.\n"
            "    {\n"
            "      \"value\": amount,         (numeric) Value in PIV.\n"
            "      \"address\": \"xxx\"         (string) PIV address or \"zerocoinmint\" for reminted change.\n"
            "    }\n"
            "    ,...\n"
            "  ]\n"
            "}\n"

            "\nExamples\n" +
            HelpExampleCli("spendzerocoin", "5000 \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\"") +
            HelpExampleRpc("spendzerocoin", "5000 \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
        throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance.");

    CAmount nAmount = AmountFromValue(request.params[0]);        // Spending amount
    const std::string address_str = (request.params.size() > 1 ? request.params[1].get_str() : "");

    std::vector<CZerocoinMint> vMintsSelected;
    return DoZpivSpend(nAmount, vMintsSelected, address_str);
}

UniValue spendzerocoinmints(const JSONRPCRequest& request)
{
    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
        throw std::runtime_error(
            "spendzerocoinmints mints_list ( \"address\" ) \n"
            "\nSpend zPIV mints to a PIV address.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. mints_list     (string, required) A json array of zerocoin mints serial hashes\n"
            "2. \"address\"     (string, optional, default=change) Send to specified address or to a new change address.\n"

            "\nResult:\n"
            "{\n"
            "  \"txid\": \"xxx\",             (string) Transaction hash.\n"
            "  \"bytes\": nnn,              (numeric) Transaction size.\n"
            "  \"fee\": amount,             (numeric) Transaction fee (if any).\n"
            "  \"spends\": [                (array) JSON array of input objects.\n"
            "    {\n"
            "      \"denomination\": nnn,   (numeric) Denomination value.\n"
            "      \"pubcoin\": \"xxx\",      (string) Pubcoin in hex format.\n"
            "      \"serial\": \"xxx\",       (string) Serial number in hex format.\n"
            "      \"acc_checksum\": \"xxx\", (string) Accumulator checksum in hex format.\n"
            "    }\n"
            "    ,...\n"
            "  ],\n"
            "  \"outputs\": [                 (array) JSON array of output objects.\n"
            "    {\n"
            "      \"value\": amount,         (numeric) Value in PIV.\n"
            "      \"address\": \"xxx\"         (string) PIV address or \"zerocoinmint\" for reminted change.\n"
            "    }\n"
            "    ,...\n"
            "  ]\n"
            "}\n"

            "\nExamples\n" +
            HelpExampleCli("spendzerocoinmints", "'[\"0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f\", \"dfe585659e265e6a509d93effb906d3d2a0ac2fe3464b2c3b6d71a3ef34c8ad7\"]' \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\"") +
            HelpExampleRpc("spendzerocoinmints", "[\"0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f\", \"dfe585659e265e6a509d93effb906d3d2a0ac2fe3464b2c3b6d71a3ef34c8ad7\"], \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
        throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance.");

    UniValue arrMints = request.params[0].get_array();
    const std::string address_str = (request.params.size() > 1 ? request.params[1].get_str() : "");

    if (arrMints.size() == 0)
        throw JSONRPCError(RPC_WALLET_ERROR, "No zerocoin selected");

    // check mints supplied and save serial hash (do this here so we don't fetch if any is wrong)
    std::vector<uint256> vSerialHashes;
    for(unsigned int i = 0; i < arrMints.size(); i++) {
        std::string serialHashStr = arrMints[i].get_str();
        if (!IsHex(serialHashStr))
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex serial hash");
        vSerialHashes.push_back(uint256S(serialHashStr));
    }

    // fetch mints and update nAmount
    CAmount nAmount(0);
    std::vector<CZerocoinMint> vMintsSelected;
    for(const uint256& serialHash : vSerialHashes) {
        CZerocoinMint mint;
        if (!pwalletMain->GetMint(serialHash, mint)) {
            std::string strErr = "Failed to fetch mint associated with serial hash " + serialHash.GetHex();
            throw JSONRPCError(RPC_WALLET_ERROR, strErr);
        }
        vMintsSelected.emplace_back(mint);
        nAmount += mint.GetDenominationAsAmount();
    }

    return DoZpivSpend(nAmount, vMintsSelected, address_str);
}

UniValue resetmintzerocoin(const JSONRPCRequest& request)
{
    if (request.fHelp || request.params.size() > 1)
        throw std::runtime_error(
            "resetmintzerocoin ( fullscan )\n"
            "\nScan the blockchain for all of the zerocoins that are held in the wallet database.\n"
            "Update any meta-data that is incorrect. Archive any mints that are not able to be found.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. fullscan          (boolean, optional) Rescan each block of the blockchain.\n"
            "                               WARNING - may take 30+ minutes!\n"

            "\nResult:\n"
            "{\n"
            "  \"updated\": [       (array) JSON array of updated mints.\n"
            "    \"xxx\"            (string) Hex encoded mint.\n"
            "    ,...\n"
            "  ],\n"
            "  \"archived\": [      (array) JSON array of archived mints.\n"
            "    \"xxx\"            (string) Hex encoded mint.\n"
            "    ,...\n"
            "  ]\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("resetmintzerocoin", "true") + HelpExampleRpc("resetmintzerocoin", "true"));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    CWalletDB walletdb(pwalletMain->strWalletFile);
    CzPIVTracker* zpivTracker = pwalletMain->zpivTracker.get();
    std::set<CMintMeta> setMints = zpivTracker->ListMints(false, false, true);
    std::vector<CMintMeta> vMintsToFind(setMints.begin(), setMints.end());
    std::vector<CMintMeta> vMintsMissing;
    std::vector<CMintMeta> vMintsToUpdate;

    // search all of our available data for these mints
    FindMints(vMintsToFind, vMintsToUpdate, vMintsMissing);

    // update the meta data of mints that were marked for updating
    UniValue arrUpdated(UniValue::VARR);
    for (CMintMeta meta : vMintsToUpdate) {
        zpivTracker->UpdateState(meta);
        arrUpdated.push_back(meta.hashPubcoin.GetHex());
    }

    // delete any mints that were unable to be located on the blockchain
    UniValue arrDeleted(UniValue::VARR);
    for (CMintMeta mint : vMintsMissing) {
        zpivTracker->Archive(mint);
        arrDeleted.push_back(mint.hashPubcoin.GetHex());
    }

    UniValue obj(UniValue::VOBJ);
    obj.pushKV("updated", arrUpdated);
    obj.pushKV("archived", arrDeleted);
    return obj;
}

UniValue resetspentzerocoin(const JSONRPCRequest& request)
{
    if (request.fHelp || request.params.size() != 0)
        throw std::runtime_error(
            "resetspentzerocoin\n"
            "\nScan the blockchain for all of the zerocoins that are held in the wallet database.\n"
            "Reset mints that are considered spent that did not make it into the blockchain.\n"

            "\nResult:\n"
            "{\n"
            "  \"restored\": [        (array) JSON array of restored objects.\n"
            "    {\n"
            "      \"serial\": \"xxx\"  (string) Serial in hex format.\n"
            "    }\n"
            "    ,...\n"
            "  ]\n"
            "}\n"

            "\nExamples:\n" +
            HelpExampleCli("resetspentzerocoin", "") + HelpExampleRpc("resetspentzerocoin", ""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    CWalletDB walletdb(pwalletMain->strWalletFile);
    CzPIVTracker* zpivTracker = pwalletMain->zpivTracker.get();
    std::set<CMintMeta> setMints = zpivTracker->ListMints(false, false, false);
    std::list<CZerocoinSpend> listSpends = walletdb.ListSpentCoins();
    std::list<CZerocoinSpend> listUnconfirmedSpends;

    for (CZerocoinSpend spend : listSpends) {
        CTransaction tx;
        uint256 hashBlock = UINT256_ZERO;
        if (!GetTransaction(spend.GetTxHash(), tx, hashBlock)) {
            listUnconfirmedSpends.push_back(spend);
            continue;
        }

        //no confirmations
        if (hashBlock.IsNull())
            listUnconfirmedSpends.push_back(spend);
    }

    UniValue objRet(UniValue::VOBJ);
    UniValue arrRestored(UniValue::VARR);
    for (CZerocoinSpend spend : listUnconfirmedSpends) {
        for (auto& meta : setMints) {
            if (meta.hashSerial == GetSerialHash(spend.GetSerial())) {
                zpivTracker->SetPubcoinNotUsed(meta.hashPubcoin);
                walletdb.EraseZerocoinSpendSerialEntry(spend.GetSerial());
                RemoveSerialFromDB(spend.GetSerial());
                UniValue obj(UniValue::VOBJ);
                obj.pushKV("serial", spend.GetSerial().GetHex());
                arrRestored.push_back(obj);
                continue;
            }
        }
    }

    objRet.pushKV("restored", arrRestored);
    return objRet;
}

UniValue getarchivedzerocoin(const JSONRPCRequest& request)
{
    if(request.fHelp || request.params.size() != 0)
        throw std::runtime_error(
            "getarchivedzerocoin\n"
            "\nDisplay zerocoins that were archived because they were believed to be orphans.\n"
            "Provides enough information to recover mint if it was incorrectly archived.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nResult:\n"
            "[\n"
            "  {\n"
            "    \"txid\": \"xxx\",           (string) Transaction ID for archived mint.\n"
            "    \"denomination\": amount,  (numeric) Denomination value.\n"
            "    \"serial\": \"xxx\",         (string) Serial number in hex format.\n"
            "    \"randomness\": \"xxx\",     (string) Hex encoded randomness.\n"
            "    \"pubcoin\": \"xxx\"         (string) Pubcoin in hex format.\n"
            "  }\n"
            "  ,...\n"
            "]\n"

            "\nExamples:\n" +
            HelpExampleCli("getarchivedzerocoin", "") + HelpExampleRpc("getarchivedzerocoin", ""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked();

    CWalletDB walletdb(pwalletMain->strWalletFile);
    std::list<CZerocoinMint> listMints = walletdb.ListArchivedZerocoins();
    std::list<CDeterministicMint> listDMints = walletdb.ListArchivedDeterministicMints();

    UniValue arrRet(UniValue::VARR);
    for (const CZerocoinMint& mint : listMints) {
        UniValue objMint(UniValue::VOBJ);
        objMint.pushKV("txid", mint.GetTxHash().GetHex());
        objMint.pushKV("denomination", ValueFromAmount(mint.GetDenominationAsAmount()));
        objMint.pushKV("serial", mint.GetSerialNumber().GetHex());
        objMint.pushKV("randomness", mint.GetRandomness().GetHex());
        objMint.pushKV("pubcoin", mint.GetValue().GetHex());
        arrRet.push_back(objMint);
    }

    for (const CDeterministicMint& dMint : listDMints) {
        UniValue objDMint(UniValue::VOBJ);
        objDMint.pushKV("txid", dMint.GetTxHash().GetHex());
        objDMint.pushKV("denomination", ValueFromAmount(libzerocoin::ZerocoinDenominationToAmount(dMint.GetDenomination())));
        objDMint.pushKV("serialhash", dMint.GetSerialHash().GetHex());
        objDMint.pushKV("pubcoinhash", dMint.GetPubcoinHash().GetHex());
        objDMint.pushKV("seedhash", dMint.GetSeedHash().GetHex());
        objDMint.pushKV("count", (int64_t)dMint.GetCount());
        arrRet.push_back(objDMint);
    }

    return arrRet;
}

UniValue exportzerocoins(const JSONRPCRequest& request)
{
    if(request.fHelp || request.params.empty() || request.params.size() > 2)
        throw std::runtime_error(
            "exportzerocoins include_spent ( denomination )\n"
            "\nExports zerocoin mints that are held by the current wallet file\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. \"include_spent\"        (bool, required) Include mints that have already been spent\n"
            "2. \"denomination\"         (integer, optional) Export a specific denomination of zPIV\n"

            "\nResult:\n"
            "[                   (array of json object)\n"
            "  {\n"
            "    \"id\": \"serial hash\",  (string) the mint's zPIV serial hash \n"
            "    \"d\": n,         (numeric) the mint's zerocoin denomination \n"
            "    \"p\": \"pubcoin\", (string) The public coin\n"
            "    \"s\": \"serial\",  (string) The secret serial number\n"
            "    \"r\": \"random\",  (string) The secret random number\n"
            "    \"t\": \"txid\",    (string) The txid that the coin was minted in\n"
            "    \"h\": n,         (numeric) The height the tx was added to the blockchain\n"
            "    \"u\": used,      (boolean) Whether the mint has been spent\n"
            "    \"v\": version,   (numeric) The version of the zPIV\n"
            "    \"k\": \"privkey\"  (string) The zPIV private key (V2+ zPIV only)\n"
            "  }\n"
            "  ,...\n"
            "]\n"

            "\nExamples:\n" +
            HelpExampleCli("exportzerocoins", "false 5") + HelpExampleRpc("exportzerocoins", "false 5"));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked();

    CWalletDB walletdb(pwalletMain->strWalletFile);

    bool fIncludeSpent = request.params[0].get_bool();
    libzerocoin::CoinDenomination denomination = libzerocoin::ZQ_ERROR;
    if (request.params.size() == 2)
        denomination = libzerocoin::IntToZerocoinDenomination(request.params[1].get_int());

    CzPIVTracker* zpivTracker = pwalletMain->zpivTracker.get();
    std::set<CMintMeta> setMints = zpivTracker->ListMints(!fIncludeSpent, false, false);

    UniValue jsonList(UniValue::VARR);
    for (const CMintMeta& meta : setMints) {
        if (denomination != libzerocoin::ZQ_ERROR && denomination != meta.denom)
            continue;

        CZerocoinMint mint;
        if (!pwalletMain->GetMint(meta.hashSerial, mint))
            continue;

        UniValue objMint(UniValue::VOBJ);
        objMint.pushKV("id", meta.hashSerial.GetHex());
        objMint.pushKV("d", mint.GetDenomination());
        objMint.pushKV("p", mint.GetValue().GetHex());
        objMint.pushKV("s", mint.GetSerialNumber().GetHex());
        objMint.pushKV("r", mint.GetRandomness().GetHex());
        objMint.pushKV("t", mint.GetTxHash().GetHex());
        objMint.pushKV("h", mint.GetHeight());
        objMint.pushKV("u", mint.IsUsed());
        objMint.pushKV("v", mint.GetVersion());
        if (mint.GetVersion() >= 2) {
            CKey key;
            key.SetPrivKey(mint.GetPrivKey(), true);
            objMint.pushKV("k", EncodeSecret(key));
        }
        jsonList.push_back(objMint);
    }

    return jsonList;
}

UniValue importzerocoins(const JSONRPCRequest& request)
{
    if(request.fHelp || request.params.size() == 0)
        throw std::runtime_error(
            "importzerocoins importdata \n"
            "\n[{\"d\":denomination,\"p\":\"pubcoin_hex\",\"s\":\"serial_hex\",\"r\":\"randomness_hex\",\"t\":\"txid\",\"h\":height, \"u\":used},{\"d\":...}]\n"
            "\nImport zerocoin mints.\n"
            "Adds raw zerocoin mints to the wallet.\n"
            "Note it is recommended to use the json export created from the exportzerocoins RPC call\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. \"importdata\"    (string, required) A json array of json objects containing zerocoin mints\n"

            "\nResult:\n"
            "{\n"
            "  \"added\": n,        (numeric) The quantity of zerocoin mints that were added\n"
            "  \"value\": amount    (numeric) The total zPIV value of zerocoin mints that were added\n"
            "}\n"

            "\nExamples\n" +
            HelpExampleCli("importzerocoins", "\'[{\"d\":100,\"p\":\"mypubcoin\",\"s\":\"myserial\",\"r\":\"randomness_hex\",\"t\":\"mytxid\",\"h\":104923, \"u\":false},{\"d\":5,...}]\'") +
            HelpExampleRpc("importzerocoins", "[{\"d\":100,\"p\":\"mypubcoin\",\"s\":\"myserial\",\"r\":\"randomness_hex\",\"t\":\"mytxid\",\"h\":104923, \"u\":false},{\"d\":5,...}]"));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked();

    RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
    UniValue arrMints = request.params[0].get_array();
    CWalletDB walletdb(pwalletMain->strWalletFile);

    int count = 0;
    CAmount nValue = 0;
    for (unsigned int idx = 0; idx < arrMints.size(); idx++) {
        const UniValue &val = arrMints[idx];
        const UniValue &o = val.get_obj();

        const UniValue& vDenom = find_value(o, "d");
        if (!vDenom.isNum())
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing d key");
        int d = vDenom.get_int();
        if (d < 0)
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, d must be positive");

        libzerocoin::CoinDenomination denom = libzerocoin::IntToZerocoinDenomination(d);
        CBigNum bnValue = 0;
        bnValue.SetHex(find_value(o, "p").get_str());
        CBigNum bnSerial = 0;
        bnSerial.SetHex(find_value(o, "s").get_str());
        CBigNum bnRandom = 0;
        bnRandom.SetHex(find_value(o, "r").get_str());
        uint256 txid(uint256S(find_value(o, "t").get_str()));

        int nHeight = find_value(o, "h").get_int();
        if (nHeight < 0)
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, h must be positive");

        bool fUsed = find_value(o, "u").get_bool();

        //Assume coin is version 1 unless it has the version actually set
        uint8_t nVersion = 1;
        const UniValue& vVersion = find_value(o, "v");
        if (vVersion.isNum())
            nVersion = static_cast<uint8_t>(vVersion.get_int());

        //Set the privkey if applicable
        CPrivKey privkey;
        if (nVersion >= libzerocoin::PrivateCoin::PUBKEY_VERSION) {
            std::string strPrivkey = find_value(o, "k").get_str();
            CKey key = DecodeSecret(strPrivkey);
            if (!key.IsValid())
                return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "privkey is not valid");
            privkey = key.GetPrivKey();
        }

        CZerocoinMint mint(denom, bnValue, bnRandom, bnSerial, fUsed, nVersion, &privkey);
        mint.SetTxHash(txid);
        mint.SetHeight(nHeight);
        pwalletMain->zpivTracker->Add(mint, true);
        count++;
        nValue += libzerocoin::ZerocoinDenominationToAmount(denom);
    }

    UniValue ret(UniValue::VOBJ);
    ret.pushKV("added", count);
    ret.pushKV("value", ValueFromAmount(nValue));
    return ret;
}

UniValue reconsiderzerocoins(const JSONRPCRequest& request)
{
    if(request.fHelp || !request.params.empty())
        throw std::runtime_error(
            "reconsiderzerocoins\n"
            "\nCheck archived zPIV list to see if any mints were added to the blockchain.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nResult:\n"
            "[\n"
            "  {\n"
            "    \"txid\" : \"xxx\",           (string) the mint's zerocoin denomination \n"
            "    \"denomination\" : amount,  (numeric) the mint's zerocoin denomination\n"
            "    \"pubcoin\" : \"xxx\",        (string) The mint's public identifier\n"
            "    \"height\" : n              (numeric) The height the tx was added to the blockchain\n"
            "  }\n"
            "  ,...\n"
            "]\n"

            "\nExamples\n" +
            HelpExampleCli("reconsiderzerocoins", "") + HelpExampleRpc("reconsiderzerocoins", ""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked(true);

    std::list<CZerocoinMint> listMints;
    std::list<CDeterministicMint> listDMints;
    pwalletMain->ReconsiderZerocoins(listMints, listDMints);

    UniValue arrRet(UniValue::VARR);
    for (const CZerocoinMint& mint : listMints) {
        UniValue objMint(UniValue::VOBJ);
        objMint.pushKV("txid", mint.GetTxHash().GetHex());
        objMint.pushKV("denomination", ValueFromAmount(mint.GetDenominationAsAmount()));
        objMint.pushKV("pubcoin", mint.GetValue().GetHex());
        objMint.pushKV("height", mint.GetHeight());
        arrRet.push_back(objMint);
    }
    for (const CDeterministicMint& dMint : listDMints) {
        UniValue objMint(UniValue::VOBJ);
        objMint.pushKV("txid", dMint.GetTxHash().GetHex());
        objMint.pushKV("denomination", FormatMoney(libzerocoin::ZerocoinDenominationToAmount(dMint.GetDenomination())));
        objMint.pushKV("pubcoinhash", dMint.GetPubcoinHash().GetHex());
        objMint.pushKV("height", dMint.GetHeight());
        arrRet.push_back(objMint);
    }

    return arrRet;
}

UniValue setzpivseed(const JSONRPCRequest& request)
{
    if(request.fHelp || request.params.size() != 1)
        throw std::runtime_error(
            "setzpivseed \"seed\"\n"
            "\nSet the wallet's deterministic zpiv seed to a specific value.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments:\n"
            "1. \"seed\"        (string, required) The deterministic zpiv seed.\n"

            "\nResult\n"
            "\"success\" : b,  (boolean) Whether the seed was successfully set.\n"

            "\nExamples\n" +
            HelpExampleCli("setzpivseed", "63f793e7895dd30d99187b35fbfb314a5f91af0add9e0a4e5877036d1e392dd5") +
            HelpExampleRpc("setzpivseed", "63f793e7895dd30d99187b35fbfb314a5f91af0add9e0a4e5877036d1e392dd5"));

    EnsureWalletIsUnlocked();

    uint256 seed;
    seed.SetHex(request.params[0].get_str());

    CzPIVWallet* zwallet = pwalletMain->getZWallet();
    bool fSuccess = zwallet->SetMasterSeed(seed, true);
    if (fSuccess)
        zwallet->SyncWithChain();

    UniValue ret(UniValue::VOBJ);
    ret.pushKV("success", fSuccess);

    return ret;
}

UniValue getzpivseed(const JSONRPCRequest& request)
{
    if(request.fHelp || !request.params.empty())
        throw std::runtime_error(
            "getzpivseed\n"
            "\nCheck archived zPIV list to see if any mints were added to the blockchain.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nResult\n"
            "\"seed\" : s,  (string) The deterministic zPIV seed.\n"

            "\nExamples\n" +
            HelpExampleCli("getzpivseed", "") + HelpExampleRpc("getzpivseed", ""));

    EnsureWalletIsUnlocked();

    CzPIVWallet* zwallet = pwalletMain->getZWallet();
    uint256 seed = zwallet->GetMasterSeed();

    UniValue ret(UniValue::VOBJ);
    ret.pushKV("seed", seed.GetHex());

    return ret;
}

UniValue generatemintlist(const JSONRPCRequest& request)
{
    if(request.fHelp || request.params.size() != 2)
        throw std::runtime_error(
            "generatemintlist\n"
            "\nShow mints that are derived from the deterministic zPIV seed.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments\n"
            "1. \"count\"  : n,  (numeric) Which sequential zPIV to start with.\n"
            "2. \"range\"  : n,  (numeric) How many zPIV to generate.\n"

            "\nResult:\n"
            "[\n"
            "  {\n"
            "    \"count\": n,          (numeric) Deterministic Count.\n"
            "    \"value\": \"xxx\",    (string) Hex encoded pubcoin value.\n"
            "    \"randomness\": \"xxx\",   (string) Hex encoded randomness.\n"
            "    \"serial\": \"xxx\"        (string) Hex encoded Serial.\n"
            "  }\n"
            "  ,...\n"
            "]\n"

            "\nExamples\n" +
            HelpExampleCli("generatemintlist", "1, 100") + HelpExampleRpc("generatemintlist", "1, 100"));

    EnsureWalletIsUnlocked();

    int nCount = request.params[0].get_int();
    int nRange = request.params[1].get_int();
    CzPIVWallet* zwallet = pwalletMain->getZWallet();

    UniValue arrRet(UniValue::VARR);
    for (int i = nCount; i < nCount + nRange; i++) {
        libzerocoin::CoinDenomination denom = libzerocoin::ZQ_ONE;
        libzerocoin::PrivateCoin coin(Params().GetConsensus().Zerocoin_Params(false), denom, false);
        CDeterministicMint dMint;
        zwallet->GenerateMint(i, denom, coin, dMint);
        UniValue obj(UniValue::VOBJ);
        obj.pushKV("count", i);
        obj.pushKV("value", coin.getPublicCoin().getValue().GetHex());
        obj.pushKV("randomness", coin.getRandomness().GetHex());
        obj.pushKV("serial", coin.getSerialNumber().GetHex());
        arrRet.push_back(obj);
    }

    return arrRet;
}

UniValue dzpivstate(const JSONRPCRequest& request) {
    if (request.fHelp || request.params.size() != 0)
        throw std::runtime_error(
                "dzpivstate\n"
                        "\nThe current state of the mintpool of the deterministic zPIV wallet.\n" +
                HelpRequiringPassphrase() + "\n"

                        "\nExamples\n" +
                HelpExampleCli("mintpoolstatus", "") + HelpExampleRpc("mintpoolstatus", ""));

    CzPIVWallet* zwallet = pwalletMain->getZWallet();
    UniValue obj(UniValue::VOBJ);
    int nCount, nCountLastUsed;
    zwallet->GetState(nCount, nCountLastUsed);
    obj.pushKV("dzpiv_count", nCount);
    obj.pushKV("mintpool_count", nCountLastUsed);

    return obj;
}

void static SearchThread(CzPIVWallet* zwallet, int nCountStart, int nCountEnd)
{
    LogPrintf("%s: start=%d end=%d\n", __func__, nCountStart, nCountEnd);
    CWalletDB walletDB(pwalletMain->strWalletFile);
    try {
        uint256 seedMaster = zwallet->GetMasterSeed();
        uint256 hashSeed = Hash(seedMaster.begin(), seedMaster.end());
        for(int i = nCountStart; i < nCountEnd; i++) {
            boost::this_thread::interruption_point();
            CDataStream ss(SER_GETHASH, 0);
            ss << seedMaster << i;
            uint512 zerocoinSeed = Hash512(ss.begin(), ss.end());

            CBigNum bnValue;
            CBigNum bnSerial;
            CBigNum bnRandomness;
            CKey key;
            zwallet->SeedToZPIV(zerocoinSeed, bnValue, bnSerial, bnRandomness, key);

            uint256 hashPubcoin = GetPubCoinHash(bnValue);
            zwallet->AddToMintPool(std::make_pair(hashPubcoin, i), true);
            walletDB.WriteMintPoolPair(hashSeed, hashPubcoin, i);
        }
    } catch (const std::exception& e) {
        LogPrintf("SearchThread() exception");
    } catch (...) {
        LogPrintf("SearchThread() exception");
    }
}

UniValue searchdzpiv(const JSONRPCRequest& request)
{
    if(request.fHelp || request.params.size() != 3)
        throw std::runtime_error(
            "searchdzpiv\n"
            "\nMake an extended search for deterministically generated zPIV that have not yet been recognized by the wallet.\n" +
            HelpRequiringPassphrase() + "\n"

            "\nArguments\n"
            "1. \"count\"       (numeric) Which sequential zPIV to start with.\n"
            "2. \"range\"       (numeric) How many zPIV to generate.\n"
            "3. \"threads\"     (numeric) How many threads should this operation consume.\n"

            "\nExamples\n" +
            HelpExampleCli("searchdzpiv", "1, 100, 2") + HelpExampleRpc("searchdzpiv", "1, 100, 2"));

    EnsureWalletIsUnlocked();

    int nCount = request.params[0].get_int();
    if (nCount < 0)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Count cannot be less than 0");

    int nRange = request.params[1].get_int();
    if (nRange < 1)
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Range has to be at least 1");

    int nThreads = request.params[2].get_int();

    CzPIVWallet* zwallet = pwalletMain->getZWallet();

    boost::thread_group* dzpivThreads = new boost::thread_group();
    int nRangePerThread = nRange / nThreads;

    int nPrevThreadEnd = nCount - 1;
    for (int i = 0; i < nThreads; i++) {
        int nStart = nPrevThreadEnd + 1;;
        int nEnd = nStart + nRangePerThread;
        nPrevThreadEnd = nEnd;
        dzpivThreads->create_thread(boost::bind(&SearchThread, zwallet, nStart, nEnd));
    }

    dzpivThreads->join_all();

    zwallet->RemoveMintsFromPool(pwalletMain->zpivTracker->GetSerialHashes());
    zwallet->SyncWithChain(false);

    //todo: better response
    return "done";
}

UniValue spendrawzerocoin(const JSONRPCRequest& request)
{
    if (request.fHelp || request.params.size() < 4 || request.params.size() > 6)
        throw std::runtime_error(
            "spendrawzerocoin \"serialHex\" denom \"randomnessHex\" \"priv key\" ( \"address\" \"mintTxId\" )\n"
            "\nCreate and broadcast a TX spending the provided zericoin.\n"

            "\nArguments:\n"
            "1. \"serialHex\"        (string, required) A zerocoin serial number (hex)\n"
            "2. \"randomnessHex\"    (string, required) A zerocoin randomness value (hex)\n"
            "3. denom                (numeric, required) A zerocoin denomination (decimal)\n"
            "4. \"priv key\"         (string, required) The private key associated with this coin (hex)\n"
            "5. \"address\"          (string, optional) PIVX address to spend to. If not specified, "
            "                        or empty string, spend to change address.\n"
            "6. \"mintTxId\"         (string, optional) txid of the transaction containing the mint. If not"
            "                        specified, or empty string, the blockchain will be scanned (could take a while)"

            "\nResult:\n"
                "\"txid\"             (string) The transaction txid in hex\n"

            "\nExamples\n" +
            HelpExampleCli("spendrawzerocoin", "\"f80892e78c30a393ef4ab4d5a9d5a2989de6ebc7b976b241948c7f489ad716a2\" \"a4fd4d7248e6a51f1d877ddd2a4965996154acc6b8de5aa6c83d4775b283b600\" 100 \"xxx\"") +
            HelpExampleRpc("spendrawzerocoin", "\"f80892e78c30a393ef4ab4d5a9d5a2989de6ebc7b976b241948c7f489ad716a2\", \"a4fd4d7248e6a51f1d877ddd2a4965996154acc6b8de5aa6c83d4775b283b600\", 100, \"xxx\""));

    LOCK2(cs_main, pwalletMain->cs_wallet);

    if (sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
            throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance.");

    const Consensus::Params& consensus = Params().GetConsensus();

    CBigNum serial;
    serial.SetHex(request.params[0].get_str());

    CBigNum randomness;
    randomness.SetHex(request.params[1].get_str());

    const int denom_int = request.params[2].get_int();
    libzerocoin::CoinDenomination denom = libzerocoin::IntToZerocoinDenomination(denom_int);

    std::string priv_key_str = request.params[3].get_str();
    CPrivKey privkey;
    CKey key = DecodeSecret(priv_key_str);
    if (!key.IsValid())
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "privkey is not valid");
    privkey = key.GetPrivKey();

    // Create the coin associated with these secrets
    libzerocoin::PrivateCoin coin(consensus.Zerocoin_Params(false), denom, serial, randomness);
    coin.setPrivKey(privkey);
    coin.setVersion(libzerocoin::PrivateCoin::CURRENT_VERSION);

    // Create the mint associated with this coin
    CZerocoinMint mint(denom, coin.getPublicCoin().getValue(), randomness, serial, false, CZerocoinMint::CURRENT_VERSION, &privkey);

    std::string address_str = "";
    if (request.params.size() > 4)
        address_str = request.params[4].get_str();

    if (request.params.size() > 5) {
        // update mint txid
        mint.SetTxHash(ParseHashV(request.params[5], "parameter 5"));
    } else {
        // If the mint tx is not provided, look for it
        const CBigNum& mintValue = mint.GetValue();
        bool found = false;
        {
            CBlockIndex* pindex = chainActive.Tip();
            while (!found && pindex && consensus.NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_ZC)) {
                LogPrintf("%s : Checking block %d...\n", __func__, pindex->nHeight);
                CBlock block;
                if (!ReadBlockFromDisk(block, pindex))
                    throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read block from disk");
                std::list<CZerocoinMint> listMints;
                BlockToZerocoinMintList(block, listMints, true);
                for (const CZerocoinMint& m : listMints) {
                    if (m.GetValue() == mintValue && m.GetDenomination() == denom) {
                        // mint found. update txid
                        mint.SetTxHash(m.GetTxHash());
                        found = true;
                        break;
                    }
                }
                pindex = pindex->pprev;
            }
        }
        if (!found)
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Mint tx not found");
    }

    std::vector<CZerocoinMint> vMintsSelected = {mint};
    return DoZpivSpend(mint.GetDenominationAsAmount(), vMintsSelected, address_str);
}

static const CRPCCommand commands[] =
{ //  category              name                        actor (function)           okSafeMode
  //  --------------------- ------------------------    -----------------------    ----------
    { "zerocoin",           "getzerocoinbalance",       &getzerocoinbalance,       false },
    { "zerocoin",           "listmintedzerocoins",      &listmintedzerocoins,      false },
    { "zerocoin",           "listspentzerocoins",       &listspentzerocoins,       false },
    { "zerocoin",           "listzerocoinamounts",      &listzerocoinamounts,      false },
    { "zerocoin",           "spendzerocoin",            &spendzerocoin,            false },
    { "zerocoin",           "spendrawzerocoin",         &spendrawzerocoin,         true  },
    { "zerocoin",           "spendzerocoinmints",       &spendzerocoinmints,       false },
    { "zerocoin",           "resetmintzerocoin",        &resetmintzerocoin,        false },
    { "zerocoin",           "resetspentzerocoin",       &resetspentzerocoin,       false },
    { "zerocoin",           "getarchivedzerocoin",      &getarchivedzerocoin,      false },
    { "zerocoin",           "importzerocoins",          &importzerocoins,          false },
    { "zerocoin",           "exportzerocoins",          &exportzerocoins,          false },
    { "zerocoin",           "reconsiderzerocoins",      &reconsiderzerocoins,      false },
    { "zerocoin",           "getzpivseed",              &getzpivseed,              false },
    { "zerocoin",           "setzpivseed",              &setzpivseed,              false },
    { "zerocoin",           "generatemintlist",         &generatemintlist,         false },
    { "zerocoin",           "searchdzpiv",              &searchdzpiv,              false },
    { "zerocoin",           "dzpivstate",               &dzpivstate,               false },

    /* Not shown in help */
    { "hidden",             "mintzerocoin",             &mintzerocoin,             false },
};

void RegisterZPIVRPCCommands(CRPCTable &tableRPC)
{
    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
        tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}

max_stars_repo_name: mohaxars/sciencecoin

max_issues_repo_name: mohaxars/sciencecoin

max_forks_repo_name: mohaxars/sciencecoin


text:
#include <boost/test/unit_test.hpp>

#include <smtrat-modules/SATModule/SATModule.h>
#include <smtrat-common/smtrat-common.h>

using namespace smtrat;

BOOST_AUTO_TEST_SUITE(Test_SATModule);

BOOST_AUTO_TEST_CASE(Test_Simple)
{

	//carl::Variable x = carl::freshRealVariable("x");
	//carl::Variable b = carl::freshBooleanVariable("b");
	//
	//FormulaT c1(x + Rational(1), carl::Relation::LESS);
	//FormulaT c2(x - Rational(1), carl::Relation::GREATER);
	//
	//FormulaT clause1(carl::FormulaType::OR, {FormulaT(b), c1});
	//FormulaT clause2(carl::FormulaType::OR, {FormulaT(carl::FormulaType::NOT, FormulaT(b)), c2});
	//
	//auto input = std::make_unique<ModuleInput>();
	//auto conditions = std::vector<std::atomic_bool*>(1, new std::atomic_bool(false));
	//SATModule<SATSettingsMCSAT> sat(input.get(), conditions);
	//
	//sat.addCore(input->add(clause1).first);
	//sat.addCore(input->add(clause2).first);
	//sat.checkCore();
}

BOOST_AUTO_TEST_SUITE_END();

ext: cpp

max_stars_repo_name: minemebarsha/smtrat

max_issues_repo_name: minemebarsha/smtrat

max_forks_repo_name: minemebarsha/smtrat


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_SELSUB_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_SELSUB_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>

#include <boost/simd/meta/hierarchy/simd.hpp>
#include <boost/simd/function/simd/if_else_zero.hpp>
#include <boost/simd/function/simd/unary_minus.hpp>
#include <boost/simd/function/simd/minus.hpp>
#include <boost/simd/function/simd/plus.hpp>

namespace boost { namespace simd { namespace ext
{
  namespace bd = boost::dispatch;
  namespace bs = boost::simd;

  BOOST_DISPATCH_OVERLOAD ( selsub_
                          , (typename A0, typename A1, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::fundamental_<A0>, X>
                          , bs::pack_<bd::unspecified_<A1>, X>
                          , bs::pack_<bd::unspecified_<A1>, X>
                          )
   {
     BOOST_FORCEINLINE A1 operator()(A0 const& a0, A1 const& a1, A1 const& a2) const
      {
       return a1 - if_else_zero(a0, a2);
      }
   };

   BOOST_DISPATCH_OVERLOAD( selsub_
                           , (typename A0, typename A1, typename X)
                           , bd::cpu_
                           , bs::pack_<bd::fundamental_<A0>, X>
                           , bs::pack_<bd::floating_<A1>, X>
                           , bs::pack_<bd::floating_<A1>, X>
                          )
   {
     BOOST_FORCEINLINE A1 operator()(A0 const& a0, A1 const& a1, A1 const& a2) const
      {
        // this is a workaround for a gcc (at least 4.6) over-optimization in case or a1 and a2 are
        // equal (constant?) and invalid (inf -inf or nan) in which case the general impl sometimes
        // return 0 in place of nan in float cases.
       return a1 + if_else_zero(a0, -a2);
      }
   };
} } }

#endif

ext: hpp


text:
//
// MIT License
//
// Copyright 2018-2019
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#define BOOST_TEST_MODULE cpu_test

#include <boost/test/unit_test.hpp>
#include <variant>

#include "decode.hh"
#include "disassemble.hh"

namespace jde = jones::decode;
namespace jdi = jones::disassemble;

namespace {

void check_instruction_invalid(const jde::instruction &instruction) {
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::INVALID);
  BOOST_CHECK(instruction.decoded_opcode.value == 0);

  BOOST_CHECK(instruction.decoded_operand.type == operand_type::INVALID);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0x00));
}

void check_instruction_no_operand(const jde::instruction &instruction) {
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::NONE);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0x00));
}

void check_disassemble(uint8_t *buffer, size_t length_in_bytes, const char *expected) {
  auto const instructions = jdi::disassemble(buffer, length_in_bytes);
  BOOST_CHECK(instructions.instructions.size() == 1);

  auto const &first_instruction = instructions.instructions[0];
  auto const disassembled = first_instruction.opcode + first_instruction.operand;
  BOOST_CHECK(disassembled == expected);
}

} // namespace

BOOST_AUTO_TEST_CASE(cpu_test) { BOOST_CHECK(true); }

//
// Test: Disassembles opcode 0x00.
//
BOOST_AUTO_TEST_CASE(disassemble_0x00_instruction_valid) {
  uint8_t binary_instruction[] = {0x00, 0x00};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "BRK #$00");
}

//
// Test: Disassembles opcode 0x01.
//
BOOST_AUTO_TEST_CASE(disassemble_0x01_instruction_valid) {
  uint8_t binary_instruction[] = {0x01, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA ($FF,X)");
}

//
// Test: Disassembles opcode 0x02.
//
BOOST_AUTO_TEST_CASE(disassemble_0x02_instruction_valid) {
  uint8_t binary_instruction[] = {0x02};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "STP");
}

//
// Test: Disassembles opcode 0x03.
//
BOOST_AUTO_TEST_CASE(disassemble_0x03_slo_instruction_valid) {
  uint8_t binary_instruction[] = {0x03, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO ($FF,X)");
}

//
// Test: Disassembles opcode 0x04.
//
BOOST_AUTO_TEST_CASE(disassemble_0x04_instruction_valid) {
  uint8_t binary_instruction[] = {0x04, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP $FF");
}

//
// Test: Disassembles opcode 0x05.
//
BOOST_AUTO_TEST_CASE(disassemble_0x05_instruction_valid) {
  uint8_t binary_instruction[] = {0x05, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA $FF");
}

//
// Test: Disassembles opcode 0x06.
//
BOOST_AUTO_TEST_CASE(disassemble_0x06_instruction_valid) {
  uint8_t binary_instruction[] = {0x06, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ASL $FF");
}

//
// Test: Disassembles opcode 0x07.
//
BOOST_AUTO_TEST_CASE(disassemble_0x07_instruction_valid) {
  uint8_t binary_instruction[] = {0x07, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO $FF");
}

//
// Test: Disassembles opcode 0x08.
//
BOOST_AUTO_TEST_CASE(disassemble_0x08_instruction_valid) {
  uint8_t binary_instruction[] = {0x08};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "PHP");
}

//
// Test: Disassembles opcode 0x09.
//
BOOST_AUTO_TEST_CASE(disassemble_0x09_instruction_valid) {
  uint8_t binary_instruction[] = {0x09, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA #$FF");
}

//
// Test: Disassembles opcode 0x0A.
//
BOOST_AUTO_TEST_CASE(disassemble_0x0A_instruction_valid) {
  uint8_t binary_instruction[] = {0x0A};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ASL A");
}

//
// Test: Disassembles opcode 0x0B.
//
BOOST_AUTO_TEST_CASE(disassemble_0x0B_instruction_valid) {
  uint8_t binary_instruction[] = {0x0B, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ANC #$FF");
}

//
// Test: Disassembles opcode 0x0C.
//
BOOST_AUTO_TEST_CASE(disassemble_0x0C_instruction_valid) {
  uint8_t binary_instruction[] = {0x0C, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP $EEFF");
}

//
// Test: Disassembles opcode 0x0D.
//
BOOST_AUTO_TEST_CASE(disassemble_0x0D_instruction_valid) {
  uint8_t binary_instruction[] = {0x0D, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA $EEFF");
}

//
// Test: Disassembles opcode 0x0E.
//
BOOST_AUTO_TEST_CASE(disassemble_0x0E_instruction_valid) {
  uint8_t binary_instruction[] = {0x0E, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ASL $EEFF");
}

//
// Test: Disassembles opcode 0x0F.
//
BOOST_AUTO_TEST_CASE(disassemble_0x0F_instruction_valid) {
  uint8_t binary_instruction[] = {0x0F, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO $EEFF");
}

//
// Test: Disassembles opcode 0x10.
//
BOOST_AUTO_TEST_CASE(disassemble_0x10_instruction_valid) {
  uint8_t binary_instruction[] = {0x10, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "BPL $FF");
}

//
// Test: Disassembles opcode 0x11.
//
BOOST_AUTO_TEST_CASE(disassemble_0x11_instruction_valid) {
  uint8_t binary_instruction[] = {0x11, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA ($FF),Y");
}

//
// Test: Disassembles opcode 0x12.
//
BOOST_AUTO_TEST_CASE(disassemble_0x12_instruction_valid) {
  uint8_t binary_instruction[] = {0x12};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "STP");
}

//
// Test: Disassembles opcode 0x13.
//
BOOST_AUTO_TEST_CASE(disassemble_0x13_instruction_valid) {
  uint8_t binary_instruction[] = {0x13, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO ($FF),Y");
}

//
// Test: Disassembles opcode 0x14.
//
BOOST_AUTO_TEST_CASE(disassemble_0x14_instruction_valid) {
  uint8_t binary_instruction[] = {0x14, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP $FF,X");
}

//
// Test: Disassembles opcode 0x15.
//
BOOST_AUTO_TEST_CASE(disassemble_0x15_instruction_valid) {
  uint8_t binary_instruction[] = {0x15, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA $FF,X");
}

//
// Test: Disassembles opcode 0x16.
//
BOOST_AUTO_TEST_CASE(disassemble_0x16_instruction_valid) {
  uint8_t binary_instruction[] = {0x16, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ASL $FF,X");
}

//
// Test: Disassembles opcode 0x17.
//
BOOST_AUTO_TEST_CASE(disassemble_0x17_instruction_valid) {
  uint8_t binary_instruction[] = {0x17, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO $FF,X");
}

//
// Test: Disassembles opcode 0x18.
//
BOOST_AUTO_TEST_CASE(disassemble_0x18_instruction_valid) {
  uint8_t binary_instruction[] = {0x18};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "CLC");
}

//
// Test: Disassembles opcode 0x19.
//
BOOST_AUTO_TEST_CASE(disassemble_0x19_instruction_valid) {
  uint8_t binary_instruction[] = {0x19, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA $EEFF,Y");
}

//
// Test: Disassembles opcode 0x1A.
//
BOOST_AUTO_TEST_CASE(disassemble_0x1A_instruction_valid) {
  uint8_t binary_instruction[] = {0x1A};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP");
}

//
// Test: Disassembles opcode 0x1B.
//
BOOST_AUTO_TEST_CASE(disassemble_0x1B_instruction_valid) {
  uint8_t binary_instruction[] = {0x1B, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO $EEFF,Y");
}

//
// Test: Disassembles opcode 0x1C.
//
BOOST_AUTO_TEST_CASE(disassemble_0x1C_instruction_valid) {
  uint8_t binary_instruction[] = {0x1C, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP $EEFF,X");
}

//
// Test: Disassembles opcode 0x1D.
//
BOOST_AUTO_TEST_CASE(disassemble_0x1D_instruction_valid) {
  uint8_t binary_instruction[] = {0x1D, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ORA $EEFF,X");
}

//
// Test: Disassembles opcode 0x1E.
//
BOOST_AUTO_TEST_CASE(disassemble_0x1E_instruction_valid) {
  uint8_t binary_instruction[] = {0x1E, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ASL $EEFF,X");
}

//
// Test: Disassembles opcode 0x1F.
//
BOOST_AUTO_TEST_CASE(disassemble_0x1F_instruction_valid) {
  uint8_t binary_instruction[] = {0x1F, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SLO $EEFF,X");
}

//
// Test: Disassembles opcode 0x20.
//
BOOST_AUTO_TEST_CASE(disassemble_0x20_instruction_valid) {
  uint8_t binary_instruction[] = {0x20, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "JSR $EEFF");
}

//
// Test: Disassembles opcode 0x21.
//
BOOST_AUTO_TEST_CASE(disassemble_0x21_instruction_valid) {
  uint8_t binary_instruction[] = {0x21, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND ($FF,X)");
}

//
// Test: Disassembles opcode 0x22.
//
BOOST_AUTO_TEST_CASE(disassemble_0x22_instruction_valid) {
  uint8_t binary_instruction[] = {0x22};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "STP");
}

//
// Test: Disassembles opcode 0x23.
//
BOOST_AUTO_TEST_CASE(disassemble_0x23_instruction_valid) {
  uint8_t binary_instruction[] = {0x23, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "RLA ($FF,X)");
}

//
// Test: Disassembles opcode 0x24.
//
BOOST_AUTO_TEST_CASE(disassemble_0x24_instruction_valid) {
  uint8_t binary_instruction[] = {0x24, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "BIT $FF");
}

//
// Test: Disassembles opcode 0x25.
//
BOOST_AUTO_TEST_CASE(disassemble_0x25_instruction_valid) {
  uint8_t binary_instruction[] = {0x25, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND $FF");
}

//
// Test: Disassembles opcode 0x26.
//
BOOST_AUTO_TEST_CASE(disassemble_0x26_instruction_valid) {
  uint8_t binary_instruction[] = {0x26, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ROL $FF");
}

//
// Test: Disassembles opcode 0x27.
//
BOOST_AUTO_TEST_CASE(disassemble_0x27_instruction_valid) {
  uint8_t binary_instruction[] = {0x27, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "RLA $FF");
}

//
// Test: Disassembles opcode 0x28.
//
BOOST_AUTO_TEST_CASE(disassemble_0x28_instruction_valid) {
  uint8_t binary_instruction[] = {0x28, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "PLP");
}

//
// Test: Disassembles opcode 0x29.
//
BOOST_AUTO_TEST_CASE(disassemble_0x29_instruction_valid) {
  uint8_t binary_instruction[] = {0x29, 0x2C};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND #$2C");
}

//
// Test: Disassembles opcode 0x2A.
//
BOOST_AUTO_TEST_CASE(disassemble_0x2A_instruction_valid) {
  uint8_t binary_instruction[] = {0x2A};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ROL A");
}

//
// Test: Disassembles opcode 0x2B.
//
BOOST_AUTO_TEST_CASE(disassemble_0x2B_instruction_valid) {
  uint8_t binary_instruction[] = {0x2B, 0x2C};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ANC #$2C");
}

//
// Test: Disassembles opcode 0x2C.
//
BOOST_AUTO_TEST_CASE(disassemble_0x2C_instruction_valid) {
  uint8_t binary_instruction[] = {0x2C, 0xEE, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "BIT $FFEE");
}

//
// Test: Disassembles opcode 0x2D.
//
BOOST_AUTO_TEST_CASE(disassemble_0x2D_instruction_valid) {
  uint8_t binary_instruction[] = {0x2D, 0xEE, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND $FFEE");
}

//
// Test: Disassembles opcode 0x2E.
//
BOOST_AUTO_TEST_CASE(disassemble_0x2E_instruction_valid) {
  uint8_t binary_instruction[] = {0x2E, 0xEE, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ROL $FFEE");
}

//
// Test: Disassembles opcode 0x2F.
//
BOOST_AUTO_TEST_CASE(disassemble_0x2F_instruction_valid) {
  uint8_t binary_instruction[] = {0x2F, 0xEE, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "RLA $FFEE");
}

//
// Test: Disassembles opcode 0x30.
//
BOOST_AUTO_TEST_CASE(disassemble_0x30_instruction_valid) {
  uint8_t binary_instruction[] = {0x30, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "BMI $FF");
}

//
// Test: Disassembles opcode 0x31.
//
BOOST_AUTO_TEST_CASE(disassemble_0x31_instruction_valid) {
  uint8_t binary_instruction[] = {0x31, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND ($FF),Y");
}

//
// Test: Disassembles opcode 0x32.
//
BOOST_AUTO_TEST_CASE(disassemble_0x32_instruction_valid) {
  uint8_t binary_instruction[] = {0x32};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "STP");
}

//
// Test: Disassembles opcode 0x33.
//
BOOST_AUTO_TEST_CASE(disassemble_0x33_instruction_valid) {
  uint8_t binary_instruction[] = {0x33, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "RLA ($FF),Y");
}

//
// Test: Disassembles opcode 0x34.
//
BOOST_AUTO_TEST_CASE(disassemble_0x34_instruction_valid) {
  uint8_t binary_instruction[] = {0x34, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP $FF,X");
}

//
// Test: Disassembles opcode 0x35.
//
BOOST_AUTO_TEST_CASE(disassemble_0x35_instruction_valid) {
  uint8_t binary_instruction[] = {0x35, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND $FF,X");
}

//
// Test: Disassembles opcode 0x36.
//
BOOST_AUTO_TEST_CASE(disassemble_0x36_instruction_valid) {
  uint8_t binary_instruction[] = {0x36, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "ROL $FF,X");
}

//
// Test: Disassembles opcode 0x37.
//
BOOST_AUTO_TEST_CASE(disassemble_0x37_instruction_valid) {
  uint8_t binary_instruction[] = {0x37, 0xFF};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "RLA $FF,X");
}

//
// Test: Disassembles opcode 0x38.
//
BOOST_AUTO_TEST_CASE(disassemble_0x38_instruction_valid) {
  uint8_t binary_instruction[] = {0x38};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "SEC");
}

//
// Test: Disassembles opcode 0x39.
//
BOOST_AUTO_TEST_CASE(disassemble_0x39_instruction_valid) {
  uint8_t binary_instruction[] = {0x39, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "AND $EEFF,Y");
}

//
// Test: Disassembles opcode 0x3A.
//
BOOST_AUTO_TEST_CASE(disassemble_0x3A_instruction_valid) {
  uint8_t binary_instruction[] = {0x3A};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "NOP");
}

//
// Test: Disassembles opcode 0x3B.
//
BOOST_AUTO_TEST_CASE(disassemble_0x3B_instruction_valid) {
  uint8_t binary_instruction[] = {0x3B, 0xFF, 0xEE};
  check_disassemble(binary_instruction, sizeof(binary_instruction), "RLA $EEFF,Y");
}

//
// Test: Decodes an instruction that is too small.  In this case, an empty instruction.
//
BOOST_AUTO_TEST_CASE(decode_invalid_instruction_too_small) {
  uint8_t empty_instruction[] = {};
  auto const instruction = jde::decode(empty_instruction, sizeof(empty_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x00.
//
BOOST_AUTO_TEST_CASE(decode_0x00_brk_instruction_valid) {
  uint8_t brk_instruction[] = {0x00, 0xFF};
  auto const instruction = jde::decode(brk_instruction, sizeof(brk_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::BRK);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x00);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::IMMEDIATE);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x01 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x01_ora_instruction_valid) {
  uint8_t ora_instruction[] = {0x01, 0xFF};
  auto const instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x01);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x01 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x01_ora_instruction_invalid_too_small) {
  uint8_t ora_instruction[] = {0x01};
  auto const instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x02.
//
BOOST_AUTO_TEST_CASE(decode_0x02_stp_instruction_valid) {
  uint8_t stp_instruction[] = {0x02};
  auto const instruction = jde::decode(stp_instruction, sizeof(stp_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::STP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x02);
  check_instruction_no_operand(instruction);
}

//
// Test: Decodes opcode value 0x03 with operand value set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x03_slo_instruction_valid) {
  uint8_t slo_instruction[] = {0x03, 0xFF};
  auto const instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::SLO);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x03);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x03 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x03_slo_instruction_invalid_too_small) {
  uint8_t slo_instruction[] = {0x03};
  auto const instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x04 with operand value set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x04_nop_instruction_valid) {
  uint8_t nop_instruction[] = {0x04, 0xFF};
  auto const instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::NOP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x04);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x04 with missing operand type.
//
BOOST_AUTO_TEST_CASE(decode_0x04_nop_instruction_invalid_too_small) {
  uint8_t nop_instruction[] = {0x04};
  auto const instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x05 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x05_ora_instruction_valid) {
  uint8_t ora_instruction[] = {0x05, 0xFF};
  auto const instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x05);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x05 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x05_ora_instruction_invalid_too_small) {
  uint8_t ora_instruction[] = {0x05};
  auto const instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x06 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x06_asl_instruction_valid) {
  uint8_t asl_instruction[] = {0x06, 0xFF};
  auto const instruction = jde::decode(asl_instruction, sizeof(asl_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ASL);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x06);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x06 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x06_asl_instruction_invalid_too_small) {
  uint8_t asl_instruction[] = {0x06};
  auto const instruction = jde::decode(asl_instruction, sizeof(asl_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x07 with operand value set to 0xFF
//
BOOST_AUTO_TEST_CASE(decode_0x07_slo_instruction_valid) {
  uint8_t slo_instruction[] = {0x07, 0xFF};
  auto const instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::SLO);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x07);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x07 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x07_slo_instruction_invalid_too_small) {
  uint8_t slo_instruction[] = {0x07};
  auto const instruction = jde::decode(slo_instruction, sizeof(slo_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x08.
//
BOOST_AUTO_TEST_CASE(decode_0x08_php_instruction_valid) {
  uint8_t php_instruction[] = {0x08, 0xFF};
  auto const instruction = jde::decode(php_instruction, sizeof(php_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::PHP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x08);
  check_instruction_no_operand(instruction);
}

//
// Test: Decodes opcode value 0x09 with missing operand value.
//
BOOST_AUTO_TEST_CASE(decode_0x09_ora_instruction_invalid_too_small) {
  uint8_t ora_instruction[] = {0x09};
  auto const instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  check_instruction_invalid(instruction);
}

//
// Test: Decodes opcode value 0x09 with operand set to 0xFF.
//
BOOST_AUTO_TEST_CASE(decode_0x09_ora_instruction_valid) {
  uint8_t ora_instruction[] = {0x09, 0xFF};
  auto const instruction = jde::decode(ora_instruction, sizeof(ora_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x09);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::IMMEDIATE);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x0A.
//
BOOST_AUTO_TEST_CASE(decode_0x0A_asl_instruction_valid) {
  uint8_t asl_instruction[] = {0x0A};
  auto const instruction = jde::decode(asl_instruction, sizeof(asl_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ASL);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x0A);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::REGISTER);
}

//
// Test: Decodes opcode value 0x0B.
//
BOOST_AUTO_TEST_CASE(decode_0x0B_anc_instruction_valid) {
  uint8_t anc_instruction[] = {0x0B, 0xFF};
  auto const instruction = jde::decode(anc_instruction, sizeof(anc_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ANC);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x0B);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::IMMEDIATE);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x0C.
//
BOOST_AUTO_TEST_CASE(decode_0x0C_nop_instruction_valid) {
  uint8_t nop_instruction[] = {0x0C, 0xFF, 0xEE};
  auto const instruction = jde::decode(nop_instruction, sizeof(nop_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::NOP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x0C);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint16_t>(instruction.decoded_operand.value) == static_cast<uint16_t>(0xEEFF));
}

//
// Test: Decodes opcode value 0x0D.
//
BOOST_AUTO_TEST_CASE(decode_0x0D_ora_instruction_valid) {
  uint8_t binary_instruction[] = {0x0D, 0xFF, 0xEE};
  auto const instruction = jde::decode(binary_instruction, sizeof(binary_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x0D);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint16_t>(instruction.decoded_operand.value) == static_cast<uint16_t>(0xEEFF));
}

//
// Test: Decodes opcode value 0x0E.
//
BOOST_AUTO_TEST_CASE(decode_0x0E_asl_instruction_valid) {
  uint8_t binary_instruction[] = {0x0E, 0xFF, 0xEE};
  auto const instruction = jde::decode(binary_instruction, sizeof(binary_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ASL);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x0E);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint16_t>(instruction.decoded_operand.value) == static_cast<uint16_t>(0xEEFF));
}

//
// Test: Decodes opcode value 0x0F.
//
BOOST_AUTO_TEST_CASE(decode_0x0F_instruction_valid) {
  uint8_t binary_instruction[] = {0x0F, 0xFF, 0xEE};
  auto const instruction = jde::decode(binary_instruction, sizeof(binary_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::SLO);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x0F);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint16_t>(instruction.decoded_operand.value) == static_cast<uint16_t>(0xEEFF));
}

//
// Test: Decodes opcode value 0x10.
//
BOOST_AUTO_TEST_CASE(decode_0x10_instruction_valid) {
  uint8_t binary_instruction[] = {0x10, 0xFF};
  auto const instruction = jde::decode(binary_instruction, sizeof(binary_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::BPL);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x10);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x11.
//
BOOST_AUTO_TEST_CASE(decode_0x11_instruction_valid) {
  uint8_t binary_instruction[] = {0x11, 0xFF};
  auto const instruction = jde::decode(binary_instruction, sizeof(binary_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::ORA);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x11);
  BOOST_CHECK(instruction.decoded_operand.type == operand_type::MEMORY);
  BOOST_CHECK(std::get<uint8_t>(instruction.decoded_operand.value) == static_cast<uint8_t>(0xFF));
}

//
// Test: Decodes opcode value 0x12.
//
BOOST_AUTO_TEST_CASE(decode_0x12_instruction_valid) {
  uint8_t binary_instruction[] = {0x12};
  auto const instruction = jde::decode(binary_instruction, sizeof(binary_instruction));
  BOOST_CHECK(instruction.decoded_opcode.type == opcode_type::STP);
  BOOST_CHECK(instruction.decoded_opcode.value == 0x12);
  check_instruction_no_operand(instruction);
}

ext: cc

max_stars_repo_name: JonForShort/nes-emulator

max_issues_repo_name: JonForShort/nes-emulator

max_forks_repo_name: JonForShort/nes-emulator


text:
//  Boost string_algo library join.hpp header file  ---------------------------//

//  Copyright Pavol Droba 2002-2006.
//
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/ for updates, documentation, and revision history.

#ifndef BOOST_STRING_JOIN_HPP
#define BOOST_STRING_JOIN_HPP

#include <boost/algorithm/string/config.hpp>
#include <boost/algorithm/string/detail/sequence.hpp>
#include <boost/range/value_type.hpp>
#include <boost/range/as_literal.hpp>

/*! \file
    Defines join algorithm.

    Join algorithm is a counterpart to split algorithms.
    It joins strings from a 'list' by adding user defined separator.
    Additionally there is a version that allows simple filtering
    by providing a predicate.
*/

namespace boost {
    namespace algorithm {

//  join --------------------------------------------------------------//

        //! Join algorithm
        /*!
            This algorithm joins all strings in a 'list' into one long string.
            Segments are concatenated by given separator.

            \param Input A container that holds the input strings. It must be a container-of-containers.
            \param Separator A string that will separate the joined segments.
            \return Concatenated string.

            \note This function provides the strong exception-safety guarantee
        */
        template< typename SequenceSequenceT, typename Range1T>
        inline typename range_value<SequenceSequenceT>::type
        join(
            const SequenceSequenceT& Input,
            const Range1T& Separator)
        {
            // Define working types
            typedef typename range_value<SequenceSequenceT>::type ResultT;
            typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;

            // Parse input
            InputIteratorT itBegin=::boost::begin(Input);
            InputIteratorT itEnd=::boost::end(Input);

            // Construct container to hold the result
            ResultT Result;

            // Append first element
            if(itBegin!=itEnd)
            {
                detail::insert(Result, ::boost::end(Result), *itBegin);
                ++itBegin;
            }

            for(;itBegin!=itEnd; ++itBegin)
            {
                // Add separator
                detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator));
                // Add element
                detail::insert(Result, ::boost::end(Result), *itBegin);
            }

            return Result;
        }

// join_if ----------------------------------------------------------//

        //! Conditional join algorithm
        /*!
            This algorithm joins all strings in a 'list' into one long string.
            Segments are concatenated by given separator. Only segments that
            satisfy the predicate will be added to the result.

            \param Input A container that holds the input strings. It must be a container-of-containers.
            \param Separator A string that will separate the joined segments.
            \param Pred A segment selection predicate
            \return Concatenated string.

            \note This function provides the strong exception-safety guarantee
        */
        template< typename SequenceSequenceT, typename Range1T, typename PredicateT>
        inline typename range_value<SequenceSequenceT>::type
        join_if(
            const SequenceSequenceT& Input,
            const Range1T& Separator,
            PredicateT Pred)
        {
            // Define working types
            typedef typename range_value<SequenceSequenceT>::type ResultT;
            typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;

            // Parse input
            InputIteratorT itBegin=::boost::begin(Input);
            InputIteratorT itEnd=::boost::end(Input);

            // Construct container to hold the result
            ResultT Result;

            // Roll to the first element that will be added
            while(itBegin!=itEnd && !Pred(*itBegin)) ++itBegin;
            // Add this element
            if(itBegin!=itEnd)
            {
                detail::insert(Result, ::boost::end(Result), *itBegin);
                ++itBegin;
            }

            for(;itBegin!=itEnd; ++itBegin)
            {
                if(Pred(*itBegin))
                {
                    // Add separator
                    detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator));
                    // Add element
                    detail::insert(Result, ::boost::end(Result), *itBegin);
                }
            }

            return Result;
        }

    } // namespace algorithm

    // pull names to the boost namespace
    using algorithm::join;
    using algorithm::join_if;

} // namespace boost

#endif  // BOOST_STRING_JOIN_HPP


text:
#ifndef _CLIQUE_HPP_
#define _CLIQUE_HPP_

/*
 * clique.hpp
 *
 * Copyright 2012 Alexander Fix
 * See LICENSE.txt for license information
 *
 * This file contains classes for defining an energy function as a sum of
 * "local clique energies". That is, we define an energy function
 *      f(x_1, x_2, ..., x_n)
 *  by writing f as a sum of local energies, f_C, defined on "cliques"
 *  or "patches" of the image. For instance, we could let the set of cliques
 *  be all 2x2 patches of the image (i.e., sliding windows of size 2x2).
 *
 *  The fusion move algorithm (in fusion-move.hpp) can handle energies which
 *  are the sum of the individual energy functions for each clique, i.e.,
 *          f(x_1, ..., x_n) = sum_C f_C(x_C)
 *  where f_C is any real-valued function on the boolean variables in C,
 *  and x_C is just the labeling x restricted to the subset C.
 *
 *
 *  To make the above concrete, we provide two classes: CliqueEnergy and
 *  CliqueSystem. A CliqueEnergy has two important parts: it keeps track of a
 *  subset of the variables which it depends on, and it can call operator()
 *  on a labeling of these variables, returning the local energy for that
 *  particular labeling.
 *
 *  A CliqueSystem is basically just a container for CliqueEnergy objects.
 *  The total energy to be optimized is the sum over all cliques of the local
 *  energies.
 *
 *
 *  To make this as flexible as possible, CliqueEnergy is an abstract base
 *  class. To use the fusion move code, the user should inherit from
 *  CliqueEnergy and implement their own operator(). This operator() should
 *  take in an array of labels (corresponding to a labeling of just the
 *  variables in the clique) and return the local energy corresponding to that
 *  labeling.
 *
 *  The reason this isn't just a simple function pointer is that the user may
 *  want to have each local energy depend on some parameter (for instance,
 *  the unary terms will typically depend on the observed data values).
 *  In this case, the user is free to add data members to their derived class.
 *  CliqueSystem is smart and stores the CliqueEnergy polymorphically, so no
 *  slicing occurs.
 */

#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>

/*
 * Abstract base class for defining the local energy of a clique.
 *
 * Template parameters:
 *  R   "real" type that is the type of energy-values
 *  T   "image" type, the base domain of the image labelling
 *  D   Maximum degree of the clique
 *
 * To use: derive from this class and implement operator()
 *
 * In the fusion-move code, these clique energies are stored by pointer, so
 * derived types can add additional data-members without worrying about
 * slicing. This is useful if your clique energy function needs to be a
 * closure over additional data than just the current labelling of the clique
 *
 * See foe-cliques.{hpp|cpp} for example of how to derive from this class.
 */
template<typename R, typename T, int D>
class CliqueEnergy {
    public:
        /*
         * Parameters
         *  size    the size of the clique. Must be <= D
         *  nbd     array of indices that defines the clique. Must be at least
         *          size 'size' long.
         */
        CliqueEnergy(int size, int nbd[])
            : _size(size)
        {
            assert(size <= D);
            for (int i = 0; i < size; ++i)
                _neighborhood[i] = nbd[i];
        }

        /*
         * operator() computes the energy of the clique, given the current
         * labelling of the clique.
         *
         *  buf     will be an array of size _size containing the current
         *          labelling of the image, with buf[i] corresponding to
         *          _neighborhood[i]
         */
        virtual R operator()(const T buf[]) const = 0;

        int _size;
        int _neighborhood[D];
};

/*
 * Container for a set of cliques.
 *
 * Stores CliqueEnergy polymorphically, so multiple derived types can be part
 * of the same CliqueSystem
 */
template<typename R, typename T, int D>
class CliqueSystem {
    public:
        typedef boost::shared_ptr<CliqueEnergy<R, T, D> > CliquePointer;

        CliqueSystem() { }

        /*
         * Add a clique to the CliqueSystem
         */
        void AddClique(const CliquePointer& cp);

        /*
         * Returns the total energy of the current labelling by summing
         * the results of the individual CliqueEnergy
         */
        R Energy(const T* im) const;

        /*
         * Returns a vector containing all the cliques in the CliqueSystem
         */
        const std::vector<CliquePointer>& GetCliques() const;

    private:
        std::vector<CliquePointer> _cliques;
};

/*
 * IMPLEMENTATION
 */

template<typename R, typename T, int D>
void CliqueSystem<R, T, D>::AddClique(const CliquePointer& cp) {
    _cliques.push_back(cp);
}

template <typename R, typename T, int D>
R CliqueSystem<R, T, D>::Energy(const T* im) const {
    R energy = 0;
    BOOST_FOREACH(const CliquePointer& cp, _cliques) {
        const CliqueEnergy<R, T, D>& c = *cp;
        T buf[c._size];
        for (int i = 0; i < c._size; ++i)
            buf[i] = im[c._neighborhood[i]];
        energy += c(buf);
    }
    return energy;
}

template <typename R, typename T, int D>
const std::vector<typename CliqueSystem<R, T, D>::CliquePointer>&
CliqueSystem<R, T, D>::GetCliques() const {
    return _cliques;
}

#endif

max_stars_repo_name: burcin/opengm

max_issues_repo_name: burcin/opengm

max_forks_repo_name: burcin/opengm


text:
// Copyright 2019 The Beam Team
//
// Licensed 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 "wallet/core/common_utils.h"

#include "wallet/core/base_transaction.h"
#include "wallet/core/strings_resources.h"
#include "utility/logger.h"

#include <boost/format.hpp>

namespace beam::wallet
{
WalletAddress GenerateNewAddress(
        const IWalletDB::Ptr& walletDB,
        const std::string& label,
        WalletAddress::ExpirationStatus expirationStatus,
        bool saveRequired)
{
    WalletAddress address;
    walletDB->createAddress(address);

    address.setExpiration(expirationStatus);
    address.m_label = label;
    if (saveRequired)
    {
        walletDB->saveAddress(address);
    }

    LOG_INFO() << boost::format(kAddrNewGenerated)
                % std::to_string(address.m_walletID);
    if (!label.empty()) {
        LOG_INFO() << boost::format(kAddrNewGeneratedLabel) % label;
    }
    return address;
}

bool ReadTreasury(ByteBuffer& bb, const std::string& sPath)
{
    if (sPath.empty())
        return false;

    std::FStream f;
    if (!f.Open(sPath.c_str(), true))
        return false;

    size_t nSize = static_cast<size_t>(f.get_Remaining());
    if (!nSize)
        return false;

    bb.resize(f.get_Remaining());
    return f.read(&bb.front(), nSize) == nSize;
}

std::string TxIDToString(const TxID& txId)
{
    return to_hex(txId.data(), txId.size());
}

void GetStatusResponseJson(const TxDescription& tx,
                           nlohmann::json& msg,
                           Height kernelProofHeight,
                           Height systemHeight)
{
    msg = nlohmann::json
    {
        {"txId", TxIDToString(tx.m_txId)},
        {"status", tx.m_status},
        {"status_string", tx.getStatusStringApi()},
        {"sender", std::to_string(tx.m_sender ? tx.m_myId : tx.m_peerId)},
        {"receiver", std::to_string(tx.m_sender ? tx.m_peerId : tx.m_myId)},
        {"fee", tx.m_fee},
        {"value", tx.m_amount},
        {"comment", std::string{ tx.m_message.begin(), tx.m_message.end() }},
        {"create_time", tx.m_createTime},
        {"income", !tx.m_sender}
    };

    if (kernelProofHeight > 0)
    {
        msg["height"] = kernelProofHeight;

        if (systemHeight >= kernelProofHeight)
        {
            msg["confirmations"] = systemHeight - kernelProofHeight;
        }
    }

    if (tx.m_status == TxStatus::Failed)
    {
        msg["failure_reason"] = GetFailureMessage(tx.m_failureReason);
    }
    else if (tx.m_status != TxStatus::Canceled)
    {
        msg["kernel"] = to_hex(tx.m_kernelID.m_pData, tx.m_kernelID.nBytes);
    }
}

}  // namespace beam::wallet

max_stars_repo_name: Atomisfoundation/beam

max_issues_repo_name: Atomisfoundation/beam

max_forks_repo_name: Atomisfoundation/beam