Skip to content

Instantly share code, notes, and snippets.

@achow101
Created October 12, 2017 04:06
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save achow101/86a4fdcb3cebc1a57968715f34d66e0a to your computer and use it in GitHub Desktop.
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 6b68f0679e8..c4c81715e48 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -145,6 +145,27 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
return ISMINE_SPENDABLE;
break;
}
+
+ case TX_CLTV_MULTISIG:
+ {
+ // Only consider transactions "mine" if we own ALL the
+ // keys involved. Multi-signature transactions that are
+ // partially owned (somebody else has a key that can spend
+ // them) enable spend-out-from-under-you attacks, especially
+ // in shared-wallet situations.
+ std::vector<valtype> keys(vSolutions.begin()+2, vSolutions.begin()+vSolutions.size()-1);
+ if (sigversion != SIGVERSION_BASE) {
+ for (size_t i = 0; i < keys.size(); i++) {
+ if (keys[i].size() != 33) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
+ }
+ }
+ if (HaveKeys(keys, keystore) == keys.size())
+ return ISMINE_SPENDABLE;
+ break;
+ }
}
if (keystore.HaveWatchOnly(scriptPubKey)) {
diff --git a/src/script/script.h b/src/script/script.h
index 2a920605433..bc8a1fadb2c 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -183,6 +183,7 @@ enum opcodetype
// template matching params
+ OP_PUSHEDDATA = 0xf0,
OP_SMALLINTEGER = 0xfa,
OP_PUBKEYS = 0xfb,
OP_PUBKEYHASH = 0xfd,
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index ac58b690a2f..ed88dbf8702 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -106,6 +106,13 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion));
+ case TX_CLTV_MULTISIG:
+ {
+ ret.push_back(valtype()); // workaround CHECKMULTISIG bug
+ std::vector<valtype> vSolutions2(vSolutions.begin()+1, vSolutions.end());
+ return (SignN(vSolutions2, creator, scriptPubKey, ret, sigversion));
+ }
+
case TX_WITNESS_V0_KEYHASH:
ret.push_back(vSolutions[0]);
return true;
@@ -348,6 +355,11 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
}
case TX_MULTISIG:
return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion));
+ case TX_CLTV_MULTISIG:
+ {
+ std::vector<valtype> vSolutions2(vSolutions.begin()+1, vSolutions.end());
+ return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions2, sigs1.script, sigs2.script, sigversion));
+ }
case TX_WITNESS_V0_SCRIPTHASH:
if (sigs1.witness.empty() || sigs1.witness.back().empty())
return sigs2;
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index f57f1f61b4f..35131e27a56 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -31,6 +31,7 @@ const char* GetTxnOutputType(txnouttype t)
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";
+ case TX_CLTV_MULTISIG: return "cltv-multisig";
}
return nullptr;
}
@@ -49,6 +50,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// Sender provides N pubkeys, receivers provides M signatures
mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+
+ // Sender provides N pubkeys and a lock time, receivers provides M signatures
+ mTemplates.insert(std::make_pair(TX_CLTV_MULTISIG, CScript() << OP_PUSHEDDATA << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
}
vSolutionsRet.clear();
@@ -121,6 +125,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
unsigned char n = vSolutionsRet.back()[0];
if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
return false;
+ } else if (typeRet == TX_CLTV_MULTISIG) {
+ // Additional checks for TX_CLTV_MULTISIG:
+ unsigned char m = vSolutionsRet[1][0];
+ unsigned char n = vSolutionsRet.back()[0];
+ if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-3 != n)
+ return false;
}
return true;
}
@@ -167,6 +177,11 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
else
break;
}
+ else if (opcode2 == OP_PUSHEDDATA)
+ {
+ // Some arbitrary data was pushed
+ vSolutionsRet.push_back(vch1);
+ }
else if (opcode1 != opcode2 || vch1 != vch2)
{
// Others must match exactly
@@ -255,6 +270,22 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
if (addressRet.empty())
return false;
}
+ else if (typeRet == TX_CLTV_MULTISIG)
+ {
+ nRequiredRet = vSolutions[1][0];
+ for (unsigned int i = 2; i < vSolutions.size()-1; i++)
+ {
+ CPubKey pubKey(vSolutions[i]);
+ if (!pubKey.IsValid())
+ continue;
+
+ CTxDestination address = pubKey.GetID();
+ addressRet.push_back(address);
+ }
+
+ if (addressRet.empty())
+ return false;
+ }
else
{
nRequiredRet = 1;
diff --git a/src/script/standard.h b/src/script/standard.h
index fa07ea88c1a..c9e423a5d51 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_CLTV_MULTISIG,
TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment