Rewrite time locks, coinbase validation, and script functions in C++ for easier integration
This commit is contained in:
@@ -1466,6 +1466,140 @@ bool CWallet::IsMine(const CTransaction& tx) const
|
||||
return false;
|
||||
}
|
||||
|
||||
// special case handling for CLTV scripts, this does not error check to ensure the script is CLTV and is
|
||||
// only internal to the wallet for that reason. if it is the first time we see this script, we add it to the wallet.
|
||||
isminetype CWallet::IsCLTVMine(CScriptExt &script, CScriptID &scriptID, int64_t locktime)
|
||||
{
|
||||
uint8_t pushOp = script.data()[0];
|
||||
uint32_t scriptStart = pushOp + 2;
|
||||
|
||||
// check post CLTV script
|
||||
CScriptExt postfix = CScriptExt(script.size() > scriptStart ? script.begin() + scriptStart : script.end(), script.end());
|
||||
|
||||
// check again with postfix subscript
|
||||
isminetype ret = ::IsMine(*this, postfix);
|
||||
if (ret != ISMINE_NO)
|
||||
{
|
||||
// once we get here, we should have this script in our
|
||||
// wallet, either as watch only if still time locked, or spendable
|
||||
if (!chainActive.Tip()->nHeight >= locktime)
|
||||
{
|
||||
ret = ISMINE_WATCH_ONLY;
|
||||
if (!this->HaveWatchOnly(script))
|
||||
{
|
||||
this->AddWatchOnly(script);
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (this->HaveWatchOnly(script))
|
||||
this->RemoveWatchOnly(script);
|
||||
if (!this->HaveCScript(scriptID))
|
||||
this->AddCScript(script);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore);
|
||||
|
||||
// special case handling for non-standard/Verus OP_RETURN script outputs, which need the transaction
|
||||
// to determine ownership
|
||||
isminetype CWallet::IsMine(const CTransaction& tx, uint32_t voutNum)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
const CScriptExt scriptPubKey = CScriptExt(tx.vout[voutNum].scriptPubKey);
|
||||
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions)) {
|
||||
if (this->HaveWatchOnly(scriptPubKey))
|
||||
return ISMINE_WATCH_ONLY;
|
||||
return ISMINE_NO;
|
||||
}
|
||||
|
||||
CKeyID keyID;
|
||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
CScriptExt subscript;
|
||||
int voutNext = voutNum + 1;
|
||||
|
||||
switch (whichType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
break;
|
||||
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
if (this->HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (this->HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
|
||||
case TX_SCRIPTHASH:
|
||||
if (this->GetCScript(scriptID, subscript))
|
||||
{
|
||||
// if this is a CLTV, handle it differently
|
||||
int64_t lockTime;
|
||||
if (subscript.IsCheckLockTimeVerify(&lockTime))
|
||||
{
|
||||
return this->IsCLTVMine(subscript, scriptID, lockTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
isminetype ret = ::IsMine(*this, subscript);
|
||||
if (ret == ISMINE_SPENDABLE)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (tx.vout.size() > (voutNext = voutNum + 1) &&
|
||||
tx.vout[voutNext].scriptPubKey.size() > 7 &&
|
||||
tx.vout[voutNext].scriptPubKey.data()[0] == OP_RETURN)
|
||||
{
|
||||
// get the opret script from next vout, verify that the front is CLTV and hash matches
|
||||
// if so, remove it and use the solver
|
||||
opcodetype op;
|
||||
std::vector<uint8_t> opretData;
|
||||
CScript::const_iterator it = tx.vout[voutNext].scriptPubKey.begin() + 1;
|
||||
if (tx.vout[voutNext].scriptPubKey.GetOp2(it, op, &opretData))
|
||||
{
|
||||
if (opretData.size() > 0 && opretData.data()[0] == OPRETTYPE_TIMELOCK)
|
||||
{
|
||||
int64_t unlocktime;
|
||||
CScriptExt opretScript = CScriptExt(opretData.begin() + 1, opretData.end());
|
||||
|
||||
if (CScriptID(opretScript) == scriptID &&
|
||||
opretScript.IsCheckLockTimeVerify(&unlocktime))
|
||||
{
|
||||
return this->IsCLTVMine(opretScript, scriptID, unlocktime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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, *this) == keys.size())
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->HaveWatchOnly(scriptPubKey))
|
||||
return ISMINE_WATCH_ONLY;
|
||||
|
||||
return ISMINE_NO;
|
||||
}
|
||||
|
||||
bool CWallet::IsFromMe(const CTransaction& tx) const
|
||||
{
|
||||
if (GetDebit(tx, ISMINE_ALL) > 0) {
|
||||
|
||||
Reference in New Issue
Block a user