main: fixed bug with overlapping address index keys

There was a bug where the spending address index could have the same key
as the receiving address index if the input and output indexes matched. This lead
to the output always overwriting the input index leading to incorrect balances
with missing spent amounts. This patch separates the two so that they have unique
keys so balances will be correctly calculated.
This commit is contained in:
Braydon Fuller 2016-03-23 14:41:08 -04:00 committed by Simon
parent 3d90427d0b
commit 70600ae1ff
3 changed files with 13 additions and 6 deletions

View File

@ -145,7 +145,7 @@ class AddressIndexTest(BitcoinTestFramework):
tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))]
send_amount = 1 * 100000000 + 12840 send_amount = 1 * 100000000 + 12840
change_amount = amount - send_amount - 10000 change_amount = amount - send_amount - 10000
tx.vout = [CTxOut(send_amount, scriptPubKey), CTxOut(change_amount, scriptPubKey2)] tx.vout = [CTxOut(change_amount, scriptPubKey2), CTxOut(send_amount, scriptPubKey)]
tx.rehash() tx.rehash()
signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8"))

View File

@ -2527,10 +2527,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
if (prevout.scriptPubKey.IsPayToScriptHash()) { if (prevout.scriptPubKey.IsPayToScriptHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22); vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, j), prevout.nValue * -1)); addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
} else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, j), prevout.nValue * -1)); addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
} else { } else {
continue; continue;
} }
@ -2564,10 +2564,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (out.scriptPubKey.IsPayToScriptHash()) { if (out.scriptPubKey.IsPayToScriptHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k), out.nValue)); addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) { } else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k), out.nValue)); addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
} else { } else {
continue; continue;
} }

View File

@ -338,6 +338,7 @@ struct CAddressIndexKey {
unsigned int txindex; unsigned int txindex;
uint256 txhash; uint256 txhash;
size_t outindex; size_t outindex;
bool spending;
size_t GetSerializeSize(int nType, int nVersion) const { size_t GetSerializeSize(int nType, int nVersion) const {
return 65; return 65;
@ -351,6 +352,8 @@ struct CAddressIndexKey {
ser_writedata32be(s, txindex); ser_writedata32be(s, txindex);
txhash.Serialize(s, nType, nVersion); txhash.Serialize(s, nType, nVersion);
ser_writedata32(s, outindex); ser_writedata32(s, outindex);
char f = spending;
ser_writedata8(s, f);
} }
template<typename Stream> template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) { void Unserialize(Stream& s, int nType, int nVersion) {
@ -360,16 +363,19 @@ struct CAddressIndexKey {
txindex = ser_readdata32be(s); txindex = ser_readdata32be(s);
txhash.Unserialize(s, nType, nVersion); txhash.Unserialize(s, nType, nVersion);
outindex = ser_readdata32(s); outindex = ser_readdata32(s);
char f = ser_readdata8(s);
spending = f;
} }
CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex, CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex,
uint256 txid, size_t outputIndex) { uint256 txid, size_t outputIndex, bool isSpending) {
type = addressType; type = addressType;
hashBytes = addressHash; hashBytes = addressHash;
blockHeight = height; blockHeight = height;
txindex = blockindex; txindex = blockindex;
txhash = txid; txhash = txid;
outindex = outputIndex; outindex = outputIndex;
spending = isSpending;
} }
CAddressIndexKey() { CAddressIndexKey() {
@ -383,6 +389,7 @@ struct CAddressIndexKey {
txindex = 0; txindex = 0;
txhash.SetNull(); txhash.SetNull();
outindex = 0; outindex = 0;
spending = false;
} }
}; };