CCoinsViewCache::GetValueIn(…) performs money summation like this:
0CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
1{
2 if (tx.IsCoinBase())
3 return 0;
4
5 CAmount nResult = 0;
6 for (unsigned int i = 0; i < tx.vin.size(); i++)
7 nResult += AccessCoin(tx.vin[i].prevout).out.nValue;
8
9 return nResult;
10}
Note that no check is done to make sure that the resulting nResult is such that it stays within the money bounds (MoneyRange(nResult)), or that the summation does not trigger a signed integer overflow.
Proof of concept output:
0coins.cpp:243:17: runtime error: signed integer overflow: 9223200000000000000 + 2100000000000000 cannot be represented in type 'long'
1GetValueIn = -9221444073709551616
Proof of concept code:
0CMutableTransaction mutable_transaction;
1mutable_transaction.vin.resize(4393);
2
3Coin coin;
4coin.out.nValue = MAX_MONEY;
5assert(MoneyRange(coin.out.nValue));
6
7CCoinsCacheEntry coins_cache_entry;
8coins_cache_entry.coin = coin;
9coins_cache_entry.flags = CCoinsCacheEntry::DIRTY;
10
11CCoinsView backend_coins_view;
12CCoinsViewCache coins_view_cache{&backend_coins_view};
13CCoinsMap coins_map;
14coins_map.emplace(COutPoint{}, std::move(coins_cache_entry));
15coins_view_cache.BatchWrite(coins_map, {});
16
17const CAmount total_value_in = coins_view_cache.GetValueIn(CTransaction{mutable_transaction});
18std::cout << "GetValueIn = " << total_value_in << std::endl;
As far as I can tell CCoinsViewCache::GetValueIn is unused outside of tests:
0$ git grep GetValueIn ":(exclude)src/test/" ":(exclude)src/bench/"
1src/coins.cpp:CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
2src/coins.h: CAmount GetValueIn(const CTransaction& tx) const;
3src/primitives/transaction.h: // GetValueIn() is a method on CCoinsViewCache, because
I suggest we drop the unused CCoinsViewCache::GetValueIn(…).
Any objections? :)