Fixup (raw)blindrawtransaction

This commit is contained in:
Gregory Sanders 2018-11-29 16:01:35 -05:00
parent a5e9e0e40f
commit 2b22b6dfc6

View file

@ -712,14 +712,16 @@ void FillBlinds(CMutableTransaction& tx, bool fUseWallet, std::vector<uint256>&
CScript blindingScript = CScript() << OP_RETURN << std::vector<unsigned char>(tx.vin[nIn].prevout.hash.begin(), tx.vin[nIn].prevout.hash.end()) << tx.vin[nIn].prevout.n;
for (size_t nPseudo = 0; nPseudo < 2; nPseudo++) {
CConfidentialValue& confValue = (nPseudo == 0) ? issuance.nAmount : issuance.nInflationKeys;
bool issuance_asset = (nPseudo == 0);
std::vector<CKey>& issuance_blinding_keys = issuance_asset ? asset_keys : token_keys;
CConfidentialValue& confValue = issuance_asset ? issuance.nAmount : issuance.nInflationKeys;
if (confValue.IsCommitment()) {
// Rangeproof must exist
if (tx.wit.vtxinwit.size() <= nIn) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Transaction issuance is already blinded but has no attached rangeproof."));
}
CTxInWitness& txinwit = tx.wit.vtxinwit[nIn];
std::vector<unsigned char>& vchRangeproof = (nPseudo == 0) ? txinwit.vchIssuanceAmountRangeproof : txinwit.vchInflationKeysRangeproof;
std::vector<unsigned char>& vchRangeproof = issuance_asset ? txinwit.vchIssuanceAmountRangeproof : txinwit.vchInflationKeysRangeproof;
uint256 blinding_factor;
uint256 asset_blinding_factor;
CAmount amount;
@ -728,29 +730,29 @@ void FillBlinds(CMutableTransaction& tx, bool fUseWallet, std::vector<uint256>&
// Wipe out confidential info from issuance
vchRangeproof.clear();
confValue = CConfidentialValue(amount);
// One key both blinded values, single key needed for issuance reveal
asset_keys.push_back(pwalletMain->GetBlindingKey(&blindingScript));
token_keys.push_back(pwalletMain->GetBlindingKey(&blindingScript));
// One key blinds both values, single key needed for issuance reveal
issuance_blinding_keys.push_back(pwalletMain->GetBlindingKey(&blindingScript));
continue;
}
#endif
// If no wallet, or unable to unblind, leave it alone in next blinding step
asset_keys.push_back(CKey());
token_keys.push_back(CKey());
} else {
issuance_blinding_keys.push_back(CKey());
} else if (confValue.IsExplicit()) {
// Without wallet, nothing to be done.
asset_keys.push_back(CKey());
token_keys.push_back(CKey());
issuance_blinding_keys.push_back(CKey());
#ifdef ENABLE_WALLET
// Use wallet to generate blindingkey used directly as nonce
// as user is not "sending" to anyone.
// Always assumed we want to blind here.
// TODO Signal intent for all blinding via API including replacing nonce commitment
if (fUseWallet) {
asset_keys[asset_keys.size()-1] = pwalletMain->GetBlindingKey(&blindingScript);
token_keys[token_keys.size()-1] = pwalletMain->GetBlindingKey(&blindingScript);
issuance_blinding_keys[issuance_blinding_keys.size()-1] = pwalletMain->GetBlindingKey(&blindingScript);
}
#endif
} else {
// Null or invalid, don't try anything but append an empty key
issuance_blinding_keys.push_back(CKey());
}
}
}
@ -766,6 +768,7 @@ UniValue rawblindrawtransaction(const JSONRPCRequest& request)
"The input raw transaction cannot have already-blinded outputs.\n"
"The output keys used can be specified by using a confidential address in createrawtransaction.\n"
"If an additional blinded output is required to make a balanced blinding, a 0-value unspendable output will be added. Since there is no access to the wallet the blinding pubkey from the last output with blinding key will be repeated.\n"
"You can not blind issuances with this call.\n"
"\nArguments:\n"
"1. \"hexstring\", (string, required) A hex-encoded raw transaction.\n"
@ -903,9 +906,9 @@ UniValue rawblindrawtransaction(const JSONRPCRequest& request)
#ifdef ENABLE_WALLET
UniValue blindrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() < 1 || request.params.size() > 4))
if (request.fHelp || (request.params.size() < 1 || request.params.size() > 5))
throw runtime_error(
"blindrawtransaction \"hexstring\" ( ignoreblindfail [\"assetcommitment,...\"] totalblinder )\n"
"blindrawtransaction \"hexstring\" ( ignoreblindfail [\"assetcommitment,...\"] blind_issuances \"totalblinder\" )\n"
"\nConvert one or more outputs of a raw transaction into confidential ones using only wallet inputs.\n"
"Returns the hex-encoded raw transaction.\n"
"The output keys used can be specified by using a confidential address in createrawtransaction.\n"
@ -914,11 +917,13 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"hexstring\", (string, required) A hex-encoded raw transaction.\n"
"2. \"ignoreblindfail\"\" (bool, optional, default=true) Return a transaction even when a blinding attempt fails due to number of blinded inputs/outputs.\n"
"3. [ (array, optional) An array of input asset generators. If provided, this list must be empty, or match the final input commitment list, including ordering, to make a valid surjection proof. This list does not include generators for issuances, as these assets are inherently unblinded.\n"
"3. \"asset_commitments\" \n"
" [ (array, optional) An array of input asset generators. If provided, this list must be empty, or match the final input commitment list, including ordering, to make a valid surjection proof. This list does not include generators for issuances, as these assets are inherently unblinded.\n"
" \"assetcommitment\" (string, optional) A hex-encoded asset commitment, one for each input.\n"
" Null commitments must be \"\".\n"
" ],\n"
"4. \"totalblinder\" (string, optional) Ignored for now.\n"
"4. \"blind_issuances\" (bool, optional, default=true) Blind the issuances found in the raw transaction or not. All issuances will be blinded if true. \n"
"5. \"totalblinder\" (string, optional) Ignored for now.\n"
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
@ -930,8 +935,10 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
} else if (request.params.size() == 3){
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)(UniValue::VARR));
} else if (request.params.size() == 4){
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)(UniValue::VARR)(UniValue::VBOOL));
} else {
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)(UniValue::VARR)(UniValue::VSTR));
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)(UniValue::VARR)(UniValue::VBOOL)(UniValue::VSTR));
}
vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
@ -966,8 +973,11 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
}
}
bool blind_issuances = request.params[3].isNull() || request.params[3].get_bool();
LOCK(pwalletMain->cs_wallet);
std::vector<uint256> input_blinds;
std::vector<uint256> input_asset_blinds;
std::vector<CAsset> input_assets;
@ -976,6 +986,7 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
std::vector<uint256> output_asset_blinds;
std::vector<CAsset> output_assets;
std::vector<CPubKey> output_pubkeys;
std::vector<CKey> blind_issuance_asset;
int n_blinded_ins = 0;
for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) {
@ -1014,8 +1025,14 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
std::vector<CKey> asset_keys;
std::vector<CKey> token_keys;
// This fills out issuance blinding data for you from the wallet itself
FillBlinds(tx, true, output_blinds, output_asset_blinds, output_pubkeys, asset_keys, token_keys);
if (!blind_issuances) {
asset_keys.clear();
token_keys.clear();
}
// How many are we trying to blind?
int numPubKeys = 0;
unsigned int keyIndex = 0;
@ -1026,6 +1043,12 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
keyIndex = i;
}
}
for (const auto& key : asset_keys) {
if (key.IsValid()) numPubKeys++;
}
for (const auto& key : token_keys) {
if (key.IsValid()) numPubKeys++;
}
if (numPubKeys == 0 && n_blinded_ins == 0) {
// Vacuous, just return the transaction
@ -1046,7 +1069,7 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
}
}
if (BlindTransaction(input_blinds, input_asset_blinds, input_assets, input_amounts, output_blinds, output_asset_blinds, output_pubkeys, std::vector<CKey>(), std::vector<CKey>(), tx, (auxiliary_generators.size() ? &auxiliary_generators : NULL)) != numPubKeys) {
if (BlindTransaction(input_blinds, input_asset_blinds, input_assets, input_amounts, output_blinds, output_asset_blinds, output_pubkeys, asset_keys, token_keys, tx, (auxiliary_generators.size() ? &auxiliary_generators : NULL)) != numPubKeys) {
// TODO Have more rich return values, communicating to user what has been blinded
// User may be ok not blinding something that for instance has no corresponding type on input
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Unable to blind transaction: Are you sure each asset type to blind is represented in the inputs?"));
@ -1567,7 +1590,7 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
{ "rawtransactions", "rawblindrawtransaction", &rawblindrawtransaction, false, {}},
#ifdef ENABLE_WALLET
{ "rawtransactions", "blindrawtransaction", &blindrawtransaction, true, {}},
{ "rawtransactions", "blindrawtransaction", &blindrawtransaction, true, {"hexstring", "ignoreblindfail", "asset_commitments", "blind_issuances", "totalblinder"}},
#endif
{ "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },