mirror of
https://github.com/dogecoin/dogecoin.git
synced 2026-03-02 00:56:02 +00:00
Merge pull request #274 from somegeekintn/optim2-1.5
Wallet/RPC Optimizations
This commit is contained in:
commit
d41600067d
@ -28,6 +28,7 @@
|
||||
#endif
|
||||
|
||||
#if MAC_OSX
|
||||
#undef MSG_NOSIGNAL // undef prior to redefinition eliminates warnings
|
||||
#define MSG_NOSIGNAL SO_NOSIGPIPE
|
||||
#endif
|
||||
|
||||
|
||||
150
src/script.cpp
150
src/script.cpp
@ -31,7 +31,6 @@ static const CBigNum bnFalse(0);
|
||||
static const CBigNum bnTrue(1);
|
||||
static const size_t nMaxNumSize = 4;
|
||||
|
||||
|
||||
CBigNum CastToBigNum(const valtype& vch)
|
||||
{
|
||||
if (vch.size() > nMaxNumSize)
|
||||
@ -1119,27 +1118,40 @@ bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubK
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
txnouttype txType;
|
||||
CScript *tScript;
|
||||
} SScriptPairRec;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
|
||||
//
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
|
||||
{
|
||||
// Templates
|
||||
static map<txnouttype, CScript> mTemplates;
|
||||
if (mTemplates.empty())
|
||||
{
|
||||
// Standard tx, sender provides pubkey, receiver adds signature
|
||||
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << 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));
|
||||
|
||||
// Sender provides N pubkeys, receivers provides M signatures
|
||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
||||
}
|
||||
static SScriptPairRec *sTemplates = NULL;
|
||||
SScriptPairRec *curTemplate;
|
||||
|
||||
if (sTemplates == NULL) {
|
||||
CScript *tScript;
|
||||
|
||||
sTemplates = (SScriptPairRec *)malloc(sizeof(SScriptPairRec) * 4);
|
||||
|
||||
// order templates such that most common transaction types are checked first
|
||||
tScript = new CScript();
|
||||
*tScript << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
sTemplates[0].txType = TX_PUBKEYHASH;
|
||||
sTemplates[0].tScript = tScript;
|
||||
|
||||
tScript = new CScript();
|
||||
*tScript << OP_PUBKEY << OP_CHECKSIG;
|
||||
sTemplates[1].txType = TX_PUBKEY;
|
||||
sTemplates[1].tScript = tScript;
|
||||
|
||||
tScript = new CScript();
|
||||
*tScript << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG;
|
||||
sTemplates[2].txType = TX_MULTISIG;
|
||||
sTemplates[2].tScript = tScript;
|
||||
|
||||
sTemplates[3].txType = (txnouttype)-1;
|
||||
sTemplates[3].tScript = NULL;
|
||||
}
|
||||
|
||||
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
||||
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
||||
@ -1150,26 +1162,29 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
vSolutionsRet.push_back(hashBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||
{
|
||||
const CScript& script2 = tplate.second;
|
||||
vSolutionsRet.clear();
|
||||
curTemplate = &sTemplates[0];
|
||||
while (curTemplate->tScript != NULL) {
|
||||
const CScript *testScript = curTemplate->tScript;
|
||||
opcodetype opcode1, opcode2;
|
||||
vector<unsigned char> vch1;
|
||||
|
||||
opcodetype opcode1, opcode2;
|
||||
vector<unsigned char> vch1, vch2;
|
||||
vSolutionsRet.clear();
|
||||
|
||||
// Compare
|
||||
CScript::const_iterator pc1 = script1.begin();
|
||||
CScript::const_iterator pc2 = script2.begin();
|
||||
CScript::const_iterator pc2 = testScript->begin();
|
||||
CScript::const_iterator end1 = script1.end();
|
||||
CScript::const_iterator end2 = testScript->end();
|
||||
|
||||
loop
|
||||
{
|
||||
if (pc1 == script1.end() && pc2 == script2.end())
|
||||
if (pc1 == end1 && pc2 == end2)
|
||||
{
|
||||
// Found a match
|
||||
typeRet = tplate.first;
|
||||
typeRet = curTemplate->txType;
|
||||
if (typeRet == TX_MULTISIG)
|
||||
{
|
||||
// Additional checks for TX_MULTISIG:
|
||||
@ -1180,9 +1195,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
||||
if (!script1.GetOp2(pc1, opcode1, &vch1))
|
||||
break;
|
||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
||||
if (!testScript->GetOp2(pc2, opcode2, NULL)) // templates push no data, no need to get vch
|
||||
break;
|
||||
|
||||
// Template matching opcodes:
|
||||
@ -1191,10 +1206,10 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
while (vch1.size() >= 33 && vch1.size() <= 120)
|
||||
{
|
||||
vSolutionsRet.push_back(vch1);
|
||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
||||
if (!script1.GetOp2(pc1, opcode1, &vch1))
|
||||
break;
|
||||
}
|
||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
||||
if (!testScript->GetOp2(pc2, opcode2, NULL))
|
||||
break;
|
||||
// Normal situation is to fall through
|
||||
// to other if/else statements
|
||||
@ -1223,16 +1238,18 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
||||
else if (opcode1 != opcode2)
|
||||
{
|
||||
// Others must match exactly
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curTemplate++;
|
||||
}
|
||||
|
||||
vSolutionsRet.clear();
|
||||
typeRet = TX_NONSTANDARD;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1446,6 +1463,67 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
return false;
|
||||
}
|
||||
|
||||
// ExtractDestinationAndMine is an amalgam of ExtractDestination and IsMine. Since they do very
|
||||
// similar work and are both called from CWalletTx::GetAmounts we can reduce kill two birds with
|
||||
// one stone by combining them and speed CWalletTx::GetAmounts considerably.
|
||||
|
||||
bool ExtractDestinationAndMine(const CKeyStore &keystore, const CScript& scriptPubKey, CTxDestination& addressRet, bool *outIsMine)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
bool hasDestination = false;
|
||||
|
||||
*outIsMine = false;
|
||||
|
||||
if (Solver(scriptPubKey, whichType, vSolutions)) {
|
||||
CKeyID keyID;
|
||||
|
||||
switch (whichType) {
|
||||
case TX_NONSTANDARD:
|
||||
break;
|
||||
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
addressRet = keyID;
|
||||
*outIsMine = keystore.HaveKey(keyID);
|
||||
hasDestination = true;
|
||||
break;
|
||||
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
addressRet = keyID;
|
||||
*outIsMine = keystore.HaveKey(keyID);
|
||||
hasDestination = true;
|
||||
break;
|
||||
|
||||
case TX_SCRIPTHASH: {
|
||||
CScript subscript;
|
||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
|
||||
addressRet = scriptID;
|
||||
hasDestination = true;
|
||||
|
||||
if (keystore.GetCScript(scriptID, subscript))
|
||||
*outIsMine = IsMine(keystore, subscript);
|
||||
}
|
||||
break;
|
||||
|
||||
case TX_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.
|
||||
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
|
||||
*outIsMine = HaveKeys(keys, keystore) == keys.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasDestination;
|
||||
}
|
||||
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
|
||||
{
|
||||
addressRet.clear();
|
||||
|
||||
15
src/script.h
15
src/script.h
@ -426,14 +426,14 @@ public:
|
||||
|
||||
bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
|
||||
{
|
||||
const_iterator scriptEnd = end();
|
||||
|
||||
opcodeRet = OP_INVALIDOPCODE;
|
||||
if (pvchRet)
|
||||
pvchRet->clear();
|
||||
if (pc >= end())
|
||||
return false;
|
||||
|
||||
// Read instruction
|
||||
if (end() - pc < 1)
|
||||
if (scriptEnd - pc < 1)
|
||||
return false;
|
||||
unsigned int opcode = *pc++;
|
||||
|
||||
@ -447,13 +447,13 @@ public:
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA1)
|
||||
{
|
||||
if (end() - pc < 1)
|
||||
if (scriptEnd - pc < 1)
|
||||
return false;
|
||||
nSize = *pc++;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA2)
|
||||
{
|
||||
if (end() - pc < 2)
|
||||
if (scriptEnd - pc < 2)
|
||||
return false;
|
||||
nSize = 0;
|
||||
memcpy(&nSize, &pc[0], 2);
|
||||
@ -461,12 +461,12 @@ public:
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA4)
|
||||
{
|
||||
if (end() - pc < 4)
|
||||
if (scriptEnd - pc < 4)
|
||||
return false;
|
||||
memcpy(&nSize, &pc[0], 4);
|
||||
pc += 4;
|
||||
}
|
||||
if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize)
|
||||
if (scriptEnd - pc < 0 || (unsigned int)(scriptEnd - pc) < nSize)
|
||||
return false;
|
||||
if (pvchRet)
|
||||
pvchRet->assign(pc, pc + nSize);
|
||||
@ -676,6 +676,7 @@ bool IsStandard(const CScript& scriptPubKey);
|
||||
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
||||
bool ExtractDestinationAndMine(const CKeyStore &keystore, const CScript& scriptPubKey, CTxDestination& addressRet, bool *outMine);
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
|
||||
@ -570,6 +570,17 @@ int64 CWallet::GetDebit(const CTxIn &txin) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CWallet::HasAddress(const CTxDestination &txDest) const
|
||||
{
|
||||
bool hasAddress = false;
|
||||
|
||||
LOCK(cs_wallet);
|
||||
if (mapAddressBook.count(txDest))
|
||||
hasAddress = true;
|
||||
|
||||
return hasAddress;
|
||||
}
|
||||
|
||||
bool CWallet::IsChange(const CTxOut& txout) const
|
||||
{
|
||||
CTxDestination address;
|
||||
@ -638,6 +649,8 @@ int CWalletTx::GetRequestCount() const
|
||||
void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived,
|
||||
list<pair<CTxDestination, int64> >& listSent, int64& nFee, string& strSentAccount) const
|
||||
{
|
||||
CTxDestination address;
|
||||
|
||||
nFee = 0;
|
||||
listReceived.clear();
|
||||
listSent.clear();
|
||||
@ -651,28 +664,43 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived,
|
||||
nFee = nDebit - nValueOut;
|
||||
}
|
||||
|
||||
if (!fMineCached)
|
||||
vfMine.resize(vout.size());
|
||||
|
||||
// Sent/received.
|
||||
BOOST_FOREACH(const CTxOut& txout, vout)
|
||||
{
|
||||
CTxDestination address;
|
||||
vector<unsigned char> vchPubKey;
|
||||
if (!ExtractDestination(txout.scriptPubKey, address))
|
||||
{
|
||||
printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
|
||||
this->GetHash().ToString().c_str());
|
||||
for (unsigned int i = 0; i < vout.size(); i++) {
|
||||
const CTxOut &txout = vout[i];
|
||||
bool isMine = false;
|
||||
bool warnUnkownTX = false;
|
||||
|
||||
if (!fMineCached) {
|
||||
address = CNoDestination();
|
||||
warnUnkownTX = !ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine);
|
||||
vfMine[i] = isMine;
|
||||
}
|
||||
else {
|
||||
if (vfMine[i]) {
|
||||
isMine = true; // already know this is ours, just fetch address
|
||||
address = CNoDestination();
|
||||
warnUnkownTX = !ExtractDestination(txout.scriptPubKey, address);
|
||||
}
|
||||
}
|
||||
if (warnUnkownTX) {
|
||||
printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString().c_str());
|
||||
}
|
||||
|
||||
// Don't report 'change' txouts
|
||||
if (nDebit > 0 && pwallet->IsChange(txout))
|
||||
continue;
|
||||
if (nDebit > 0) {
|
||||
if (isMine && !pwallet->HasAddress(address)) // Don't report 'change' txouts
|
||||
continue;
|
||||
|
||||
if (nDebit > 0)
|
||||
listSent.push_back(make_pair(address, txout.nValue));
|
||||
}
|
||||
|
||||
if (pwallet->IsMine(txout))
|
||||
if (isMine)
|
||||
listReceived.push_back(make_pair(address, txout.nValue));
|
||||
}
|
||||
|
||||
fMineCached = true;
|
||||
}
|
||||
|
||||
void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nReceived,
|
||||
|
||||
@ -213,6 +213,7 @@ public:
|
||||
throw std::runtime_error("CWallet::GetCredit() : value out of range");
|
||||
return (IsMine(txout) ? txout.nValue : 0);
|
||||
}
|
||||
bool HasAddress(const CTxDestination &txDest) const;
|
||||
bool IsChange(const CTxOut& txout) const;
|
||||
int64 GetChange(const CTxOut& txout) const
|
||||
{
|
||||
@ -383,6 +384,8 @@ public:
|
||||
int64 nOrderPos; // position in ordered transaction list
|
||||
|
||||
// memory only
|
||||
mutable std::vector<char> vfMine; // which outputs are mine
|
||||
mutable bool fMineCached;
|
||||
mutable bool fDebitCached;
|
||||
mutable bool fCreditCached;
|
||||
mutable bool fImmatureCreditCached;
|
||||
@ -426,6 +429,8 @@ public:
|
||||
fFromMe = false;
|
||||
strFromAccount.clear();
|
||||
vfSpent.clear();
|
||||
vfMine.clear();
|
||||
fMineCached = false;
|
||||
fDebitCached = false;
|
||||
fCreditCached = false;
|
||||
fImmatureCreditCached = false;
|
||||
@ -519,6 +524,8 @@ public:
|
||||
// make sure balances are recalculated
|
||||
void MarkDirty()
|
||||
{
|
||||
vfMine.clear();
|
||||
fMineCached = false;
|
||||
fCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fDebitCached = false;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user