aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
authorWladimir J. van der Laan <[email protected]>2016-06-24 16:25:44 +0200
committerWladimir J. van der Laan <[email protected]>2016-06-24 18:07:44 +0200
commitd612837814020ae832499d18e6ee5eb919a87907 (patch)
treea93b5e382503577109efaa5cf7526e4dc378b7ea /src/script
parentMerge #8256: BUG: bitcoin-qt crash (diff)
parentBIP9 parameters for testnet (diff)
downloaddiscoin-d612837814020ae832499d18e6ee5eb919a87907.tar.xz
discoin-d612837814020ae832499d18e6ee5eb919a87907.zip
Merge #8149: Segregated witness rebased
f852813 BIP9 parameters for testnet (Johnson Lau) 070dbc4 --- [SEGWIT] begin: deployment --- (Pieter Wuille) fdb43df [qa] Add GetTransactionSigOpCost unit tests (Jonas Nick) d846e02 [qa] script_tests: witness tests can specify tx amount (Suhas Daftuar) 330b0f3 [qa] p2p segwit tests (Suhas Daftuar) 4f7ff00 [qa] Add rpc test for segwit (Alex Morcos) 66cca79 [qa] Autogeneration support for witness in script_tests (Pieter Wuille) 06d3805 [qa] Add segwit support to script_tests (Pieter Wuille) 00f46cb [qa] Add transaction tests for segwit (NicolasDorier) 0aa9207 [qa] Witness version 0 signing unit tests (Pieter Wuille) 978e200 --- [SEGWIT] begin: tests --- (Pieter Wuille) 745eb67 [RPC] signrawtransaction can sign P2WSH (NicolasDorier) f4691ab [RPC] Add wallet support for witness transactions (using P2SH) (Pieter Wuille) 605e847 BIP143: Signing logic (Pieter Wuille) 9757b57 --- [SEGWIT] begin: wallet --- (Pieter Wuille) af87a67 Do not use compact blocks when segwit is enabled (Pieter Wuille) 6032f69 Add rewind logic to deal with post-fork software updates (Pieter Wuille) b7dbeb2 [libconsensus] Script verification API with amounts (Thomas Kerin) 2b1f6f9 BIP141: Other consensus critical limits, and BIP145 (Pieter Wuille) 7c4bf77 [RPC] Return witness data in blockchain RPCs (Johnson Lau) 3dd4102 BIP143: Verification logic (Pieter Wuille) 0ef1dd3 Refactor script validation to observe amounts (Pieter Wuille) b8a9749 BIP144: Handshake and relay (receiver side) (Pieter Wuille) 8b49040 BIP141: Commitment structure and deployment (Pieter Wuille) 449f9b8 BIP141: Witness program (Pieter Wuille) 7030d9e BIP144: Serialization, hashes, relay (sender side) (Pieter Wuille) ecacfd9 --- [SEGWIT] begin: P2P/node/consensus --- (Pieter Wuille)
Diffstat (limited to 'src/script')
-rw-r--r--src/script/bitcoinconsensus.cpp29
-rw-r--r--src/script/bitcoinconsensus.h10
-rw-r--r--src/script/interpreter.cpp240
-rw-r--r--src/script/interpreter.h33
-rw-r--r--src/script/ismine.cpp19
-rw-r--r--src/script/script.cpp38
-rw-r--r--src/script/script.h16
-rw-r--r--src/script/script_error.cpp14
-rw-r--r--src/script/script_error.h9
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.cpp283
-rw-r--r--src/script/sign.h37
-rw-r--r--src/script/standard.cpp41
-rw-r--r--src/script/standard.h3
14 files changed, 650 insertions, 124 deletions
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 47ad1d080..62fd9031f 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -69,7 +69,7 @@ struct ECCryptoClosure
ECCryptoClosure instance_of_eccryptoclosure;
}
-int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
+static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
{
@@ -82,15 +82,36 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen)
return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
- // Regardless of the verification result, the tx did not error.
- set_error(err, bitcoinconsensus_ERR_OK);
+ // Regardless of the verification result, the tx did not error.
+ set_error(err, bitcoinconsensus_ERR_OK);
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount), NULL);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
}
+int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
+ const unsigned char *txTo , unsigned int txToLen,
+ unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
+{
+ CAmount am(amount);
+ return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
+}
+
+
+int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
+ const unsigned char *txTo , unsigned int txToLen,
+ unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
+{
+ if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
+ return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
+ }
+
+ CAmount am(0);
+ return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
+}
+
unsigned int bitcoinconsensus_version()
{
// Just use the API version for now
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 5b8c33c6b..6f868d0d6 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_BITCOINCONSENSUS_H
#define BITCOIN_BITCOINCONSENSUS_H
+#include <stdint.h>
+
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#if defined(_WIN32)
@@ -31,7 +33,7 @@
extern "C" {
#endif
-#define BITCOINCONSENSUS_API_VER 0
+#define BITCOINCONSENSUS_API_VER 1
typedef enum bitcoinconsensus_error_t
{
@@ -39,6 +41,7 @@ typedef enum bitcoinconsensus_error_t
bitcoinconsensus_ERR_TX_INDEX,
bitcoinconsensus_ERR_TX_SIZE_MISMATCH,
bitcoinconsensus_ERR_TX_DESERIALIZE,
+ bitcoinconsensus_ERR_AMOUNT_REQUIRED,
} bitcoinconsensus_error;
/** Script verification flags */
@@ -48,6 +51,7 @@ enum
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141)
};
/// Returns 1 if the input nIn of the serialized transaction pointed to by
@@ -55,6 +59,10 @@ enum
/// the additional constraints specified by flags.
/// If not NULL, err will contain an error/success code for the operation
EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
+ const unsigned char *txTo , unsigned int txToLen,
+ unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
+
+EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index fd4a5674c..bc027e9f0 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -229,7 +229,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@@ -869,13 +869,15 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
CScript scriptCode(pbegincodehash, pend);
// Drop the signature, since there's no way for a signature to sign itself
- scriptCode.FindAndDelete(CScript(vchSig));
+ if (sigversion == SIGVERSION_BASE) {
+ scriptCode.FindAndDelete(CScript(vchSig));
+ }
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
//serror is set
return false;
}
- bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode);
+ bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
popstack(stack);
popstack(stack);
@@ -925,7 +927,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
- scriptCode.FindAndDelete(CScript(vchSig));
+ if (sigversion == SIGVERSION_BASE) {
+ scriptCode.FindAndDelete(CScript(vchSig));
+ }
}
bool fSuccess = true;
@@ -943,7 +947,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
}
// Check signature
- bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode);
+ bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
if (fOk) {
isig++;
@@ -1106,8 +1110,64 @@ public:
} // anon namespace
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion)
{
+ if (sigversion == SIGVERSION_WITNESS_V0) {
+ uint256 hashPrevouts;
+ uint256 hashSequence;
+ uint256 hashOutputs;
+
+ if (!(nHashType & SIGHASH_ANYONECANPAY)) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].prevout;
+ }
+ hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ }
+
+ if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].nSequence;
+ }
+ hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ }
+
+ if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vout.size(); n++) {
+ ss << txTo.vout[n];
+ }
+ hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
+ CHashWriter ss(SER_GETHASH, 0);
+ ss << txTo.vout[nIn];
+ hashOutputs = ss.GetHash();
+ }
+
+ CHashWriter ss(SER_GETHASH, 0);
+ // Version
+ ss << txTo.nVersion;
+ // Input prevouts/nSequence (none/all, depending on flags)
+ ss << hashPrevouts;
+ ss << hashSequence;
+ // The input being signed (replacing the scriptSig with scriptCode + amount)
+ // The prevout may already be contained in hashPrevout, and the nSequence
+ // may already be contain in hashSequence.
+ ss << txTo.vin[nIn].prevout;
+ ss << static_cast<const CScriptBase&>(scriptCode);
+ ss << amount;
+ ss << txTo.vin[nIn].nSequence;
+ // Outputs (none/one/all, depending on flags)
+ ss << hashOutputs;
+ // Locktime
+ ss << txTo.nLockTime;
+ // Sighash type
+ ss << nHashType;
+
+ return ss.GetHash();
+ }
+
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
if (nIn >= txTo.vin.size()) {
// nIn out of range
@@ -1136,7 +1196,7 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha
return pubkey.Verify(sighash, vchSig);
}
-bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@@ -1149,7 +1209,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
int nHashType = vchSig.back();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
@@ -1239,8 +1299,67 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
return true;
}
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
+static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
+ vector<vector<unsigned char> > stack;
+ CScript scriptPubKey;
+
+ if (witversion == 0) {
+ if (program.size() == 32) {
+ // Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness
+ if (witness.stack.size() == 0) {
+ return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
+ }
+ scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
+ stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 1);
+ uint256 hashScriptPubKey;
+ CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
+ if (memcmp(hashScriptPubKey.begin(), &program[0], 32)) {
+ return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
+ }
+ } else if (program.size() == 20) {
+ // Special case for pay-to-pubkeyhash; signature + pubkey in witness
+ if (witness.stack.size() != 2) {
+ return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
+ }
+ scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
+ stack = witness.stack;
+ } else {
+ return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
+ }
+ } else if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
+ return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
+ } else {
+ // Higher version witness scripts return true for future softfork compatibility
+ return set_success(serror);
+ }
+
+ // Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
+ for (unsigned int i = 0; i < stack.size(); i++) {
+ if (stack.at(i).size() > MAX_SCRIPT_ELEMENT_SIZE)
+ return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
+ }
+
+ if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_WITNESS_V0, serror)) {
+ return false;
+ }
+
+ // Scripts inside witness implicitly require cleanstack behaviour
+ if (stack.size() != 1)
+ return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
+ if (!CastToBool(stack.back()))
+ return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
+ return true;
+}
+
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
+{
+ static const CScriptWitness emptyWitness;
+ if (witness == NULL) {
+ witness = &emptyWitness;
+ }
+ bool hadWitness = false;
+
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
@@ -1248,12 +1367,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
}
vector<vector<unsigned char> > stack, stackCopy;
- if (!EvalScript(stack, scriptSig, flags, checker, serror))
+ if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack;
- if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
+ if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (stack.empty())
@@ -1261,6 +1380,25 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
if (CastToBool(stack.back()) == false)
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
+ // Bare witness programs
+ int witnessversion;
+ std::vector<unsigned char> witnessprogram;
+ if (flags & SCRIPT_VERIFY_WITNESS) {
+ if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
+ hadWitness = true;
+ if (scriptSig.size() != 0) {
+ // The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability.
+ return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED);
+ }
+ if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) {
+ return false;
+ }
+ // Bypass the cleanstack check at the end. The actual stack is obviously not clean
+ // for witness programs.
+ stack.resize(1);
+ }
+ }
+
// Additional validation for spend-to-script-hash transactions:
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
{
@@ -1280,26 +1418,102 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stack);
- if (!EvalScript(stack, pubKey2, flags, checker, serror))
+ if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
if (stack.empty())
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
if (!CastToBool(stack.back()))
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
+
+ // P2SH witness program
+ if (flags & SCRIPT_VERIFY_WITNESS) {
+ if (pubKey2.IsWitnessProgram(witnessversion, witnessprogram)) {
+ hadWitness = true;
+ if (scriptSig != CScript() << std::vector<unsigned char>(pubKey2.begin(), pubKey2.end())) {
+ // The scriptSig must be _exactly_ a single push of the redeemScript. Otherwise we
+ // reintroduce malleability.
+ return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED_P2SH);
+ }
+ if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) {
+ return false;
+ }
+ // Bypass the cleanstack check at the end. The actual stack is obviously not clean
+ // for witness programs.
+ stack.resize(1);
+ }
+ }
}
// The CLEANSTACK check is only performed after potential P2SH evaluation,
// as the non-P2SH evaluation of a P2SH script will obviously not result in
- // a clean stack (the P2SH inputs remain).
+ // a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) {
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
// would be possible, which is not a softfork (and P2SH should be one).
assert((flags & SCRIPT_VERIFY_P2SH) != 0);
+ assert((flags & SCRIPT_VERIFY_WITNESS) != 0);
if (stack.size() != 1) {
return set_error(serror, SCRIPT_ERR_CLEANSTACK);
}
}
+ if (flags & SCRIPT_VERIFY_WITNESS) {
+ // We can't check for correct unexpected witness data if P2SH was off, so require
+ // that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be
+ // possible, which is not a softfork.
+ assert((flags & SCRIPT_VERIFY_P2SH) != 0);
+ if (!hadWitness && !witness->IsNull()) {
+ return set_error(serror, SCRIPT_ERR_WITNESS_UNEXPECTED);
+ }
+ }
+
return set_success(serror);
}
+
+size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& witprogram, const CScriptWitness& witness, int flags)
+{
+ if (witversion == 0) {
+ if (witprogram.size() == 20)
+ return 1;
+
+ if (witprogram.size() == 32 && witness.stack.size() > 0) {
+ CScript subscript(witness.stack.back().begin(), witness.stack.back().end());
+ return subscript.GetSigOpCount(true);
+ }
+ }
+
+ // Future flags may be implemented here.
+ return 0;
+}
+
+size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
+{
+ static const CScriptWitness witnessEmpty;
+
+ if ((flags & SCRIPT_VERIFY_WITNESS) == 0) {
+ return 0;
+ }
+ assert((flags & SCRIPT_VERIFY_P2SH) != 0);
+
+ int witnessversion;
+ std::vector<unsigned char> witnessprogram;
+ if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
+ return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags);
+ }
+
+ if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) {
+ CScript::const_iterator pc = scriptSig.begin();
+ vector<unsigned char> data;
+ while (pc < scriptSig.end()) {
+ opcodetype opcode;
+ scriptSig.GetOp(pc, opcode, data);
+ }
+ CScript subscript(data.begin(), data.end());
+ if (subscript.IsWitnessProgram(witnessversion, witnessprogram)) {
+ return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index e5cb7290f..bd2f21166 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -74,7 +74,7 @@ enum
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
// "Exactly one stack element must remain, and when interpreted as a boolean, it must be true".
// (softfork safe, BIP62 rule 6)
- // Note: CLEANSTACK should never be used without P2SH.
+ // Note: CLEANSTACK should never be used without P2SH or WITNESS.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
// Verify CHECKLOCKTIMEVERIFY
@@ -86,16 +86,30 @@ enum
//
// See BIP112 for details
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
+
+ // Support segregated witness
+ //
+ SCRIPT_VERIFY_WITNESS = (1U << 11),
+
+ // Making v1-v16 witness program non-standard
+ //
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
};
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+enum SigVersion
+{
+ SIGVERSION_BASE = 0,
+ SIGVERSION_WITNESS_V0 = 1,
+};
+
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion);
class BaseSignatureChecker
{
public:
- virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
return false;
}
@@ -118,13 +132,14 @@ class TransactionSignatureChecker : public BaseSignatureChecker
private:
const CTransaction* txTo;
unsigned int nIn;
+ const CAmount amount;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
- bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn) {}
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckSequence(const CScriptNum& nSequence) const;
};
@@ -135,10 +150,12 @@ private:
const CTransaction txTo;
public:
- MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {}
+ MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
};
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL);
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL);
+
+size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
#endif // BITCOIN_SCRIPT_INTERPRETER_H
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 535c56b57..0bf180341 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -57,6 +57,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
return ISMINE_SPENDABLE;
break;
case TX_PUBKEYHASH:
+ case TX_WITNESS_V0_KEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (keystore.HaveKey(keyID))
return ISMINE_SPENDABLE;
@@ -72,6 +73,20 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
}
break;
}
+ case TX_WITNESS_V0_SCRIPTHASH:
+ {
+ uint160 hash;
+ CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
+ CScriptID scriptID = CScriptID(hash);
+ 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
@@ -88,8 +103,8 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
if (keystore.HaveWatchOnly(scriptPubKey)) {
// TODO: This could be optimized some by doing some work after the above solver
- CScript scriptSig;
- return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, scriptSig) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;
+ SignatureData sigs;
+ return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;
}
return ISMINE_NO;
}
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 9f2809e59..da551c23e 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -210,6 +210,32 @@ bool CScript::IsPayToScriptHash() const
(*this)[22] == OP_EQUAL);
}
+bool CScript::IsPayToWitnessScriptHash() const
+{
+ // Extra-fast test for pay-to-witness-script-hash CScripts:
+ return (this->size() == 34 &&
+ (*this)[0] == OP_0 &&
+ (*this)[1] == 0x20);
+}
+
+// A witness program is any valid CScript that consists of a 1-byte push opcode
+// followed by a data push between 2 and 40 bytes.
+bool CScript::IsWitnessProgram(int& version, std::vector<unsigned char>& program) const
+{
+ if (this->size() < 4 || this->size() > 42) {
+ return false;
+ }
+ if ((*this)[0] != OP_0 && ((*this)[0] < OP_1 || (*this)[0] > OP_16)) {
+ return false;
+ }
+ if ((size_t)((*this)[1] + 2) == this->size()) {
+ version = DecodeOP_N((opcodetype)(*this)[0]);
+ program = std::vector<unsigned char>(this->begin() + 2, this->end());
+ return true;
+ }
+ return false;
+}
+
bool CScript::IsPushOnly(const_iterator pc) const
{
while (pc < end())
@@ -231,3 +257,15 @@ bool CScript::IsPushOnly() const
{
return this->IsPushOnly(begin());
}
+
+std::string CScriptWitness::ToString() const
+{
+ std::string ret = "CScriptWitness(";
+ for (unsigned int i = 0; i < stack.size(); i++) {
+ if (i) {
+ ret += ", ";
+ }
+ ret += HexStr(stack[i]);
+ }
+ return ret + ")";
+}
diff --git a/src/script/script.h b/src/script/script.h
index a2941ce90..71af3754b 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -621,6 +621,8 @@ public:
unsigned int GetSigOpCount(const CScript& scriptSig) const;
bool IsPayToScriptHash() const;
+ bool IsPayToWitnessScriptHash() const;
+ bool IsWitnessProgram(int& version, std::vector<unsigned char>& program) const;
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
bool IsPushOnly(const_iterator pc) const;
@@ -643,6 +645,20 @@ public:
}
};
+struct CScriptWitness
+{
+ // Note that this encodes the data elements being pushed, rather than
+ // encoding them as a CScript that pushes them.
+ std::vector<std::vector<unsigned char> > stack;
+
+ // Some compilers complain without a default constructor
+ CScriptWitness() { }
+
+ bool IsNull() const { return stack.empty(); }
+
+ std::string ToString() const;
+};
+
class CReserveScript
{
public:
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index f1aa1fb40..cef807edc 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -65,8 +65,22 @@ const char* ScriptErrorString(const ScriptError serror)
return "Dummy CHECKMULTISIG argument must be zero";
case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS:
return "NOPx reserved for soft-fork upgrades";
+ case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM:
+ return "Witness version reserved for soft-fork upgrades";
case SCRIPT_ERR_PUBKEYTYPE:
return "Public key is neither compressed or uncompressed";
+ case SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH:
+ return "Witness program has incorrect length";
+ case SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY:
+ return "Witness program was passed an empty witness";
+ case SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH:
+ return "Witness program hash mismatch";
+ case SCRIPT_ERR_WITNESS_MALLEATED:
+ return "Witness requires empty scriptSig";
+ case SCRIPT_ERR_WITNESS_MALLEATED_P2SH:
+ return "Witness requires only-redeemscript scriptSig";
+ case SCRIPT_ERR_WITNESS_UNEXPECTED:
+ return "Witness provided for non-witness script";
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;
diff --git a/src/script/script_error.h b/src/script/script_error.h
index 26df33932..09dc6945a 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -51,6 +51,15 @@ typedef enum ScriptError_t
/* softfork safeness */
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,
+ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
+
+ /* segregated witness */
+ SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH,
+ SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY,
+ SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH,
+ SCRIPT_ERR_WITNESS_MALLEATED,
+ SCRIPT_ERR_WITNESS_MALLEATED_P2SH,
+ SCRIPT_ERR_WITNESS_UNEXPECTED,
SCRIPT_ERR_ERROR_COUNT
} ScriptError;
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index be1df09c2..050bf8cc4 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -22,7 +22,7 @@ private:
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, nInIn, amount), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 2f4111f78..87f38d9c7 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -18,31 +18,31 @@ using namespace std;
typedef std::vector<unsigned char> valtype;
-TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}
+TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
-bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
+bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
{
CKey key;
if (!keystore->GetKey(address, key))
return false;
- uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
+ uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
return true;
}
-static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
+static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
vector<unsigned char> vchSig;
- if (!creator.CreateSig(vchSig, address, scriptCode))
+ if (!creator.CreateSig(vchSig, address, scriptCode, sigversion))
return false;
- scriptSigRet << vchSig;
+ ret.push_back(vchSig);
return true;
}
-static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
+static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
@@ -50,7 +50,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
{
const valtype& pubkey = multisigdata[i];
CKeyID keyID = CPubKey(pubkey).GetID();
- if (Sign1(keyID, creator, scriptCode, scriptSigRet))
+ if (Sign1(keyID, creator, scriptCode, ret, sigversion))
++nSigned;
}
return nSigned==nRequired;
@@ -63,9 +63,11 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
* Returns false if scriptPubKey could not be completely satisfied.
*/
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
- CScript& scriptSigRet, txnouttype& whichTypeRet)
+ std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion)
{
- scriptSigRet.clear();
+ CScript scriptRet;
+ uint160 h160;
+ ret.clear();
vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
@@ -79,62 +81,142 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
return false;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
- return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
+ return Sign1(keyID, creator, scriptPubKey, ret, sigversion);
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
- if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
+ if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion))
return false;
else
{
CPubKey vch;
creator.KeyStore().GetPubKey(keyID, vch);
- scriptSigRet << ToByteVector(vch);
+ ret.push_back(ToByteVector(vch));
}
return true;
case TX_SCRIPTHASH:
- return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);
+ if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
+ ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
+ return true;
+ }
+ return false;
case TX_MULTISIG:
- scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
- return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
+ ret.push_back(valtype()); // workaround CHECKMULTISIG bug
+ return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion));
+
+ case TX_WITNESS_V0_KEYHASH:
+ ret.push_back(vSolutions[0]);
+ return true;
+
+ case TX_WITNESS_V0_SCRIPTHASH:
+ CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
+ if (creator.KeyStore().GetCScript(h160, scriptRet)) {
+ ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
+ return true;
+ }
+ return false;
+
+ default:
+ return false;
}
- return false;
}
-bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
+static CScript PushAll(const vector<valtype>& values)
{
+ CScript result;
+ BOOST_FOREACH(const valtype& v, values) {
+ if (v.size() == 0) {
+ result << OP_0;
+ } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {
+ result << CScript::EncodeOP_N(v[0]);
+ } else {
+ result << v;
+ }
+ }
+ return result;
+}
+
+bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
+{
+ CScript script = fromPubKey;
+ bool solved = true;
+ std::vector<valtype> result;
txnouttype whichType;
- if (!SignStep(creator, fromPubKey, scriptSig, whichType))
- return false;
+ solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE);
+ bool P2SH = false;
+ CScript subscript;
+ sigdata.scriptWitness.stack.clear();
- if (whichType == TX_SCRIPTHASH)
+ if (solved && whichType == TX_SCRIPTHASH)
{
- // Solver returns the subscript that need to be evaluated;
+ // Solver returns the subscript that needs to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
- CScript subscript = scriptSig;
+ script = subscript = CScript(result[0].begin(), result[0].end());
+ solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH;
+ P2SH = true;
+ }
+ if (solved && whichType == TX_WITNESS_V0_KEYHASH)
+ {
+ CScript witnessscript;
+ witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
txnouttype subType;
- bool fSolved =
- SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
- // Append serialized subscript whether or not it is completely signed:
- scriptSig << valtype(subscript.begin(), subscript.end());
- if (!fSolved) return false;
+ solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0);
+ sigdata.scriptWitness.stack = result;
+ result.clear();
+ }
+ else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH)
+ {
+ CScript witnessscript(result[0].begin(), result[0].end());
+ txnouttype subType;
+ solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
+ result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
+ sigdata.scriptWitness.stack = result;
+ result.clear();
}
+ if (P2SH) {
+ result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
+ }
+ sigdata.scriptSig = PushAll(result);
+
// Test solution
- return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
+ return solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
+}
+
+SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)
+{
+ SignatureData data;
+ assert(tx.vin.size() > nIn);
+ data.scriptSig = tx.vin[nIn].scriptSig;
+ if (tx.wit.vtxinwit.size() > nIn) {
+ data.scriptWitness = tx.wit.vtxinwit[nIn].scriptWitness;
+ }
+ return data;
+}
+
+void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
+{
+ assert(tx.vin.size() > nIn);
+ tx.vin[nIn].scriptSig = data.scriptSig;
+ if (!data.scriptWitness.IsNull() || tx.wit.vtxinwit.size() > nIn) {
+ tx.wit.vtxinwit.resize(tx.vin.size());
+ tx.wit.vtxinwit[nIn].scriptWitness = data.scriptWitness;
+ }
}
-bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
{
assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
CTransaction txToConst(txTo);
- TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);
+ TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType);
- return ProduceSignature(creator, fromPubKey, txin.scriptSig);
+ SignatureData sigdata;
+ bool ret = ProduceSignature(creator, fromPubKey, sigdata);
+ UpdateTransaction(txTo, nIn, sigdata);
+ return ret;
}
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
@@ -144,20 +226,12 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab
assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n];
- return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
-}
-
-static CScript PushAll(const vector<valtype>& values)
-{
- CScript result;
- BOOST_FOREACH(const valtype& v, values)
- result << v;
- return result;
+ return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
}
-static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
+static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const vector<valtype>& vSolutions,
- const vector<valtype>& sigs1, const vector<valtype>& sigs2)
+ const vector<valtype>& sigs1, const vector<valtype>& sigs2, SigVersion sigversion)
{
// Combine all the signatures we've got:
set<valtype> allsigs;
@@ -185,7 +259,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
- if (checker.CheckSig(sig, pubkey, scriptPubKey))
+ if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion))
{
sigs[pubkey] = sig;
break;
@@ -194,87 +268,126 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
}
// Now build a merged CScript:
unsigned int nSigsHave = 0;
- CScript result; result << OP_0; // pop-one-too-many workaround
+ std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
{
if (sigs.count(vSolutions[i+1]))
{
- result << sigs[vSolutions[i+1]];
+ result.push_back(sigs[vSolutions[i+1]]);
++nSigsHave;
}
}
// Fill any missing with OP_0:
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
- result << OP_0;
+ result.push_back(valtype());
return result;
}
-static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
+namespace
+{
+struct Stacks
+{
+ std::vector<valtype> script;
+ std::vector<valtype> witness;
+
+ Stacks() {}
+ explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_), witness() {}
+ explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) {
+ EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE);
+ }
+
+ SignatureData Output() const {
+ SignatureData result;
+ result.scriptSig = PushAll(script);
+ result.scriptWitness.stack = witness;
+ return result;
+ }
+};
+}
+
+static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const txnouttype txType, const vector<valtype>& vSolutions,
- vector<valtype>& sigs1, vector<valtype>& sigs2)
+ Stacks sigs1, Stacks sigs2, SigVersion sigversion)
{
switch (txType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
// Don't know anything about this, assume bigger one is correct:
- if (sigs1.size() >= sigs2.size())
- return PushAll(sigs1);
- return PushAll(sigs2);
+ if (sigs1.script.size() >= sigs2.script.size())
+ return sigs1;
+ return sigs2;
case TX_PUBKEY:
case TX_PUBKEYHASH:
// Signatures are bigger than placeholders or empty scripts:
- if (sigs1.empty() || sigs1[0].empty())
- return PushAll(sigs2);
- return PushAll(sigs1);
+ if (sigs1.script.empty() || sigs1.script[0].empty())
+ return sigs2;
+ return sigs1;
+ case TX_WITNESS_V0_KEYHASH:
+ // Signatures are bigger than placeholders or empty scripts:
+ if (sigs1.witness.empty() || sigs1.witness[0].empty())
+ return sigs2;
+ return sigs1;
case TX_SCRIPTHASH:
- if (sigs1.empty() || sigs1.back().empty())
- return PushAll(sigs2);
- else if (sigs2.empty() || sigs2.back().empty())
- return PushAll(sigs1);
+ if (sigs1.script.empty() || sigs1.script.back().empty())
+ return sigs2;
+ else if (sigs2.script.empty() || sigs2.script.back().empty())
+ return sigs1;
else
{
// Recur to combine:
- valtype spk = sigs1.back();
+ valtype spk = sigs1.script.back();
CScript pubKey2(spk.begin(), spk.end());
txnouttype txType2;
vector<vector<unsigned char> > vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
- sigs1.pop_back();
- sigs2.pop_back();
- CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
- result << spk;
+ sigs1.script.pop_back();
+ sigs2.script.pop_back();
+ Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion);
+ result.script.push_back(spk);
return result;
}
case TX_MULTISIG:
- return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
+ return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion));
+ case TX_WITNESS_V0_SCRIPTHASH:
+ if (sigs1.witness.empty() || sigs1.witness.back().empty())
+ return sigs2;
+ else if (sigs2.witness.empty() || sigs2.witness.back().empty())
+ return sigs1;
+ else
+ {
+ // Recur to combine:
+ CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end());
+ txnouttype txType2;
+ vector<valtype> vSolutions2;
+ Solver(pubKey2, txType2, vSolutions2);
+ sigs1.witness.pop_back();
+ sigs1.script = sigs1.witness;
+ sigs1.witness.clear();
+ sigs2.witness.pop_back();
+ sigs2.script = sigs2.witness;
+ sigs2.witness.clear();
+ Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0);
+ result.witness = result.script;
+ result.script.clear();
+ result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end()));
+ return result;
+ }
+ default:
+ return Stacks();
}
-
- return CScript();
}
-CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- const CScript& scriptSig1, const CScript& scriptSig2)
-{
- TransactionSignatureChecker checker(&txTo, nIn);
- return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
-}
-
-CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const CScript& scriptSig1, const CScript& scriptSig2)
+SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
+ const SignatureData& scriptSig1, const SignatureData& scriptSig2)
{
txnouttype txType;
vector<vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions);
- vector<valtype> stack1;
- EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
- vector<valtype> stack2;
- EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
-
- return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
+ return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output();
}
namespace {
@@ -284,7 +397,7 @@ class DummySignatureChecker : public BaseSignatureChecker
public:
DummySignatureChecker() {}
- bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
return true;
}
@@ -297,7 +410,7 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
return dummyChecker;
}
-bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const
+bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const
{
// Create a dummy signature that is a valid DER-encoding
vchSig.assign(72, '\000');
diff --git a/src/script/sign.h b/src/script/sign.h
index 47a9cde7f..6404b4523 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -27,7 +27,7 @@ public:
virtual const BaseSignatureChecker& Checker() const =0;
/** Create a singular (non-script) signature. */
- virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0;
+ virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
};
/** A signature creator for transactions. */
@@ -35,12 +35,20 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction* txTo;
unsigned int nIn;
int nHashType;
+ CAmount amount;
const TransactionSignatureChecker checker;
public:
- TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL);
+ TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
const BaseSignatureChecker& Checker() const { return checker; }
- bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;
+};
+
+class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
+ CTransaction tx;
+
+public:
+ MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
/** A signature creator that just produces 72-byte empty signatyres. */
@@ -48,20 +56,29 @@ class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
const BaseSignatureChecker& Checker() const;
- bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;
+};
+
+struct SignatureData {
+ CScript scriptSig;
+ CScriptWitness scriptWitness;
+
+ SignatureData() {}
+ explicit SignatureData(const CScript& script) : scriptSig(script) {}
};
/** Produce a script signature using a generic signature creator. */
-bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
+bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
/** Produce a script signature for a transaction. */
-bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
-bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
+bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
-CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2);
+SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2);
-/** Combine two script signatures on transactions. */
-CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
+/** Extract signature data from a transaction, and insert it. */
+SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
+void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
#endif // BITCOIN_SCRIPT_SIGN_H
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 67b6af327..bb178f49f 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -31,6 +31,8 @@ const char* GetTxnOutputType(txnouttype t)
case TX_SCRIPTHASH: return "scripthash";
case TX_MULTISIG: return "multisig";
case TX_NULL_DATA: return "nulldata";
+ case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
+ case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
}
return NULL;
}
@@ -66,6 +68,22 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
return true;
}
+ int witnessversion;
+ std::vector<unsigned char> witnessprogram;
+ if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
+ if (witnessversion == 0 && witnessprogram.size() == 20) {
+ typeRet = TX_WITNESS_V0_KEYHASH;
+ vSolutionsRet.push_back(witnessprogram);
+ return true;
+ }
+ if (witnessversion == 0 && witnessprogram.size() == 32) {
+ typeRet = TX_WITNESS_V0_SCRIPTHASH;
+ vSolutionsRet.push_back(witnessprogram);
+ return true;
+ }
+ return false;
+ }
+
// Provably prunable, data-carrying output
//
// So long as script passes the IsUnspendable() test and all but the first
@@ -282,3 +300,26 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
return script;
}
+
+CScript GetScriptForWitness(const CScript& redeemscript)
+{
+ CScript ret;
+
+ txnouttype typ;
+ std::vector<std::vector<unsigned char> > vSolutions;
+ if (Solver(redeemscript, typ, vSolutions)) {
+ if (typ == TX_PUBKEY) {
+ unsigned char h160[20];
+ CHash160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160);
+ ret << OP_0 << std::vector<unsigned char>(&h160[0], &h160[20]);
+ return ret;
+ } else if (typ == TX_PUBKEYHASH) {
+ ret << OP_0 << vSolutions[0];
+ return ret;
+ }
+ }
+ uint256 hash;
+ CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin());
+ ret << OP_0 << ToByteVector(hash);
+ return ret;
+}
diff --git a/src/script/standard.h b/src/script/standard.h
index f348da8e1..72aaea0b7 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -51,6 +51,8 @@ enum txnouttype
TX_SCRIPTHASH,
TX_MULTISIG,
TX_NULL_DATA,
+ TX_WITNESS_V0_SCRIPTHASH,
+ TX_WITNESS_V0_KEYHASH,
};
class CNoDestination {
@@ -77,5 +79,6 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
CScript GetScriptForDestination(const CTxDestination& dest);
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
+CScript GetScriptForWitness(const CScript& redeemscript);
#endif // BITCOIN_SCRIPT_STANDARD_H