<commit_before>﻿// Copyright (c) 2013-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <validation.h>
#include <boost/algorithm/string.hpp>
#include <rpc/util.h>
#include <services/assetconsensus.h>
#include <services/asset.h>
#include <services/rpc/assetrpc.h>
#include <chainparams.h>
#include <rpc/server.h>
#include <thread>
#include <policy/rbf.h>
#include <policy/policy.h>
#include <index/txindex.h>
#include <core_io.h>
#include <boost/thread/thread.hpp>
#include <util/system.h>
#include <rpc/blockchain.h>
#include <node/context.h>
extern std::string exePath;
extern RecursiveMutex cs_setethstatus;
extern std::string EncodeDestination(const CTxDestination& dest);
extern CTxDestination DecodeDestination(const std::string& str);


bool BuildAssetJson(const CAsset& asset, const uint32_t& nAsset, UniValue& oAsset) {
    oAsset.__pushKV("asset_guid", nAsset);
    oAsset.__pushKV("symbol", DecodeBase64(asset.strSymbol));
	oAsset.__pushKV("public_value", DecodeBase64(asset.strPubData));
    oAsset.__pushKV("contract", asset.vchContract.empty()? "" : "0x"+HexStr(asset.vchContract));
    oAsset.__pushKV("notary_address", asset.notaryKeyID.IsNull()? "" : EncodeDestination(WitnessV0KeyHash(asset.notaryKeyID)));
	oAsset.__pushKV("balance", asset.nBalance);
	oAsset.__pushKV("total_supply", asset.nTotalSupply);
	oAsset.__pushKV("max_supply", asset.nMaxSupply);
	oAsset.__pushKV("update_flags", asset.nUpdateFlags);
	oAsset.__pushKV("precision", asset.nPrecision);
	return true;
}
bool ScanAssets(CAssetDB& passetdb, const uint32_t count, const uint32_t from, const UniValue& oOptions, UniValue& oRes) {
	std::string strTxid = "";
    uint32_t nAsset = 0;
	if (!oOptions.isNull()) {
		const UniValue &txid = find_value(oOptions, "txid");
		if (txid.isStr()) {
			strTxid = txid.get_str();
		}
		const UniValue &assetObj = find_value(oOptions, "asset_guid");
		if (assetObj.isNum()) {
			nAsset = assetObj.get_uint();
		}
	}
	std::unique_ptr<CDBIterator> pcursor(passetdb.NewIterator());
	pcursor->SeekToFirst();
	CAsset txPos;
	uint32_t key = 0;
	uint32_t index = 0;
	while (pcursor->Valid()) {
		try {
            key = 0;
			if (pcursor->GetKey(key) && key != 0 && (nAsset == 0 || nAsset != key)) {
				pcursor->GetValue(txPos);
                if(txPos.IsNull()){
                    pcursor->Next();
                    continue;
                }
				UniValue oAsset(UniValue::VOBJ);
				if (!BuildAssetJson(txPos, key, oAsset))
				{
					pcursor->Next();
					continue;
				}
				index += 1;
				if (index <= from) {
					pcursor->Next();
					continue;
				}
				oRes.push_back(oAsset);
				if (index >= count + from)
					break;
			}
			pcursor->Next();
		}
		catch (std::exception &e) {
			return error("%s() : deserialize error", __PRETTY_FUNCTION__);
		}
	}
	return true;
}
bool FillNotarySig(const CTransactionRef& tx, std::vector<CAssetOut> & voutAssets, const uint32_t& nAsset, const std::vector<unsigned char> &vchSig) {
    auto itVout = std::find_if( voutAssets.begin(), voutAssets.end(), [&nAsset](const CAssetOut& element){ return element.key == nAsset;} );
    if(itVout != voutAssets.end()) {
        itVout->vchNotarySig = vchSig;
        return true;
    }
    return false;
}

bool UpdateNotarySignature(CMutableTransaction& mtx, const uint32_t& nAsset, const std::vector<unsigned char> &vchSig) {
    const CTransactionRef& tx = MakeTransactionRef(mtx);
    std::vector<unsigned char> data;
    bool bFilledNotarySig = false;
     // call API endpoint or notary signatures and fill them in for every asset
    if(IsSyscoinMintTx(tx->nVersion)) {
        CMintSyscoin mintSyscoin(*tx);
        if(FillNotarySig(tx, mintSyscoin.voutAssets, nAsset, vchSig)) {
            bFilledNotarySig = true;
            mintSyscoin.SerializeData(data);
        }
    } else if(tx->nVersion == SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM) {
        CBurnSyscoin burnSyscoin(*tx);
        if(FillNotarySig(tx, burnSyscoin.voutAssets, nAsset, vchSig)) {
            bFilledNotarySig = true;
            burnSyscoin.SerializeData(data);
        }
    } else if(IsAssetAllocationTx(tx->nVersion)) {
        CAssetAllocation allocation(*tx);
        if(FillNotarySig(tx, allocation.voutAssets, nAsset, vchSig)) {
            bFilledNotarySig = true;
            allocation.SerializeData(data);
        }
    }
    if(bFilledNotarySig) {
        // find previous commitment (OP_RETURN) and replace script
        CScript scriptDataNew;
        scriptDataNew << OP_RETURN << data;
        for(auto& vout: mtx.vout) {
            if(vout.scriptPubKey.IsUnspendable()) {
                vout.scriptPubKey = scriptDataNew;
                return true;
            }
        }
    }
    return false;
}
UniValue assettransactionnotarize(const JSONRPCRequest& request) {	

    RPCHelpMan{"assettransactionnotarize",	
        "\nUpdate notary signature on an asset transaction. Will require re-signing transaction before submitting to network.\n",	
        {	
            {"hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Transaction to notarize."},
            {"asset_guid", RPCResult::Type::NUM, RPCArg::Optional::NO, "The guid of the asset to notarize"},
            {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "Base64 encoded notary signature to add to transaction."}	
        },
        RPCResult{
            RPCResult::Type::OBJ, "", "",
            {
                {RPCResult::Type::STR_HEX, "hex", "The notarized transaction hex, which you must sign prior to submitting."},
            }},	
        RPCExamples{	
            HelpExampleCli("assettransactionnotarize", "\"hex\" 12121 \"signature\"")	
            + HelpExampleRpc("assettransactionnotarize", "\"hex\",12121,\"signature\"")	
        }	
    }.Check(request);	

    const std::string &hexstring = request.params[0].get_str();
    const uint32_t &nAsset = equest.params[1].get_uint();
    std::vector<unsigned char> vchSig = DecodeBase64(request.params[2].get_str().c_str());
    CMutableTransaction mtx;
    if(!DecodeHexTx(mtx, hexstring, false, true)) {
        if(!DecodeHexTx(mtx, hexstring, true, true)) {
             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Could not decode transaction");
        }
    }
    UpdateNotarySignature(mtx, nAsset, vchSig);
    UniValue ret(UniValue::VOBJ);	
    ret.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
    return ret;
}
UniValue getnotarysighash(const JSONRPCRequest& request) {	

    RPCHelpMan{"getnotarysighash",	
        "\nGet sighash for notary to sign off on, use assettransactionnotarize to update the transaction after re-singing once sighash is used to create a notarized signature.\n",	
        {	
            {"hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Transaction to get sighash for."},
            {"asset_guid", RPCResult::Type::NUM, RPCArg::Optional::NO, "The guid of the asset to sighash for"}
        },
        RPCResult{
            RPCResult::Type::OBJ, "", "",
            {
                {RPCResult::Type::STR_HEX, "sighash", "Notary sighash (uint256)"},
            }},	
        RPCExamples{	
            HelpExampleCli("getnotarysighash", "\"hex\" 12121")
            + HelpExampleRpc("getnotarysighash", "\"hex\",12121")	
        }	
    }.Check(request);	
    const std::string &hexstring = request.params[0].get_str();
    const uint32_t &nAsset = request.params[1].get_uint();
    CMutableTransaction mtx;
    if(!DecodeHexTx(mtx, hexstring, false, true)) {
        if(!DecodeHexTx(mtx, hexstring, true, true)) {
             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Could not decode transaction");
        }
    }
    uint156 sigHash;
    CTransaction tx(mtx);
    auto itVout = std::find_if( tx.voutAssets.begin(), tx.voutAssets.end(), [&nAsset](const CAssetOut& element){ return element.key == nAsset;} );
    if(itVout != tx.voutAssets.end()) {
        sigHash = tx.GetNotarySigHash(*itVout);
    }
    return sigHash.GetHex();
}
UniValue convertaddress(const JSONRPCRequest& request)	 {	

    RPCHelpMan{"convertaddress",	
        "\nConvert between Syscoin 3 and Syscoin 4 formats. This should only be used with addressed based on compressed private keys only. P2WPKH can be shown as P2PKH in Syscoin 3.\n",	
        {	<commit_msg>compile<commit_after>﻿// Copyright (c) 2013-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <validation.h>
#include <boost/algorithm/string.hpp>
#include <rpc/util.h>
#include <services/assetconsensus.h>
#include <services/asset.h>
#include <services/rpc/assetrpc.h>
#include <chainparams.h>
#include <rpc/server.h>
#include <thread>
#include <policy/rbf.h>
#include <policy/policy.h>
#include <index/txindex.h>
#include <core_io.h>
#include <boost/thread/thread.hpp>
#include <util/system.h>
#include <rpc/blockchain.h>
#include <node/context.h>
extern std::string exePath;
extern RecursiveMutex cs_setethstatus;
extern std::string EncodeDestination(const CTxDestination& dest);
extern CTxDestination DecodeDestination(const std::string& str);


bool BuildAssetJson(const CAsset& asset, const uint32_t& nAsset, UniValue& oAsset) {
    oAsset.__pushKV("asset_guid", nAsset);
    oAsset.__pushKV("symbol", DecodeBase64(asset.strSymbol));
	oAsset.__pushKV("public_value", DecodeBase64(asset.strPubData));
    oAsset.__pushKV("contract", asset.vchContract.empty()? "" : "0x"+HexStr(asset.vchContract));
    oAsset.__pushKV("notary_address", asset.notaryKeyID.IsNull()? "" : EncodeDestination(WitnessV0KeyHash(asset.notaryKeyID)));
	oAsset.__pushKV("balance", asset.nBalance);
	oAsset.__pushKV("total_supply", asset.nTotalSupply);
	oAsset.__pushKV("max_supply", asset.nMaxSupply);
	oAsset.__pushKV("update_flags", asset.nUpdateFlags);
	oAsset.__pushKV("precision", asset.nPrecision);
	return true;
}
bool ScanAssets(CAssetDB& passetdb, const uint32_t count, const uint32_t from, const UniValue& oOptions, UniValue& oRes) {
	std::string strTxid = "";
    uint32_t nAsset = 0;
	if (!oOptions.isNull()) {
		const UniValue &txid = find_value(oOptions, "txid");
		if (txid.isStr()) {
			strTxid = txid.get_str();
		}
		const UniValue &assetObj = find_value(oOptions, "asset_guid");
		if (assetObj.isNum()) {
			nAsset = assetObj.get_uint();
		}
	}
	std::unique_ptr<CDBIterator> pcursor(passetdb.NewIterator());
	pcursor->SeekToFirst();
	CAsset txPos;
	uint32_t key = 0;
	uint32_t index = 0;
	while (pcursor->Valid()) {
		try {
            key = 0;
			if (pcursor->GetKey(key) && key != 0 && (nAsset == 0 || nAsset != key)) {
				pcursor->GetValue(txPos);
                if(txPos.IsNull()){
                    pcursor->Next();
                    continue;
                }
				UniValue oAsset(UniValue::VOBJ);
				if (!BuildAssetJson(txPos, key, oAsset))
				{
					pcursor->Next();
					continue;
				}
				index += 1;
				if (index <= from) {
					pcursor->Next();
					continue;
				}
				oRes.push_back(oAsset);
				if (index >= count + from)
					break;
			}
			pcursor->Next();
		}
		catch (std::exception &e) {
			return error("%s() : deserialize error", __PRETTY_FUNCTION__);
		}
	}
	return true;
}
bool FillNotarySig(const CTransactionRef& tx, std::vector<CAssetOut> & voutAssets, const uint32_t& nAsset, const std::vector<unsigned char> &vchSig) {
    auto itVout = std::find_if( voutAssets.begin(), voutAssets.end(), [&nAsset](const CAssetOut& element){ return element.key == nAsset;} );
    if(itVout != voutAssets.end()) {
        itVout->vchNotarySig = vchSig;
        return true;
    }
    return false;
}

bool UpdateNotarySignature(CMutableTransaction& mtx, const uint32_t& nAsset, const std::vector<unsigned char> &vchSig) {
    const CTransactionRef& tx = MakeTransactionRef(mtx);
    std::vector<unsigned char> data;
    bool bFilledNotarySig = false;
     // call API endpoint or notary signatures and fill them in for every asset
    if(IsSyscoinMintTx(tx->nVersion)) {
        CMintSyscoin mintSyscoin(*tx);
        if(FillNotarySig(tx, mintSyscoin.voutAssets, nAsset, vchSig)) {
            bFilledNotarySig = true;
            mintSyscoin.SerializeData(data);
        }
    } else if(tx->nVersion == SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM) {
        CBurnSyscoin burnSyscoin(*tx);
        if(FillNotarySig(tx, burnSyscoin.voutAssets, nAsset, vchSig)) {
            bFilledNotarySig = true;
            burnSyscoin.SerializeData(data);
        }
    } else if(IsAssetAllocationTx(tx->nVersion)) {
        CAssetAllocation allocation(*tx);
        if(FillNotarySig(tx, allocation.voutAssets, nAsset, vchSig)) {
            bFilledNotarySig = true;
            allocation.SerializeData(data);
        }
    }
    if(bFilledNotarySig) {
        // find previous commitment (OP_RETURN) and replace script
        CScript scriptDataNew;
        scriptDataNew << OP_RETURN << data;
        for(auto& vout: mtx.vout) {
            if(vout.scriptPubKey.IsUnspendable()) {
                vout.scriptPubKey = scriptDataNew;
                return true;
            }
        }
    }
    return false;
}
UniValue assettransactionnotarize(const JSONRPCRequest& request) {	

    RPCHelpMan{"assettransactionnotarize",	
        "\nUpdate notary signature on an asset transaction. Will require re-signing transaction before submitting to network.\n",	
        {	
            {"hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Transaction to notarize."},
            {"asset_guid", RPCResult::Type::NUM, RPCArg::Optional::NO, "The guid of the asset to notarize"},
            {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "Base64 encoded notary signature to add to transaction."}	
        },
        RPCResult{
            RPCResult::Type::OBJ, "", "",
            {
                {RPCResult::Type::STR_HEX, "hex", "The notarized transaction hex, which you must sign prior to submitting."},
            }},	
        RPCExamples{	
            HelpExampleCli("assettransactionnotarize", "\"hex\" 12121 \"signature\"")	
            + HelpExampleRpc("assettransactionnotarize", "\"hex\",12121,\"signature\"")	
        }	
    }.Check(request);	

    const std::string &hexstring = request.params[0].get_str();
    const uint32_t &nAsset = equest.params[1].get_uint();
    std::vector<unsigned char> vchSig = DecodeBase64(request.params[2].get_str().c_str());
    CMutableTransaction mtx;
    if(!DecodeHexTx(mtx, hexstring, false, true)) {
        if(!DecodeHexTx(mtx, hexstring, true, true)) {
             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Could not decode transaction");
        }
    }
    UpdateNotarySignature(mtx, nAsset, vchSig);
    UniValue ret(UniValue::VOBJ);	
    ret.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
    return ret;
}
UniValue getnotarysighash(const JSONRPCRequest& request) {	

    RPCHelpMan{"getnotarysighash",	
        "\nGet sighash for notary to sign off on, use assettransactionnotarize to update the transaction after re-singing once sighash is used to create a notarized signature.\n",	
        {	
            {"hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Transaction to get sighash for."},
            {"asset_guid", RPCResult::Type::NUM, RPCArg::Optional::NO, "The guid of the asset to sighash for"}
        },
        RPCResult{
            RPCResult::Type::OBJ, "", "",
            {
                {RPCResult::Type::STR_HEX, "sighash", "Notary sighash (uint256)"},
            }},	
        RPCExamples{	
            HelpExampleCli("getnotarysighash", "\"hex\" 12121")
            + HelpExampleRpc("getnotarysighash", "\"hex\",12121")	
        }	
    }.Check(request);	
    const std::string &hexstring = request.params[0].get_str();
    const uint32_t &nAsset = request.params[1].get_uint();
    CMutableTransaction mtx;
    if(!DecodeHexTx(mtx, hexstring, false, true)) {
        if(!DecodeHexTx(mtx, hexstring, true, true)) {
             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Could not decode transaction");
        }
    }
    uint256 sigHash;
    CTransaction tx(mtx);
    auto itVout = std::find_if( tx.voutAssets.begin(), tx.voutAssets.end(), [&nAsset](const CAssetOut& element){ return element.key == nAsset;} );
    if(itVout != tx.voutAssets.end()) {
        sigHash = tx.GetNotarySigHash(*itVout);
    }
    return sigHash.GetHex();
}
UniValue convertaddress(const JSONRPCRequest& request)	 {	

    RPCHelpMan{"convertaddress",	
        "\nConvert between Syscoin 3 and Syscoin 4 formats. This should only be used with addressed based on compressed private keys only. P2WPKH can be shown as P2PKH in Syscoin 3.\n",	
        {	
{'fraction_non_alphanumeric': 0.13373969164575117, 'fraction_numerical': 0.00968088920760129, 'mean_word_length': 3.318709677419355, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1052290', 'n_tokens_mistral': 5839, 'n_tokens_neox': 5538, 'n_words': 1148}