Skip to content

Commit bb582a5

Browse files
committed
Add P2WSH destination helper and use it instead of manual hashing
1 parent eaba1c1 commit bb582a5

File tree

5 files changed

+39
-109
lines changed

5 files changed

+39
-109
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -637,9 +637,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
637637
} else {
638638
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
639639
// Newer segwit program versions should be considered when then become available.
640-
uint256 scriptHash;
641-
CSHA256().Write(script.data(), script.size()).Finalize(scriptHash.begin());
642-
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(scriptHash));
640+
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
643641
}
644642
ScriptPubKeyToUniv(segwitScr, sr, true);
645643
sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr)));

src/script/standard.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <script/standard.h>
77

8+
#include <crypto/sha256.h>
89
#include <pubkey.h>
910
#include <script/script.h>
1011
#include <util.h>
@@ -18,6 +19,11 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
1819

1920
CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
2021

22+
WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
23+
{
24+
CSHA256().Write(in.data(), in.size()).Finalize(begin());
25+
}
26+
2127
const char* GetTxnOutputType(txnouttype t)
2228
{
2329
switch (t)
@@ -329,9 +335,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
329335
return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
330336
}
331337
}
332-
uint256 hash;
333-
CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin());
334-
return GetScriptForDestination(WitnessV0ScriptHash(hash));
338+
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
335339
}
336340

337341
bool IsValidDestination(const CTxDestination& dest) {

src/script/standard.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct WitnessV0ScriptHash : public uint256
7777
{
7878
WitnessV0ScriptHash() : uint256() {}
7979
explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {}
80+
explicit WitnessV0ScriptHash(const CScript& script);
8081
using uint256::uint256;
8182
};
8283

src/test/script_standard_tests.cpp

Lines changed: 29 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
402402
// P2PK compressed
403403
{
404404
CBasicKeyStore keystore;
405-
scriptPubKey.clear();
406-
scriptPubKey << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
405+
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
407406

408407
// Keystore does not have key
409408
result = IsMine(keystore, scriptPubKey);
@@ -418,8 +417,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
418417
// P2PK uncompressed
419418
{
420419
CBasicKeyStore keystore;
421-
scriptPubKey.clear();
422-
scriptPubKey << ToByteVector(uncompressedPubkey) << OP_CHECKSIG;
420+
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
423421

424422
// Keystore does not have key
425423
result = IsMine(keystore, scriptPubKey);
@@ -434,8 +432,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
434432
// P2PKH compressed
435433
{
436434
CBasicKeyStore keystore;
437-
scriptPubKey.clear();
438-
scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
435+
scriptPubKey = GetScriptForDestination(pubkeys[0].GetID());
439436

440437
// Keystore does not have key
441438
result = IsMine(keystore, scriptPubKey);
@@ -450,8 +447,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
450447
// P2PKH uncompressed
451448
{
452449
CBasicKeyStore keystore;
453-
scriptPubKey.clear();
454-
scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(uncompressedPubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
450+
scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID());
455451

456452
// Keystore does not have key
457453
result = IsMine(keystore, scriptPubKey);
@@ -467,11 +463,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
467463
{
468464
CBasicKeyStore keystore;
469465

470-
CScript redeemScript;
471-
redeemScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
472-
473-
scriptPubKey.clear();
474-
scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
466+
CScript redeemScript = GetScriptForDestination(pubkeys[0].GetID());
467+
scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
475468

476469
// Keystore does not have redeemScript or key
477470
result = IsMine(keystore, scriptPubKey);
@@ -492,12 +485,9 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
492485
{
493486
CBasicKeyStore keystore;
494487

495-
CScript redeemscript, redeemscript_inner;
496-
redeemscript_inner << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
497-
redeemscript << OP_HASH160 << ToByteVector(CScriptID(redeemscript_inner)) << OP_EQUAL;
498-
499-
scriptPubKey.clear();
500-
scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL;
488+
CScript redeemscript_inner = GetScriptForDestination(pubkeys[0].GetID());
489+
CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner));
490+
scriptPubKey = GetScriptForDestination(CScriptID(redeemscript));
501491

502492
keystore.AddCScript(redeemscript);
503493
keystore.AddCScript(redeemscript_inner);
@@ -511,14 +501,9 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
511501
{
512502
CBasicKeyStore keystore;
513503

514-
CScript witnessscript, redeemscript;
515-
redeemscript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
516-
witnessscript << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL;
517-
518-
uint256 scripthash;
519-
CSHA256().Write(witnessscript.data(), witnessscript.size()).Finalize(scripthash.begin());
520-
scriptPubKey.clear();
521-
scriptPubKey << OP_0 << ToByteVector(scripthash);
504+
CScript redeemscript = GetScriptForDestination(pubkeys[0].GetID());
505+
CScript witnessscript = GetScriptForDestination(CScriptID(redeemscript));
506+
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
522507

523508
keystore.AddCScript(witnessscript);
524509
keystore.AddCScript(redeemscript);
@@ -532,13 +517,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
532517
{
533518
CBasicKeyStore keystore;
534519

535-
CScript witnessscript;
536-
witnessscript << OP_0 << ToByteVector(pubkeys[0].GetID());
537-
538-
scriptPubKey.clear();
539-
uint256 scripthash;
540-
CSHA256().Write(witnessscript.data(), witnessscript.size()).Finalize(scripthash.begin());
541-
scriptPubKey << OP_0 << ToByteVector(scripthash);
520+
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID()));
521+
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
542522

543523
keystore.AddCScript(witnessscript);
544524
keystore.AddCScript(scriptPubKey);
@@ -551,16 +531,9 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
551531
{
552532
CBasicKeyStore keystore;
553533

554-
CScript witnessscript_inner;
555-
witnessscript_inner << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
556-
uint256 scripthash;
557-
CSHA256().Write(witnessscript_inner.data(), witnessscript_inner.size()).Finalize(scripthash.begin());
558-
CScript witnessscript;
559-
witnessscript << OP_0 << ToByteVector(scripthash);
560-
561-
scriptPubKey.clear();
562-
CSHA256().Write(witnessscript.data(), witnessscript.size()).Finalize(scripthash.begin());
563-
scriptPubKey << OP_0 << ToByteVector(scripthash);
534+
CScript witnessscript_inner = GetScriptForDestination(pubkeys[0].GetID());
535+
CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
536+
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
564537

565538
keystore.AddCScript(witnessscript_inner);
566539
keystore.AddCScript(witnessscript);
@@ -575,8 +548,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
575548
CBasicKeyStore keystore;
576549
keystore.AddKey(keys[0]);
577550

578-
scriptPubKey.clear();
579-
scriptPubKey << OP_0 << ToByteVector(pubkeys[0].GetID());
551+
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID()));
580552

581553
// Keystore implicitly has key and P2SH redeemScript
582554
keystore.AddCScript(scriptPubKey);
@@ -589,8 +561,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
589561
CBasicKeyStore keystore;
590562
keystore.AddKey(uncompressedKey);
591563

592-
scriptPubKey.clear();
593-
scriptPubKey << OP_0 << ToByteVector(uncompressedPubkey.GetID());
564+
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey.GetID()));
594565

595566
// Keystore has key, but no P2SH redeemScript
596567
result = IsMine(keystore, scriptPubKey);
@@ -606,11 +577,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
606577
{
607578
CBasicKeyStore keystore;
608579

609-
scriptPubKey.clear();
610-
scriptPubKey << OP_2 <<
611-
ToByteVector(uncompressedPubkey) <<
612-
ToByteVector(pubkeys[1]) <<
613-
OP_2 << OP_CHECKMULTISIG;
580+
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
614581

615582
// Keystore does not have any keys
616583
result = IsMine(keystore, scriptPubKey);
@@ -641,14 +608,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
641608
keystore.AddKey(uncompressedKey);
642609
keystore.AddKey(keys[1]);
643610

644-
CScript redeemScript;
645-
redeemScript << OP_2 <<
646-
ToByteVector(uncompressedPubkey) <<
647-
ToByteVector(pubkeys[1]) <<
648-
OP_2 << OP_CHECKMULTISIG;
649-
650-
scriptPubKey.clear();
651-
scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
611+
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
612+
scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
652613

653614
// Keystore has no redeemScript
654615
result = IsMine(keystore, scriptPubKey);
@@ -666,18 +627,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
666627
keystore.AddKey(keys[0]);
667628
keystore.AddKey(keys[1]);
668629

669-
CScript witnessScript;
670-
witnessScript << OP_2 <<
671-
ToByteVector(pubkeys[0]) <<
672-
ToByteVector(pubkeys[1]) <<
673-
OP_2 << OP_CHECKMULTISIG;
674-
675-
uint256 scriptHash;
676-
CSHA256().Write(&witnessScript[0], witnessScript.size())
677-
.Finalize(scriptHash.begin());
678-
679-
scriptPubKey.clear();
680-
scriptPubKey << OP_0 << ToByteVector(scriptHash);
630+
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
631+
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
681632

682633
// Keystore has keys, but no witnessScript or P2SH redeemScript
683634
result = IsMine(keystore, scriptPubKey);
@@ -700,18 +651,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
700651
keystore.AddKey(uncompressedKey);
701652
keystore.AddKey(keys[1]);
702653

703-
CScript witnessScript;
704-
witnessScript << OP_2 <<
705-
ToByteVector(uncompressedPubkey) <<
706-
ToByteVector(pubkeys[1]) <<
707-
OP_2 << OP_CHECKMULTISIG;
708-
709-
uint256 scriptHash;
710-
CSHA256().Write(&witnessScript[0], witnessScript.size())
711-
.Finalize(scriptHash.begin());
712-
713-
scriptPubKey.clear();
714-
scriptPubKey << OP_0 << ToByteVector(scriptHash);
654+
CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
655+
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
715656

716657
// Keystore has keys, but no witnessScript or P2SH redeemScript
717658
result = IsMine(keystore, scriptPubKey);
@@ -732,21 +673,9 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
732673
{
733674
CBasicKeyStore keystore;
734675

735-
CScript witnessScript;
736-
witnessScript << OP_2 <<
737-
ToByteVector(pubkeys[0]) <<
738-
ToByteVector(pubkeys[1]) <<
739-
OP_2 << OP_CHECKMULTISIG;
740-
741-
uint256 scriptHash;
742-
CSHA256().Write(&witnessScript[0], witnessScript.size())
743-
.Finalize(scriptHash.begin());
744-
745-
CScript redeemScript;
746-
redeemScript << OP_0 << ToByteVector(scriptHash);
747-
748-
scriptPubKey.clear();
749-
scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
676+
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
677+
CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
678+
scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
750679

751680
// Keystore has no witnessScript, P2SH redeemScript, or keys
752681
result = IsMine(keystore, scriptPubKey);

src/wallet/wallet.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4520,9 +4520,7 @@ CTxDestination CWallet::AddAndGetDestinationForScript(const CScript& script, Out
45204520
return CScriptID(script);
45214521
case OutputType::P2SH_SEGWIT:
45224522
case OutputType::BECH32: {
4523-
WitnessV0ScriptHash hash;
4524-
CSHA256().Write(script.data(), script.size()).Finalize(hash.begin());
4525-
CTxDestination witdest = hash;
4523+
CTxDestination witdest = WitnessV0ScriptHash(script);
45264524
CScript witprog = GetScriptForDestination(witdest);
45274525
// Check if the resulting program is solvable (i.e. doesn't use an uncompressed key)
45284526
if (!IsSolvable(*this, witprog)) return CScriptID(script);

0 commit comments

Comments
 (0)