aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2016-03-31 14:54:58 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2016-06-22 15:43:01 +0200
commit605e8473a7ddca13b24a4020c7bd630aa5d374e2 (patch)
tree8c425e851aa6c30d9edc8bccb60e731a3f053101 /src/script
parent9757b57c25c67de611b8f5d0a19f409c2e8753a6 (diff)
BIP143: Signing logic
Diffstat (limited to 'src/script')
-rw-r--r--src/script/ismine.cpp19
-rw-r--r--src/script/sign.cpp279
-rw-r--r--src/script/sign.h34
-rw-r--r--src/script/standard.cpp41
-rw-r--r--src/script/standard.h3
5 files changed, 282 insertions, 94 deletions
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 535c56b57a..0bf180341e 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/sign.cpp b/src/script/sign.cpp
index 83bb0cfa29..87f38d9c72 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -20,29 +20,29 @@ typedef std::vector<unsigned char> valtype;
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, amount, SIGVERSION_BASE);
+ 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, NULL, 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, SIGVERSION_BASE))
+ 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 CAmount& amount,
- const CScript& scriptSig1, const CScript& scriptSig2)
-{
- TransactionSignatureChecker checker(&txTo, nIn, amount);
- 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(), SIGVERSION_BASE);
- vector<valtype> stack2;
- EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE);
-
- return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
+ return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output();
}
namespace {
@@ -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 f54511f7a6..6404b4523e 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. */
@@ -41,7 +41,14 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
public:
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. */
@@ -49,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 CAmount& amount, 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 67b6af327a..bb178f49fe 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 f348da8e19..72aaea0b7b 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