aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/script/ismine.cpp3
-rw-r--r--src/script/script.h1
-rw-r--r--src/script/script_error.cpp2
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/standard.cpp45
-rw-r--r--src/script/standard.h37
7 files changed, 88 insertions, 8 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 7315500e3b..77314e8cb2 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1175,6 +1175,8 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
+ assert(nIn < txTo.vin.size());
+
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
uint256 hashSequence;
@@ -1221,10 +1223,6 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
}
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
- if (nIn >= txTo.vin.size()) {
- // nIn out of range
- return one;
- }
// Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 0a39619734..6b68f0679e 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -46,6 +46,8 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)
{
+ isInvalid = false;
+
std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
@@ -59,6 +61,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
diff --git a/src/script/script.h b/src/script/script.h
index 587f2d26eb..2a92060543 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -420,6 +420,7 @@ public:
CScript& operator+=(const CScript& b)
{
+ reserve(size() + b.size());
insert(end(), b.begin(), b.end());
return *this;
}
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index c9d13c92a8..6c590f53e3 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -73,6 +73,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Witness version reserved for soft-fork upgrades";
case SCRIPT_ERR_PUBKEYTYPE:
return "Public key is neither compressed or uncompressed";
+ case SCRIPT_ERR_CLEANSTACK:
+ return "Extra items left on stack after execution";
case SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH:
return "Witness program has incorrect length";
case SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY:
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index dc50467d3f..ac58b690a2 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -79,6 +79,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
return false;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
@@ -309,6 +310,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
// Don't know anything about this, assume bigger one is correct:
if (sigs1.script.size() >= sigs2.script.size())
return sigs1;
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index b6e2232ab4..f57f1f61b4 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -30,6 +30,7 @@ const char* GetTxnOutputType(txnouttype t)
case TX_NULL_DATA: return "nulldata";
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
+ case TX_WITNESS_UNKNOWN: return "witness_unknown";
}
return nullptr;
}
@@ -75,6 +76,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
vSolutionsRet.push_back(witnessprogram);
return true;
}
+ if (witnessversion != 0) {
+ typeRet = TX_WITNESS_UNKNOWN;
+ vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
+ vSolutionsRet.push_back(std::move(witnessprogram));
+ return true;
+ }
return false;
}
@@ -198,6 +205,23 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
addressRet = CScriptID(uint160(vSolutions[0]));
return true;
+ } else if (whichType == TX_WITNESS_V0_KEYHASH) {
+ WitnessV0KeyHash hash;
+ std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
+ addressRet = hash;
+ return true;
+ } else if (whichType == TX_WITNESS_V0_SCRIPTHASH) {
+ WitnessV0ScriptHash hash;
+ std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
+ addressRet = hash;
+ return true;
+ } else if (whichType == TX_WITNESS_UNKNOWN) {
+ WitnessUnknown unk;
+ unk.version = vSolutions[0][0];
+ std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
+ unk.length = vSolutions[1].size();
+ addressRet = unk;
+ return true;
}
// Multisig txns have more than one address...
return false;
@@ -268,6 +292,27 @@ public:
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
}
+
+ bool operator()(const WitnessV0KeyHash& id) const
+ {
+ script->clear();
+ *script << OP_0 << ToByteVector(id);
+ return true;
+ }
+
+ bool operator()(const WitnessV0ScriptHash& id) const
+ {
+ script->clear();
+ *script << OP_0 << ToByteVector(id);
+ return true;
+ }
+
+ bool operator()(const WitnessUnknown& id) const
+ {
+ script->clear();
+ *script << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
+ return true;
+ }
};
} // namespace
diff --git a/src/script/standard.h b/src/script/standard.h
index 8df143a3a3..fa07ea88c1 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -64,6 +64,7 @@ enum txnouttype
TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
TX_WITNESS_V0_SCRIPTHASH,
TX_WITNESS_V0_KEYHASH,
+ TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
};
class CNoDestination {
@@ -72,14 +73,42 @@ public:
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};
+struct WitnessV0ScriptHash : public uint256 {};
+struct WitnessV0KeyHash : public uint160 {};
+
+//! CTxDestination subtype to encode any future Witness version
+struct WitnessUnknown
+{
+ unsigned int version;
+ unsigned int length;
+ unsigned char program[40];
+
+ friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
+ if (w1.version != w2.version) return false;
+ if (w1.length != w2.length) return false;
+ return std::equal(w1.program, w1.program + w1.length, w2.program);
+ }
+
+ friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
+ if (w1.version < w2.version) return true;
+ if (w1.version > w2.version) return false;
+ if (w1.length < w2.length) return true;
+ if (w1.length > w2.length) return false;
+ return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length);
+ }
+};
+
/**
* A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
- * * CKeyID: TX_PUBKEYHASH destination
- * * CScriptID: TX_SCRIPTHASH destination
+ * * CKeyID: TX_PUBKEYHASH destination (P2PKH)
+ * * CScriptID: TX_SCRIPTHASH destination (P2SH)
+ * * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
+ * * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
+ * * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
-typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
+typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);
@@ -104,7 +133,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
* Parse a standard scriptPubKey for the destination address. Assigns result to
* the addressRet parameter and returns true if successful. For multisig
* scripts, instead use ExtractDestinations. Currently only works for P2PK,
- * P2PKH, and P2SH scripts.
+ * P2PKH, P2SH, P2WPKH, and P2WSH scripts.
*/
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);