| 838 | } |
| 839 | |
| 840 | static bool fillBlindDetails(BlindDetails* det, CWallet* wallet, CMutableTransaction& txNew, std::vector<CInputCoin>& selected_coins, bilingual_str& error) { |
| 841 | int num_inputs_blinded = 0; |
| 842 | |
| 843 | // Fill in input blinding details |
| 844 | for (const CInputCoin& coin : selected_coins) { |
| 845 | det->i_amount_blinds.push_back(coin.bf_value); |
| 846 | det->i_asset_blinds.push_back(coin.bf_asset); |
| 847 | det->i_assets.push_back(coin.asset); |
| 848 | det->i_amounts.push_back(coin.value); |
| 849 | if (coin.txout.nValue.IsCommitment() || coin.txout.nAsset.IsCommitment()) { |
| 850 | num_inputs_blinded++; |
| 851 | } |
| 852 | } |
| 853 | // Fill in output blinding details |
| 854 | for (size_t nOut = 0; nOut < txNew.vout.size(); nOut++) { |
| 855 | //TODO(CA) consider removing all blind setting before BlindTransaction as they get cleared anyway |
| 856 | det->o_amount_blinds.push_back(uint256()); |
| 857 | det->o_asset_blinds.push_back(uint256()); |
| 858 | det->o_assets.push_back(txNew.vout[nOut].nAsset.GetAsset()); |
| 859 | det->o_amounts.push_back(txNew.vout[nOut].nValue.GetAmount()); |
| 860 | } |
| 861 | |
| 862 | // There are a few edge-cases of blinding we need to take care of |
| 863 | // |
| 864 | // First, if there are blinded inputs but not outputs to blind |
| 865 | // We need this to go through, even though no privacy is gained. |
| 866 | if (num_inputs_blinded > 0 && det->num_to_blind == 0) { |
| 867 | // We need to make sure to dupe an asset that is in input set |
| 868 | //TODO Have blinding do some extremely minimal rangeproof |
| 869 | CTxOut newTxOut(det->o_assets.back(), 0, CScript() << OP_RETURN); |
| 870 | CPubKey blind_pub = wallet->GetBlindingPubKey(newTxOut.scriptPubKey); // irrelevant, just needs to be non-null |
| 871 | newTxOut.nNonce.vchCommitment = std::vector<unsigned char>(blind_pub.begin(), blind_pub.end()); |
| 872 | txNew.vout.push_back(newTxOut); |
| 873 | det->o_pubkeys.push_back(wallet->GetBlindingPubKey(newTxOut.scriptPubKey)); |
| 874 | det->o_amount_blinds.push_back(uint256()); |
| 875 | det->o_asset_blinds.push_back(uint256()); |
| 876 | det->o_amounts.push_back(0); |
| 877 | det->o_assets.push_back(det->o_assets.back()); |
| 878 | det->num_to_blind++; |
| 879 | wallet->WalletLogPrintf("Adding OP_RETURN output to complete blinding since there are %d blinded inputs and no blinded outputs\n", num_inputs_blinded); |
| 880 | |
| 881 | // No blinded inputs, but 1 blinded output |
| 882 | } else if (num_inputs_blinded == 0 && det->num_to_blind == 1) { |
| 883 | if (det->change_to_blind == 1) { |
| 884 | // Only 1 blinded change, unblind the change |
| 885 | //TODO Split up change instead if possible |
| 886 | if (det->ignore_blind_failure) { |
| 887 | det->num_to_blind--; |
| 888 | det->change_to_blind--; |
| 889 | txNew.vout[det->only_change_pos].nNonce.SetNull(); |
| 890 | det->o_pubkeys[det->only_change_pos] = CPubKey(); |
| 891 | det->o_amount_blinds[det->only_change_pos] = uint256(); |
| 892 | det->o_asset_blinds[det->only_change_pos] = uint256(); |
| 893 | wallet->WalletLogPrintf("Unblinding change at index %d due to lack of inputs and other outputs being blinded.\n", det->only_change_pos); |
| 894 | } else { |
| 895 | error = _("Change output could not be blinded as there are no blinded inputs and no other blinded outputs."); |
| 896 | return false; |
| 897 | } |
no test coverage detected