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))]
send_amount = 1 * 100000000 + 12840
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()
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]);
if (prevout.scriptPubKey.IsPayToScriptHash()) {
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()) {
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 {
continue;
}
@ -2564,10 +2564,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (out.scriptPubKey.IsPayToScriptHash()) {
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()) {
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 {
continue;
}

View File

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