// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Original code was distributed under the MIT software license.
// Copyright (c) 2014-2019 Coin Sciences Ltd
// MultiChain code distributed under the GPLv3 license, see COPYING file.

#include "wallet_ismine.h"

#include "keys/key.h"
#include "keystore.h"
#include "script/script.h"
#include "script/standard.h"

#include <boost/foreach.hpp>

using namespace std;

typedef vector<unsigned char> valtype;

unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
{
    unsigned int nResult = 0;
    BOOST_FOREACH(const valtype& pubkey, pubkeys)
    {
        CKeyID keyID = CPubKey(pubkey).GetID();
        if (keystore.HaveKey(keyID))
            ++nResult;
    }
    return nResult;
}

isminetype IsMineKeyID(const CKeyStore& keystore, const CKeyID& dest)
{
    if (keystore.HaveKey(dest))
        return ISMINE_SPENDABLE;
    if (keystore.HaveWatchOnly(GetScriptForDestination(dest)))
        return ISMINE_WATCH_ONLY;
    return ISMINE_NO;    
}

isminetype IsMineScriptID(const CKeyStore& keystore, const CScriptID& dest)
{
    CScript subscript;
    if (keystore.GetCScript(dest, subscript)) {
        isminetype ret = IsMine(keystore, subscript);
        if (ret == ISMINE_SPENDABLE)
            return ret;
    }    
    if (keystore.HaveWatchOnly(GetScriptForDestination(dest)))
        return ISMINE_WATCH_ONLY;
    return ISMINE_NO;    
}

isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
{
    CScript script = GetScriptForDestination(dest);
    return IsMine(keystore, script);
}

isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
    vector<valtype> vSolutions;
    txnouttype whichType;
    if (!TemplateSolver(scriptPubKey, whichType, vSolutions)) {
/* MCHN START */        
//        if (keystore.HaveWatchOnly(scriptPubKey))
        if (keystore.HaveWatchOnly(scriptPubKey.RemoveOpDrops()))
/* MCHN END */        
            return ISMINE_WATCH_ONLY;
        return ISMINE_NO;
    }

    
    CKeyID keyID;
    switch (whichType)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        break;
    case TX_PUBKEY:
        keyID = CPubKey(vSolutions[0]).GetID();
        if (keystore.HaveKey(keyID))
            return ISMINE_SPENDABLE;
        break;
    case TX_PUBKEYHASH:
        keyID = CKeyID(uint160(vSolutions[0]));
        if (keystore.HaveKey(keyID))
            return ISMINE_SPENDABLE;
        break;
    case TX_SCRIPTHASH:
    {
        CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
        CScript subscript;
        if (keystore.GetCScript(scriptID, subscript)) {
            isminetype ret = IsMine(keystore, subscript);
            if (ret == ISMINE_SPENDABLE)
                return ret;
        }
        break;
    }
    case TX_MULTISIG:
    {
        // Only consider transactions "mine" if we own ALL the
        // keys involved. multi-signature transactions that are
        // partially owned (somebody else has a key that can spend
        // them) enable spend-out-from-under-you attacks, especially
        // in shared-wallet situations.
        vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
        if (HaveKeys(keys, keystore) == keys.size())
            return ISMINE_SPENDABLE;
        break;
    }
    }

/* MCHN START */        
//    if (keystore.HaveWatchOnly(scriptPubKey))
    if (keystore.HaveWatchOnly(scriptPubKey.RemoveOpDrops()))
/* MCHN END */        
        return ISMINE_WATCH_ONLY;
    return ISMINE_NO;
}
