Skip to content

Commit 9c84fb3

Browse files
Add staking on p2sh addresses
1 parent e107b0b commit 9c84fb3

File tree

3 files changed

+74
-23
lines changed

3 files changed

+74
-23
lines changed

src/miner.cpp

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -590,33 +590,71 @@ bool CreateCoinStake(CMutableTransaction& coinstakeTx, CBlock* pblock, std::shar
590590
if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false))
591591
LogPrintf("%s : parsed kernel type=%s\n", __func__, GetTxnOutputType(whichType));
592592

593-
if (whichType != TxoutType::PUBKEY && gArgs.GetBoolArg("-quantumsafestaking", false)) {
594-
OutputType output_type = OutputType::BECH32;
595-
CTxDestination dest;
596-
std::string error;
597-
if (pwallet->GetNewChangeDestination(output_type, dest, error)) {
598-
LogPrintf("%s : using new destination for coinstake (%s)\n", __func__, EncodeDestination(dest));
599-
scriptPubKeyOut = GetScriptForDestination(dest);
600-
} else {
601-
LogPrintf("%s : failed to get new destination for coinstake (%s)\n", __func__, error);
593+
if (whichType == TxoutType::PUBKEYHASH || whichType == TxoutType::WITNESS_V0_KEYHASH || whichType == TxoutType::SCRIPTHASH) { // we support p2pkh, p2wpkh, and p2sh-p2wpkh inputs
594+
if (whichType == TxoutType::SCRIPTHASH) { // a p2sh input could be many things, but we only support p2sh-p2wpkh for now
595+
CScript subscript;
596+
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKeyKernel);
597+
if (provider && provider->GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) { // extract the redeem script
598+
TxoutType scriptType = Solver(subscript, vSolutions);
599+
if (scriptType != TxoutType::WITNESS_V0_KEYHASH || Params().NetworkIDString() == CBaseChainParams::MAIN) { // this is a script we don't recognize
600+
if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false))
601+
LogPrintf("%s : no support for %s kernel type=%s\n", __func__, GetTxnOutputType(whichType), GetTxnOutputType(scriptType));
602+
continue;
603+
}
604+
whichType = scriptType;
605+
} else {
606+
if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false))
607+
LogPrintf("%s : failed to get script for kernel type=%s\n", __func__, GetTxnOutputType(whichType));
608+
continue; // unable to find corresponding script
609+
}
610+
}
611+
612+
if (gArgs.GetBoolArg("-quantumsafestaking", false)) { // a new bech32 address is generated for every stake to protect the public key from quantum computers
613+
OutputType output_type = OutputType::BECH32;
614+
CTxDestination dest;
615+
std::string error;
616+
if (pwallet->GetNewChangeDestination(output_type, dest, error)) {
617+
LogPrintf("%s : using new destination for coinstake (%s)\n", __func__, EncodeDestination(dest));
618+
scriptPubKeyOut = GetScriptForDestination(dest);
619+
} else {
620+
LogPrintf("%s : failed to get new destination for coinstake (%s)\n", __func__, error);
621+
scriptPubKeyOut = scriptPubKeyKernel;
622+
}
623+
} else if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { // on legacy wallets we can convert every input to p2pk for smaller coinstake TXs
624+
// convert to pay to public key type
625+
CPubKey pubkey;
626+
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKeyKernel);
627+
if (!provider || !provider->GetPubKey(CKeyID(uint160(vSolutions[0])), pubkey)) {
628+
if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false))
629+
LogPrintf("%s : failed to get key for kernel type=%s\n", __func__, GetTxnOutputType(whichType));
630+
continue; // unable to find corresponding public key
631+
}
632+
scriptPubKeyOut << ToByteVector(pubkey) << OP_CHECKSIG;
633+
} else { // descriptor wallets only credit earnings back to the original address
602634
scriptPubKeyOut = scriptPubKeyKernel;
603635
}
604-
} else if ((whichType == TxoutType::PUBKEYHASH || whichType == TxoutType::WITNESS_V0_KEYHASH) && !pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { // pay to address type or witness keyhash
636+
} else if (whichType == TxoutType::PUBKEY) { // p2pk inputs can be left alone
637+
scriptPubKeyOut = scriptPubKeyKernel;
638+
} else if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && (whichType == TxoutType::MULTISIG || whichType == TxoutType::MULTISIG_DATA)) { // convert multisig to p2pk
605639
// convert to pay to public key type
606640
CPubKey pubkey;
607-
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKeyKernel);
608-
if (!provider || !provider->GetPubKey(CKeyID(uint160(vSolutions[0])), pubkey)) {
641+
bool found = false;
642+
if (vSolutions.size() == 3 && vSolutions.front()[0] == 1 && vSolutions.back()[0] == 1) { // only support single pubkey multisig for now
643+
pubkey = CPubKey(vSolutions[1]);
644+
if (pubkey.IsValid())
645+
found = true;
646+
}
647+
if (found) {
648+
scriptPubKeyOut << ToByteVector(pubkey) << OP_CHECKSIG;
649+
} else {
609650
if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false))
610651
LogPrintf("%s : failed to get key for kernel type=%s\n", __func__, GetTxnOutputType(whichType));
611-
continue; // unable to find corresponding public key
652+
continue; // unable to find corresponding public key
612653
}
613-
scriptPubKeyOut << ToByteVector(pubkey) << OP_CHECKSIG;
614-
} else if (whichType == TxoutType::PUBKEY || (pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && (whichType == TxoutType::PUBKEYHASH || whichType == TxoutType::WITNESS_V0_KEYHASH))) {
615-
scriptPubKeyOut = scriptPubKeyKernel;
616654
} else {
617655
if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false))
618656
LogPrintf("%s : no support for kernel type=%s\n", __func__, GetTxnOutputType(whichType));
619-
continue; // only support pay to public key and pay to address and pay to witness keyhash
657+
continue; // only support p2pk, p2pkh, p2wpkh, and p2sh-p2wpkh
620658
}
621659

622660
coinstakeTx.vin.push_back(CTxIn(prevout.hash, prevout.n));

src/validation.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5735,13 +5735,12 @@ bool CheckBlockSignature(const CBlock& block)
57355735
CPubKey pubkey;
57365736

57375737
if (whichType == TxoutType::PUBKEY) {
5738-
const std::vector<unsigned char>& vchPubKey = vSolutions[0];
5739-
pubkey = CPubKey(vchPubKey);
5738+
pubkey = CPubKey(vSolutions[0]);
57405739
} else {
57415740
if (block.IsProofOfWork()) // no inputs for coinbase
57425741
return false;
57435742
const CTxIn& txin = block.vtx[1]->vin[0];
5744-
if (txin.scriptSig.size() == 0 && txin.scriptWitness.stack.size() == 2 && txin.scriptWitness.stack.back().size() == CPubKey::COMPRESSED_SIZE) { // p2wpkh input
5743+
if ((txin.scriptSig.size() == 0 || txin.scriptSig.size() == 23) && txin.scriptWitness.stack.size() == 2 && txin.scriptWitness.stack.back().size() == CPubKey::COMPRESSED_SIZE) { // p2wpkh or p2sh-p2wpkh input
57455744
pubkey = CPubKey(txin.scriptWitness.stack.back());
57465745
} else if (txin.scriptWitness.stack.size() == 0 && txin.scriptSig.size() >= 70 && txin.scriptSig.size() <= 140 && txin.scriptSig.IsPushOnly() && txin.scriptSig[0] >= 70 && txin.scriptSig[0] <= 73) { // p2pkh input (sig + pubkey)
57475746
unsigned int pubkeyStart = txin.scriptSig[0] + 2u; // skip sig and length bytes by reading sig length from pushdata

src/wallet/wallet.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4646,13 +4646,27 @@ bool CWallet::SignBlock(CBlock& block) const
46464646
TxoutType whichType = Solver(scriptPubKey, vSolutions);
46474647

46484648
// Sign
4649-
const std::vector<unsigned char>& vchPubKey = vSolutions[0];
46504649
CPubKey pubkey;
46514650
if (whichType == TxoutType::PUBKEY) {
4652-
pubkey = CPubKey(vchPubKey);
4651+
pubkey = CPubKey(vSolutions[0]);
46534652
} else if (whichType == TxoutType::PUBKEYHASH || whichType == TxoutType::WITNESS_V0_KEYHASH) {
46544653
std::unique_ptr<SigningProvider> provider = GetSolvingProvider(scriptPubKey);
4655-
if (!provider || !provider->GetPubKey(CKeyID(uint160(vchPubKey)), pubkey))
4654+
if (!provider || !provider->GetPubKey(CKeyID(uint160(vSolutions[0])), pubkey))
4655+
return false;
4656+
} else if (whichType == TxoutType::SCRIPTHASH) {
4657+
CScript subscript;
4658+
std::unique_ptr<SigningProvider> provider = GetSolvingProvider(scriptPubKey);
4659+
if (provider && provider->GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) {
4660+
whichType = Solver(subscript, vSolutions);
4661+
if (whichType != TxoutType::WITNESS_V0_KEYHASH || !provider->GetPubKey(CKeyID(uint160(vSolutions[0])), pubkey))
4662+
return false;
4663+
} else
4664+
return false;
4665+
} else if (whichType == TxoutType::MULTISIG || whichType == TxoutType::MULTISIG_DATA) {
4666+
if (vSolutions.size() != 3 || vSolutions.front()[0] != 1 || vSolutions.back()[0] != 1)
4667+
return false;
4668+
pubkey = CPubKey(vSolutions[1]);
4669+
if (!pubkey.IsValid())
46564670
return false;
46574671
} else {
46584672
return false;

0 commit comments

Comments
 (0)