<NME> base58_tests.cpp
<BEF> // Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"

#include "data/base58_encode_decode.json.h"
#include "data/base58_keys_invalid.json.h"
#include "data/base58_keys_valid.json.h"

#include "key.h"
#include "script/script.h"
#include "uint256.h"
#include "util.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"

#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/included/unit_test.hpp>

#include <univalue.h>

extern UniValue read_json(const std::string& jsondata);

std::string bitcoin_address_to_firo(const std::string address) {
    std::vector<unsigned char> vchTemp;
    if(DecodeBase58(address.c_str(), vchTemp) && vchTemp.size() > 4) {
        vchTemp.resize(vchTemp.size() - 4);
        switch (vchTemp[0]) {
        case 0:
            vchTemp[0] = 82;
            break;
        case 5:
            vchTemp[0] = 7;
            break;
        case 128:
            vchTemp[0] = 210;
            break;
        std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
        std::string base58string = test[1].get_str();
        BOOST_CHECK_MESSAGE(
                    EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,
                    strTest);
    }
}
            vchTemp[0] = 185;
            break;
        }
        return EncodeBase58Check(vchTemp);
    }
    return address;
}

BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)

// Goal: test low-level base58 encoding functionality
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
{
    UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 2) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
        std::string base58string = test[1].get_str();
        BOOST_CHECK_MESSAGE(
                    EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()) == base58string,
                    strTest);
    }
}

// Goal: test low-level base58 decoding functionality
BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
{
    UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
    std::vector<unsigned char> result;

    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 2) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        std::vector<unsigned char> expected = ParseHex(test[0].get_str());
        std::string base58string = test[1].get_str();
        BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest);
        BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);
    }

    BOOST_CHECK(!DecodeBase58("invalid", result));

    // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end.
    BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result));
    BOOST_CHECK( DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t ", result));
    std::vector<unsigned char> expected = ParseHex("971a55");
    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
}

// Visitor to check address type
class TestAddrTypeVisitor : public boost::static_visitor<bool>
{
private:
    std::string exp_addrType;
public:
    TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }
    bool operator()(const CKeyID &id) const
    {
        return (exp_addrType == "pubkey");
    }
    bool operator()(const CScriptID &id) const
    {
        return (exp_addrType == "script");
    }
    bool operator()(const CNoDestination &no) const
    {
        return (exp_addrType == "none");
    }
};

// Visitor to check address payload
class TestPayloadVisitor : public boost::static_visitor<bool>
{
private:
    std::vector<unsigned char> exp_payload;
public:
    TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }
    bool operator()(const CKeyID &id) const
    {
        uint160 exp_key(exp_payload);
        return exp_key == id;
    }
    bool operator()(const CScriptID &id) const
    {
        uint160 exp_key(exp_payload);
        return exp_key == id;
    }
    bool operator()(const CNoDestination &no) const
    {
        return exp_payload.size() == 0;
    }
};

// Goal: check that parsed keys match test payload
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
    UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
    CBitcoinSecret secret;
    CBitcoinAddress addr;
    SelectParams(CBaseChainParams::MAIN);

    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 3) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        std::string exp_base58string = test[0].get_str();
        std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
        const UniValue &metadata = test[2].get_obj();
        bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
        bool isTestnet = find_value(metadata, "isTestnet").get_bool();
        if (isTestnet)
            SelectParams(CBaseChainParams::TESTNET);
        else
            SelectParams(CBaseChainParams::MAIN);
        if(isPrivkey)
        {
            bool isCompressed = find_value(metadata, "isCompressed").get_bool();
            // Must be valid private key
            // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
            BOOST_CHECK_MESSAGE(secret.SetString(bitcoin_address_to_firo(exp_base58string)), "!SetString:"+ strTest);
            BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
            CKey privkey = secret.GetKey();
            BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
            BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);

            // Private key must be invalid public key
            addr.SetString(bitcoin_address_to_firo(exp_base58string));
            BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
        }
        else
        {
            std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
            // Must be valid public key
            BOOST_CHECK_MESSAGE(addr.SetString(bitcoin_address_to_firo(exp_base58string)), "SetString:" + strTest);
            BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
            BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
            CTxDestination dest = addr.Get();
            BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);

            // Public key must be invalid private key
            secret.SetString(exp_base58string);
            BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
        }
    }
}

// Goal: check that generated keys match test vectors
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
    UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));

    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 3) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        std::string exp_base58string = test[0].get_str();
        std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
        const UniValue &metadata = test[2].get_obj();
        bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
        bool isTestnet = find_value(metadata, "isTestnet").get_bool();
        if (isTestnet)
            SelectParams(CBaseChainParams::TESTNET);
        else
            SelectParams(CBaseChainParams::MAIN);
        if(isPrivkey)
        {
            bool isCompressed = find_value(metadata, "isCompressed").get_bool();
            CKey key;
            key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
            assert(key.IsValid());
            CBitcoinSecret secret;
            secret.SetKey(key);
            BOOST_CHECK_MESSAGE(secret.ToString() == bitcoin_address_to_firo(exp_base58string), "result mismatch: " + strTest);
        }
        else
        {
            std::string exp_addrType = find_value(metadata, "addrType").get_str();
            CTxDestination dest;
            if(exp_addrType == "pubkey")
            {
                dest = CKeyID(uint160(exp_payload));
            }
            else if(exp_addrType == "script")
            {
                dest = CScriptID(uint160(exp_payload));
            }
            else if(exp_addrType == "none")
            {
                dest = CNoDestination();
            }
            else
            {
                BOOST_ERROR("Bad addrtype: " << strTest);
                continue;
            }
            CBitcoinAddress addrOut;
            BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
            BOOST_CHECK_MESSAGE(addrOut.ToString() == bitcoin_address_to_firo(exp_base58string), "mismatch: " + strTest);
        }
    }

    // Visiting a CNoDestination must fail
    CBitcoinAddress dummyAddr;
    CTxDestination nodest = CNoDestination();
    BOOST_CHECK(!dummyAddr.Set(nodest));

    SelectParams(CBaseChainParams::MAIN);
}

// Goal: check that base58 parsing code is robust against a variety of corrupted data
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
    UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
    CBitcoinSecret secret;
    CBitcoinAddress addr;

    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 1) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        std::string exp_base58string = test[0].get_str();

        // must be invalid as public and as private key
        addr.SetString(exp_base58string);
        BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
        secret.SetString(exp_base58string);
        BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
    }
}


BOOST_AUTO_TEST_SUITE_END()


<MSG> script: Fix reference into empty vector run time exception

Edit by laanwj: `begin_ptr(sourcedata) + sourcedata.size()` -> `end_ptr(sourcedata)`

<DFF> @@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
         std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
         std::string base58string = test[1].get_str();
         BOOST_CHECK_MESSAGE(
-                    EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,
+                    EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string,
                     strTest);
     }
 }

{'commit': 'diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp\nindex fd3e4f1ff..d742fb9eb 100644\n--- a/src/script/interpreter.cpp\n+++ b/src/script/interpreter.cpp\n@@ -637,19 +637,19 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co\n                     valtype& vch = stacktop(-1);\n                     valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);\n                     if (opcode == OP_RIPEMD160)\n-                        CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);\n+                        CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));\n                     else if (opcode == OP_SHA1)\n-                        CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);\n+                        CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));\n                     else if (opcode == OP_SHA256)\n-                        CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);\n+                        CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));\n                     else if (opcode == OP_HASH160)\n-                        CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);\n+                        CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));\n                     else if (opcode == OP_HASH256)\n-                        CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);\n+                        CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));\n                     popstack(stack);\n                     stack.push_back(vchHash);\n                 }\n-                break;\n+                break;                                   \n \n                 case OP_CODESEPARATOR:\n                 {\ndiff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp\nindex fe68e9e97..58fffb6df 100644\n--- a/src/test/base58_tests.cpp\n+++ b/src/test/base58_tests.cpp\n@@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)\n         std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());\n         std::string base58string = test[1].get_str();\n         BOOST_CHECK_MESSAGE(\n-                    EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,\n+                    EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string,\n                     strTest);\n     }\n }\n', 'commit_subject': 'script: Fix reference into empty vector run time exception', 'repo_name': 'zcoinofficial/zcoin', 'committer': {'name': 'Wladimir J. van der Laan', 'email': 'bbc07dc96bb50bf6868a2ddfc4dae14fbed703d9@gmail.com', 'time_sec': '1411638412', 'tz_offset': '120', 'date': {'seconds': '1411638412'}}, 'commit_tree': 'c221e25eb0dffeebbf4bbdb81bf9ee85099843c4', 'commit_message': 'script: Fix reference into empty vector run time exception\n\nEdit by laanwj: `begin_ptr(sourcedata) + sourcedata.size()` -> `end_ptr(sourcedata)`\n', 'language_name': 'C++', 'license': 'mit', 'hunks': '@@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)\n         std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());\n         std::string base58string = test[1].get_str();\n         BOOST_CHECK_MESSAGE(\n-                    EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,\n+                    EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string,\n                     strTest);\n     }\n }\n', 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/src/test/base58_tests.cpp', 'tgt_file': 'b/src/test/base58_tests.cpp', 'file_extension': '.cpp', 'before_file': '// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include "base58.h"\n\n#include "data/base58_encode_decode.json.h"\n#include "data/base58_keys_invalid.json.h"\n#include "data/base58_keys_valid.json.h"\n\n#include "key.h"\n#include "script/script.h"\n#include "uint256.h"\n#include "util.h"\n#include "utilstrencodings.h"\n#include "test/test_bitcoin.h"\n\n#include <boost/foreach.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/test/included/unit_test.hpp>\n\n#include <univalue.h>\n\nextern UniValue read_json(const std::string& jsondata);\n\nstd::string bitcoin_address_to_firo(const std::string address) {\n    std::vector<unsigned char> vchTemp;\n    if(DecodeBase58(address.c_str(), vchTemp) && vchTemp.size() > 4) {\n        vchTemp.resize(vchTemp.size() - 4);\n        switch (vchTemp[0]) {\n        case 0:\n            vchTemp[0] = 82;\n            break;\n        case 5:\n            vchTemp[0] = 7;\n            break;\n        case 128:\n            vchTemp[0] = 210;\n            break;\n        std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());\n        std::string base58string = test[1].get_str();\n        BOOST_CHECK_MESSAGE(\n                    EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,\n                    strTest);\n    }\n}\n            vchTemp[0] = 185;\n            break;\n        }\n        return EncodeBase58Check(vchTemp);\n    }\n    return address;\n}\n\nBOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)\n\n// Goal: test low-level base58 encoding functionality\nBOOST_AUTO_TEST_CASE(base58_EncodeBase58)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 2) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR("Bad test: " << strTest);\n            continue;\n        }\n        std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());\n        std::string base58string = test[1].get_str();\n        BOOST_CHECK_MESSAGE(\n                    EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()) == base58string,\n                    strTest);\n    }\n}\n\n// Goal: test low-level base58 decoding functionality\nBOOST_AUTO_TEST_CASE(base58_DecodeBase58)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));\n    std::vector<unsigned char> result;\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 2) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR("Bad test: " << strTest);\n            continue;\n        }\n        std::vector<unsigned char> expected = ParseHex(test[0].get_str());\n        std::string base58string = test[1].get_str();\n        BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest);\n        BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);\n    }\n\n    BOOST_CHECK(!DecodeBase58("invalid", result));\n\n    // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end.\n    BOOST_CHECK(!DecodeBase58(" \\t\\n\\v\\f\\r skip \\r\\f\\v\\n\\t a", result));\n    BOOST_CHECK( DecodeBase58(" \\t\\n\\v\\f\\r skip \\r\\f\\v\\n\\t ", result));\n    std::vector<unsigned char> expected = ParseHex("971a55");\n    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());\n}\n\n// Visitor to check address type\nclass TestAddrTypeVisitor : public boost::static_visitor<bool>\n{\nprivate:\n    std::string exp_addrType;\npublic:\n    TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }\n    bool operator()(const CKeyID &id) const\n    {\n        return (exp_addrType == "pubkey");\n    }\n    bool operator()(const CScriptID &id) const\n    {\n        return (exp_addrType == "script");\n    }\n    bool operator()(const CNoDestination &no) const\n    {\n        return (exp_addrType == "none");\n    }\n};\n\n// Visitor to check address payload\nclass TestPayloadVisitor : public boost::static_visitor<bool>\n{\nprivate:\n    std::vector<unsigned char> exp_payload;\npublic:\n    TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }\n    bool operator()(const CKeyID &id) const\n    {\n        uint160 exp_key(exp_payload);\n        return exp_key == id;\n    }\n    bool operator()(const CScriptID &id) const\n    {\n        uint160 exp_key(exp_payload);\n        return exp_key == id;\n    }\n    bool operator()(const CNoDestination &no) const\n    {\n        return exp_payload.size() == 0;\n    }\n};\n\n// Goal: check that parsed keys match test payload\nBOOST_AUTO_TEST_CASE(base58_keys_valid_parse)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));\n    CBitcoinSecret secret;\n    CBitcoinAddress addr;\n    SelectParams(CBaseChainParams::MAIN);\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 3) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR("Bad test: " << strTest);\n            continue;\n        }\n        std::string exp_base58string = test[0].get_str();\n        std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());\n        const UniValue &metadata = test[2].get_obj();\n        bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();\n        bool isTestnet = find_value(metadata, "isTestnet").get_bool();\n        if (isTestnet)\n            SelectParams(CBaseChainParams::TESTNET);\n        else\n            SelectParams(CBaseChainParams::MAIN);\n        if(isPrivkey)\n        {\n            bool isCompressed = find_value(metadata, "isCompressed").get_bool();\n            // Must be valid private key\n            // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!\n            BOOST_CHECK_MESSAGE(secret.SetString(bitcoin_address_to_firo(exp_base58string)), "!SetString:"+ strTest);\n            BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);\n            CKey privkey = secret.GetKey();\n            BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);\n            BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);\n\n            // Private key must be invalid public key\n            addr.SetString(bitcoin_address_to_firo(exp_base58string));\n            BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);\n        }\n        else\n        {\n            std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"\n            // Must be valid public key\n            BOOST_CHECK_MESSAGE(addr.SetString(bitcoin_address_to_firo(exp_base58string)), "SetString:" + strTest);\n            BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);\n            BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);\n            CTxDestination dest = addr.Get();\n            BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);\n\n            // Public key must be invalid private key\n            secret.SetString(exp_base58string);\n            BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);\n        }\n    }\n}\n\n// Goal: check that generated keys match test vectors\nBOOST_AUTO_TEST_CASE(base58_keys_valid_gen)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 3) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR("Bad test: " << strTest);\n            continue;\n        }\n        std::string exp_base58string = test[0].get_str();\n        std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());\n        const UniValue &metadata = test[2].get_obj();\n        bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();\n        bool isTestnet = find_value(metadata, "isTestnet").get_bool();\n        if (isTestnet)\n            SelectParams(CBaseChainParams::TESTNET);\n        else\n            SelectParams(CBaseChainParams::MAIN);\n        if(isPrivkey)\n        {\n            bool isCompressed = find_value(metadata, "isCompressed").get_bool();\n            CKey key;\n            key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);\n            assert(key.IsValid());\n            CBitcoinSecret secret;\n            secret.SetKey(key);\n            BOOST_CHECK_MESSAGE(secret.ToString() == bitcoin_address_to_firo(exp_base58string), "result mismatch: " + strTest);\n        }\n        else\n        {\n            std::string exp_addrType = find_value(metadata, "addrType").get_str();\n            CTxDestination dest;\n            if(exp_addrType == "pubkey")\n            {\n                dest = CKeyID(uint160(exp_payload));\n            }\n            else if(exp_addrType == "script")\n            {\n                dest = CScriptID(uint160(exp_payload));\n            }\n            else if(exp_addrType == "none")\n            {\n                dest = CNoDestination();\n            }\n            else\n            {\n                BOOST_ERROR("Bad addrtype: " << strTest);\n                continue;\n            }\n            CBitcoinAddress addrOut;\n            BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);\n            BOOST_CHECK_MESSAGE(addrOut.ToString() == bitcoin_address_to_firo(exp_base58string), "mismatch: " + strTest);\n        }\n    }\n\n    // Visiting a CNoDestination must fail\n    CBitcoinAddress dummyAddr;\n    CTxDestination nodest = CNoDestination();\n    BOOST_CHECK(!dummyAddr.Set(nodest));\n\n    SelectParams(CBaseChainParams::MAIN);\n}\n\n// Goal: check that base58 parsing code is robust against a variety of corrupted data\nBOOST_AUTO_TEST_CASE(base58_keys_invalid)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases\n    CBitcoinSecret secret;\n    CBitcoinAddress addr;\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 1) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR("Bad test: " << strTest);\n            continue;\n        }\n        std::string exp_base58string = test[0].get_str();\n\n        // must be invalid as public and as private key\n        addr.SetString(exp_base58string);\n        BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);\n        secret.SetString(exp_base58string);\n        BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);\n    }\n}\n\n\nBOOST_AUTO_TEST_SUITE_END()\n\n', 'message': 'script: Fix reference into empty vector run time exception\n\nEdit by laanwj: `begin_ptr(sourcedata) + sourcedata.size()` -> `end_ptr(sourcedata)`\n', 'author_name': 'Wladimir J. van der Laan', 'lang': 'cpp'}