CreateTransaction stores destination blinding keys,factors, and amounts

This commit is contained in:
instagibbs 2016-06-07 14:51:47 -04:00 committed by Gregory Sanders
parent 7acb86cf8b
commit e30340a8d6
4 changed files with 49 additions and 7 deletions

View file

@ -60,7 +60,7 @@ bool UnblindOutput(const CKey &key, const CTxOut& txout, CAmount& amount_out, ui
}
}
bool BlindOutputs(const std::vector<uint256 >& input_blinding_factors, const std::vector<uint256 >& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx)
bool BlindOutputs(const std::vector<uint256 >& input_blinding_factors, std::vector<uint256 >& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx)
{
assert(tx.vout.size() == output_blinding_factors.size());
assert(tx.vout.size() == output_pubkeys.size());
@ -84,10 +84,10 @@ bool BlindOutputs(const std::vector<uint256 >& input_blinding_factors, const std
//Number of outputs to newly blind
int nToBlind = 0;
for (size_t nOut = 0; nOut < tx.vout.size(); nOut++) {
assert((output_blinding_factors[nOut] != uint256()) == !tx.vout[nOut].nValue.IsAmount());
if (output_blinding_factors[nOut] != uint256()) {
blindptrs.push_back(output_blinding_factors[nOut].begin());
nBlindsOut++;
assert((output_blinding_factors[nOut] != uint256()) == !tx.vout[nOut].nValue.IsAmount());
if (output_blinding_factors[nOut] != uint256()) {
blindptrs.push_back(output_blinding_factors[nOut].begin());
nBlindsOut++;
} else {
if (output_pubkeys[nOut].IsValid()) {
nToBlind++;
@ -125,6 +125,7 @@ bool BlindOutputs(const std::vector<uint256 >& input_blinding_factors, const std
GetRandBytes(&blind[nBlinded][0], 32);
blindptrs.push_back(&blind[nBlinded++][0]);
}
output_blinding_factors[nOut] = uint256(std::vector<unsigned char>(blindptrs[blindptrs.size()-1], blindptrs[blindptrs.size()-1]+32));
nBlindsOut++;
// Create blinded value
CTxOutValue& value = tx.vout[nOut].nValue;

View file

@ -9,7 +9,12 @@ bool UnblindOutput(const CKey& blinding_key, const CTxOut& txout, CAmount& amoun
/* Returns false if there is no output to create where the non-zero resultant (inputs - outputs) factor can be put.
* The caller should retry with an extra blinded output, in that case.
* @param[in] input_blinding_factors - A vector of input blinding factors that will be used to create the balanced output blinding factors
* @param[in/out] output_blinding_factors - A vector of blinding factors. Null uint256 values are used to signal to the callee that a new blinding is needed. New blinds then replace the blank values.
* @param[in] blinding factor must be created for the commitments and range proof creation. Non-null is used to signal that the given value should be used.
* @param[in] output_pubkeys - If non-null, these pubkeys will be used in conjunction with the non-null passed in output blinding factors.
* @param[in/out] tx - The transaction to be modified.
*/
bool BlindOutputs(const std::vector<uint256>& input_blinding_factors, const std::vector<uint256>& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx);
bool BlindOutputs(const std::vector<uint256>& input_blinding_factors, std::vector<uint256>& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx);
#endif

View file

@ -1512,6 +1512,7 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
listReceived.push_back(output);
}
// This should not happen if transaction was created via CreateTransaction
if (nValueUnaccounted != 0 && nDebit > 0) {
if (nValueUnaccounted > 0 && nUnaccountedOutputs == 1) {
// There is exactly one sent output with unknown value. Reconstruct it.
@ -1911,6 +1912,26 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
return CTransaction(tx1) == CTransaction(tx2);
}
void CWalletTx::SetBlindingData(unsigned int nOut, CAmount amountIn, CPubKey pubkeyIn, uint256 blindingfactorIn) const
{
assert(nOut < tx->vout.size());
if (mapValue["blindingdata"].size() < (nOut + 1) * 74) {
mapValue["blindingdata"].resize(tx->vout.size() * 74);
}
unsigned char* it = (unsigned char*)(&mapValue["blindingdata"][0]) + 74 * nOut;
*it = 1;
memcpy(&*(it + 1), &amountIn, 8);
memcpy(&*(it + 9), blindingfactorIn.begin(), 32);
if (pubkeyIn.IsValid() && pubkeyIn.size() == 33) {
memcpy(&*(it + 41), pubkeyIn.begin(), 33);
} else {
memset(&*(it + 41), 0, 33);
}
}
void CWalletTx::GetBlindingData(unsigned int nOut, CAmount* pamountOut, CPubKey* ppubkeyOut, uint256* pblindingfactorOut) const
{
// Blinding data is cached in a serialized record mapWallet["blindingdata"].
@ -2718,6 +2739,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
txNew.nTxFee = nFeeRet;
LogPrintf("Created transaction (before blinding): %s", CTransaction(txNew).ToString());
// Store amounts for storage in mapValue
std::vector<CAmount> vAmounts;
// Create blinded outputs
std::vector<uint256> input_blinds;
std::vector<uint256> output_blinds;
@ -2731,6 +2755,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
output_blinds.push_back(uint256());
if (outAmounts)
outAmounts->push_back(txNew.vout[nOut].nValue.GetAmount());
vAmounts.push_back(txNew.vout[nOut].nValue.GetAmount());
}
if (!BlindOutputs(input_blinds, output_blinds, output_pubkeys, txNew)) {
// We need a dummy output to put a non-zero blinding factor.
@ -2740,6 +2765,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
txNew.vout.push_back(newTxOut);
output_pubkeys.push_back(GetBlindingPubKey(newTxOut.scriptPubKey));
output_blinds.push_back(uint256());
vAmounts.push_back(0);
// Now it has to succeed
bool ret = BlindOutputs(input_blinds, output_blinds, output_pubkeys, txNew);
assert(ret);
@ -2756,6 +2782,13 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CTransaction txNewConst(txNew);
dPriority = txNewConst.ComputePriority(dPriority, nBytes);
assert(vAmounts.size() == output_pubkeys.size());
assert(output_pubkeys.size() == output_blinds.size());
for (unsigned int i = 0; i< vAmounts.size(); i++) {
wtxNew.SetBlindingData(i, vAmounts[i], output_pubkeys[i], output_blinds[i]);
}
// Remove scriptSigs to eliminate the fee calculation dummy signatures
for (auto& vin : txNew.vin) {
vin.scriptSig = CScript();

View file

@ -439,12 +439,15 @@ public:
std::set<uint256> GetConflicts() const;
// For use in wallet transaction creation to remember 3rd party values
void SetBlindingData(unsigned int nOut, CAmount amountIn, CPubKey pubkeyIn, uint256 blindingfactorIn) const;
private:
void GetBlindingData(unsigned int nOut, CAmount* pamountOut, CPubKey* ppubkeyOut, uint256* pblindingfactorOut) const;
void WipeUnknownBlindingData() const;
public:
//! Returns either the value out (if it is to us) or -1
//! Returns either the value out (if it is known) or -1
CAmount GetValueOut(unsigned int nOut) const;
//! Returns either the blinding factor (if it is to us) or 0