{
case TX_NONSTANDARD: return "nonstandard";
case TX_PUBKEY: return "pubkey";
+ case TX_PUBKEY_DROP: return "pubkeydrop";
case TX_PUBKEYHASH: return "pubkeyhash";
case TX_SCRIPTHASH: return "scripthash";
case TX_MULTISIG: return "multisig";
case OP_ENDIF : return "OP_ENDIF";
case OP_VERIFY : return "OP_VERIFY";
case OP_RETURN : return "OP_RETURN";
+ case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
// stack ops
case OP_TOALTSTACK : return "OP_TOALTSTACK";
// expanson
case OP_NOP1 : return "OP_NOP1";
- case OP_NOP2 : return "OP_NOP2";
case OP_NOP3 : return "OP_NOP3";
case OP_NOP4 : return "OP_NOP4";
case OP_NOP5 : return "OP_NOP5";
return true;
}
-bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
- if (!(flags & SCRIPT_VERIFY_STRICTENC))
- return true;
-
+bool IsDERSignature(const valtype &vchSig, bool fWithHashType, bool fCheckLow) {
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
// Where R and S are not negative (their first byte has its highest bit not set), and not
return error("Non-canonical signature: too short");
if (vchSig.size() > 73)
return error("Non-canonical signature: too long");
- unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
- if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
- return error("Non-canonical signature: unknown hashtype byte");
if (vchSig[0] != 0x30)
return error("Non-canonical signature: wrong type");
- if (vchSig[1] != vchSig.size()-3)
+ if (vchSig[1] != vchSig.size() - (fWithHashType ? 3 : 2))
return error("Non-canonical signature: wrong length marker");
+ if (fWithHashType) {
+ unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
+ if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
+ return error("Non-canonical signature: unknown hashtype byte");
+ }
unsigned int nLenR = vchSig[3];
if (5 + nLenR >= vchSig.size())
return error("Non-canonical signature: S length misplaced");
unsigned int nLenS = vchSig[5+nLenR];
- if ((unsigned long)(nLenR+nLenS+7) != vchSig.size())
+ if ((unsigned long)(nLenR + nLenS + (fWithHashType ? 7 : 6)) != vchSig.size())
return error("Non-canonical signature: R+S length mismatch");
const unsigned char *R = &vchSig[4];
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
return error("Non-canonical signature: S value excessively padded");
- if (flags & SCRIPT_VERIFY_EVEN_S) {
- if (S[nLenS-1] & 1)
- return error("Non-canonical signature: S value odd");
+ if (fCheckLow) {
+ unsigned int nLenR = vchSig[3];
+ unsigned int nLenS = vchSig[5+nLenR];
+ const unsigned char *S = &vchSig[6+nLenR];
+ // If the S value is above the order of the curve divided by two, its
+ // complement modulo the order could have been used instead, which is
+ // one byte shorter when encoded correctly.
+ if (!CKey::CheckSignatureElement(S, nLenS, true))
+ return error("Non-canonical signature: S value is unnecessarily high");
}
return true;
}
+bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
+ if (!(flags & SCRIPT_VERIFY_STRICTENC))
+ return true;
+
+ return IsDERSignature(vchSig, true, (flags & SCRIPT_VERIFY_LOW_S) != 0);
+}
+
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
{
CAutoBN_CTX pctx;
// Control
//
case OP_NOP:
- case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
+ case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
break;
}
break;
+ case OP_CHECKLOCKTIMEVERIFY:
+ {
+ // CHECKLOCKTIMEVERIFY
+ //
+ // (nLockTime -- nLockTime)
+ if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
+ break; // treat as a NOP is not enabled
+ if (stack.size() < 1)
+ return false;
+ const CBigNum nLockTime = CastToBigNum(stacktop(-1));
+ if (nLockTime < 0)
+ return false; // Negative argument is senseless.
+
+ if (!( // We can have either lock-by-blockheight or lock-by-blocktime.
+ (txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
+ (txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
+ ))
+ return false;
+
+ // Now we can perform a simple numerical comparison
+ if (nLockTime > (int64_t)txTo.nLockTime)
+ return false;
+
+ // Finally the nLockTime feature can be disabled and thus
+ // CHECKLOCKTIMEVERIFY bypassed if every txin has been
+ // finalized by setting nSequence to maxint. The
+ // transaction would be allowed into the blockchain, making
+ // the opcode ineffective.
+ //
+ // Testing if this vin is not final is sufficient to
+ // prevent this condition. Alternatively we could test all
+ // inputs, but testing just this input minimizes the data
+ // required to prove correct CHECKLOCKTIMEVERIFY execution.
+ if (txTo.vin[nIn].IsFinal())
+ return false;
+ break;
+ }
//
// Stack ops
case OP_DEPTH:
{
// -- stacksize
- CBigNum bn(stack.size());
+ CBigNum bn((uint16_t) stack.size());
stack.push_back(bn.getvch());
}
break;
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
if (stack.size() < 2)
return false;
- int n = CastToBigNum(stacktop(-1)).getint();
+ int n = CastToBigNum(stacktop(-1)).getint32();
popstack(stack);
if (n < 0 || n >= (int)stack.size())
return false;
// (in -- in size)
if (stack.size() < 1)
return false;
- CBigNum bn(stacktop(-1).size());
+ CBigNum bn((uint16_t) stacktop(-1).size());
stack.push_back(bn.getvch());
}
break;
if ((int)stack.size() < i)
return false;
- int nKeysCount = CastToBigNum(stacktop(-i)).getint();
+ int nKeysCount = CastToBigNum(stacktop(-i)).getint32();
if (nKeysCount < 0 || nKeysCount > 20)
return false;
nOpCount += nKeysCount;
if ((int)stack.size() < i)
return false;
- int nSigsCount = CastToBigNum(stacktop(-i)).getint();
+ int nSigsCount = CastToBigNum(stacktop(-i)).getint32();
if (nSigsCount < 0 || nSigsCount > nKeysCount)
return false;
int isig = ++i;
// sigdata_type is (signature hash, signature, public key):
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey > sigdata_type;
std::set< sigdata_type> setValid;
- CCriticalSection cs_sigcache;
+ boost::shared_mutex cs_sigcache;
public:
bool
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
{
- LOCK(cs_sigcache);
+ boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
sigdata_type k(hash, vchSig, pubKey);
std::set<sigdata_type>::iterator mi = setValid.find(k);
// (~200 bytes per cache entry times 50,000 entries)
// Since there are a maximum of 20,000 signature operations per block
// 50,000 is a reasonable default.
- int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
+ int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
if (nMaxCacheSize <= 0) return;
- LOCK(cs_sigcache);
+ boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
- while (static_cast<int64>(setValid.size()) > nMaxCacheSize)
+ while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
{
// Evict a random entry. Random because that helps
// foil would-be DoS attackers who might try to pre-generate
// Standard tx, sender provides pubkey, receiver adds signature
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+ if (fTestNet || GetTime() > SMALLDATA_SWITCH_TIME)
+ {
+ // Malleable pubkey tx hack, sender provides generated pubkey combined with R parameter. The R parameter is dropped before checking a signature.
+ mTemplates.insert(make_pair(TX_PUBKEY_DROP, CScript() << OP_PUBKEY << OP_PUBKEY << OP_DROP << OP_CHECKSIG));
+ }
+
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
}
else if (opcode2 == OP_SMALLDATA)
{
- // small pushdata, <= 80 bytes
- if (vch1.size() > 80)
+ // small pushdata, <= 1024 bytes
+ if (vch1.size() > (GetTime() > SMALLDATA_SWITCH_TIME ? 1024 : 80))
break;
}
else if (opcode1 != opcode2 || vch1 != vch2)
}
-bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+bool Sign1(const CKeyID& address, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
{
CKey key;
if (!keystore.GetKey(address, key))
return true;
}
-bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+bool SignR(const CPubKey& pubKey, const CPubKey& R, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
+{
+ CKey key;
+ if (!keystore.CreatePrivKey(pubKey, R, key))
+ return false;
+
+ vector<unsigned char> vchSig;
+ if (!key.Sign(hash, vchSig))
+ return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig;
+
+ return true;
+}
+
+bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
// Returns false if scriptPubKey could not be completely satisfied.
//
-bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
+bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, const uint256& hash, int nHashType,
CScript& scriptSigRet, txnouttype& whichTypeRet)
{
scriptSigRet.clear();
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
+ case TX_PUBKEY_DROP:
+ {
+ CPubKey key = CPubKey(vSolutions[0]);
+ CPubKey R = CPubKey(vSolutions[1]);
+ return SignR(key, R, keystore, hash, nHashType, scriptSigRet);
+ }
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
case TX_NULL_DATA:
return 1;
case TX_PUBKEY:
+ case TX_PUBKEY_DROP:
return 1;
case TX_PUBKEYHASH:
return 2;
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
};
-bool IsMine(const CKeyStore &keystore, const CTxDestination &dest)
+isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
{
- return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest);
+ CScript script;
+ script.SetDestination(dest);
+ return IsMine(keystore, script);
}
-bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
+isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
vector<valtype> vSolutions;
txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ if (!Solver(scriptPubKey, whichType, vSolutions)) {
+ if (keystore.HaveWatchOnly(scriptPubKey))
+ return MINE_WATCH_ONLY;
+ return MINE_NO;
+ }
CKeyID keyID;
switch (whichType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
- return false;
+ break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
- return keystore.HaveKey(keyID);
+ if (keystore.HaveKey(keyID))
+ return MINE_SPENDABLE;
+ break;
+ case TX_PUBKEY_DROP:
+ {
+ CPubKey key = CPubKey(vSolutions[0]);
+ CPubKey R = CPubKey(vSolutions[1]);
+ if (keystore.CheckOwnership(key, R))
+ return MINE_SPENDABLE;
+ }
+ break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
- return keystore.HaveKey(keyID);
+ if (keystore.HaveKey(keyID))
+ return MINE_SPENDABLE;
+ break;
case TX_SCRIPTHASH:
{
+ CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
- if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript))
- return false;
- return IsMine(keystore, subscript);
+ if (keystore.GetCScript(scriptID, subscript)) {
+ isminetype ret = IsMine(keystore, subscript);
+ if (ret == MINE_SPENDABLE)
+ return ret;
+ }
+ break;
}
case TX_MULTISIG:
{
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
- return HaveKeys(keys, keystore) == keys.size();
+ if (HaveKeys(keys, keystore) == keys.size())
+ return MINE_SPENDABLE;
+ break;
}
}
- return false;
+
+ if (keystore.HaveWatchOnly(scriptPubKey))
+ return MINE_WATCH_ONLY;
+ return MINE_NO;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
class CAffectedKeysVisitor : public boost::static_visitor<void> {
private:
const CKeyStore &keystore;
+ CAffectedKeysVisitor& operator=(CAffectedKeysVisitor const&);
std::vector<CKeyID> &vKeys;
public:
if (!Solver(scriptPubKey, typeRet, vSolutions))
return false;
if (typeRet == TX_NULL_DATA)
+ {
+ nRequiredRet = 0;
return true;
+ }
if (typeRet == TX_MULTISIG)
{
else
{
nRequiredRet = 1;
+ if (typeRet == TX_PUBKEY_DROP)
+ return true;
CTxDestination address;
if (!ExtractDestination(scriptPubKey, address))
return false;
}
// Test solution
- return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
+ return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STRICT_FLAGS, 0);
}
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
}
-bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
-{
- assert(nIn < txTo.vin.size());
- const CTxIn& txin = txTo.vin[nIn];
- if (txin.prevout.n >= txFrom.vout.size())
- return false;
- const CTxOut& txout = txFrom.vout[txin.prevout.n];
-
- if (txin.prevout.hash != txFrom.GetHash())
- return false;
-
- return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, flags, nHashType);
-}
-
static CScript PushAll(const vector<valtype>& values)
{
CScript result;
return result;
}
-static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
// Build a map of pubkey -> signature by matching sigs to pubkeys:
assert(vSolutions.size() > 1);
unsigned int nSigsRequired = vSolutions.front()[0];
- unsigned int nPubKeys = vSolutions.size()-2;
+ unsigned int nPubKeys = (unsigned int)(vSolutions.size()-2);
map<valtype, valtype> sigs;
BOOST_FOREACH(const valtype& sig, allsigs)
{
return result;
}
-static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const txnouttype txType, const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
return PushAll(sigs1);
return PushAll(sigs2);
case TX_PUBKEY:
+ case TX_PUBKEY_DROP:
case TX_PUBKEYHASH:
// Signatures are bigger than placeholders or empty scripts:
if (sigs1.empty() || sigs1[0].empty())
return CScript();
}
-CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const CScript& scriptSig1, const CScript& scriptSig2)
{
txnouttype txType;
boost::apply_visitor(CScriptVisitor(this), dest);
}
+void CScript::SetDestination(const CPubKey& R, CPubKey& pubKeyVariant)
+{
+ this->clear();
+ *this << pubKeyVariant << R << OP_DROP << OP_CHECKSIG;
+}
+
+
void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
{
this->clear();
*this << EncodeOP_N(nRequired);
BOOST_FOREACH(const CKey& key, keys)
*this << key.GetPubKey();
- *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
+ *this << EncodeOP_N((int)(keys.size())) << OP_CHECKMULTISIG;
}