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; 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++) { 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()) { if (confValue.IsCommitment()) {
// Rangeproof must exist // Rangeproof must exist
if (tx.wit.vtxinwit.size() <= nIn) { if (tx.wit.vtxinwit.size() <= nIn) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Transaction issuance is already blinded but has no attached rangeproof.")); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Transaction issuance is already blinded but has no attached rangeproof."));
} }
CTxInWitness& txinwit = tx.wit.vtxinwit[nIn]; 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 blinding_factor;
uint256 asset_blinding_factor; uint256 asset_blinding_factor;
CAmount amount; CAmount amount;
@ -728,29 +730,29 @@ void FillBlinds(CMutableTransaction& tx, bool fUseWallet, std::vector<uint256>&
// Wipe out confidential info from issuance // Wipe out confidential info from issuance
vchRangeproof.clear(); vchRangeproof.clear();
confValue = CConfidentialValue(amount); confValue = CConfidentialValue(amount);
// One key both blinded values, single key needed for issuance reveal // One key blinds both values, single key needed for issuance reveal
asset_keys.push_back(pwalletMain->GetBlindingKey(&blindingScript)); issuance_blinding_keys.push_back(pwalletMain->GetBlindingKey(&blindingScript));
token_keys.push_back(pwalletMain->GetBlindingKey(&blindingScript));
continue; continue;
} }
#endif #endif
// If no wallet, or unable to unblind, leave it alone in next blinding step // If no wallet, or unable to unblind, leave it alone in next blinding step
asset_keys.push_back(CKey()); issuance_blinding_keys.push_back(CKey());
token_keys.push_back(CKey());
} else { } else if (confValue.IsExplicit()) {
// Without wallet, nothing to be done. // Without wallet, nothing to be done.
asset_keys.push_back(CKey()); issuance_blinding_keys.push_back(CKey());
token_keys.push_back(CKey());
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
// Use wallet to generate blindingkey used directly as nonce // Use wallet to generate blindingkey used directly as nonce
// as user is not "sending" to anyone. // as user is not "sending" to anyone.
// Always assumed we want to blind here. // Always assumed we want to blind here.
// TODO Signal intent for all blinding via API including replacing nonce commitment // TODO Signal intent for all blinding via API including replacing nonce commitment
if (fUseWallet) { if (fUseWallet) {
asset_keys[asset_keys.size()-1] = pwalletMain->GetBlindingKey(&blindingScript); issuance_blinding_keys[issuance_blinding_keys.size()-1] = pwalletMain->GetBlindingKey(&blindingScript);
token_keys[token_keys.size()-1] = pwalletMain->GetBlindingKey(&blindingScript);
} }
#endif #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 input raw transaction cannot have already-blinded outputs.\n"
"The output keys used can be specified by using a confidential address in createrawtransaction.\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" "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" "\nArguments:\n"
"1. \"hexstring\", (string, required) A hex-encoded raw transaction.\n" "1. \"hexstring\", (string, required) A hex-encoded raw transaction.\n"
@ -903,9 +906,9 @@ UniValue rawblindrawtransaction(const JSONRPCRequest& request)
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
UniValue blindrawtransaction(const JSONRPCRequest& request) 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( 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" "\nConvert one or more outputs of a raw transaction into confidential ones using only wallet inputs.\n"
"Returns the hex-encoded raw transaction.\n" "Returns the hex-encoded raw transaction.\n"
"The output keys used can be specified by using a confidential address in createrawtransaction.\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" "\nArguments:\n"
"1. \"hexstring\", (string, required) A hex-encoded raw transaction.\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" "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" " \"assetcommitment\" (string, optional) A hex-encoded asset commitment, one for each input.\n"
" Null commitments must be \"\".\n" " Null commitments must be \"\".\n"
" ],\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" "\nResult:\n"
"\"transaction\" (string) hex string of the transaction\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)); RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
} else if (request.params.size() == 3){ } else if (request.params.size() == 3){
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)(UniValue::VARR)); 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 { } 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")); 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); LOCK(pwalletMain->cs_wallet);
std::vector<uint256> input_blinds; std::vector<uint256> input_blinds;
std::vector<uint256> input_asset_blinds; std::vector<uint256> input_asset_blinds;
std::vector<CAsset> input_assets; std::vector<CAsset> input_assets;
@ -976,6 +986,7 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
std::vector<uint256> output_asset_blinds; std::vector<uint256> output_asset_blinds;
std::vector<CAsset> output_assets; std::vector<CAsset> output_assets;
std::vector<CPubKey> output_pubkeys; std::vector<CPubKey> output_pubkeys;
std::vector<CKey> blind_issuance_asset;
int n_blinded_ins = 0; int n_blinded_ins = 0;
for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) { 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> asset_keys;
std::vector<CKey> token_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); 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? // How many are we trying to blind?
int numPubKeys = 0; int numPubKeys = 0;
unsigned int keyIndex = 0; unsigned int keyIndex = 0;
@ -1026,6 +1043,12 @@ UniValue blindrawtransaction(const JSONRPCRequest& request)
keyIndex = i; 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) { if (numPubKeys == 0 && n_blinded_ins == 0) {
// Vacuous, just return the transaction // 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 // 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 // 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?")); 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", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
{ "rawtransactions", "rawblindrawtransaction", &rawblindrawtransaction, false, {}}, { "rawtransactions", "rawblindrawtransaction", &rawblindrawtransaction, false, {}},
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
{ "rawtransactions", "blindrawtransaction", &blindrawtransaction, true, {}}, { "rawtransactions", "blindrawtransaction", &blindrawtransaction, true, {"hexstring", "ignoreblindfail", "asset_commitments", "blind_issuances", "totalblinder"}},
#endif #endif
{ "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} }, { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} }, { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },