Skip to content

Commit 433a57a

Browse files
committed
Merge #1156: [backport] Backport fixes from master to elements-22.x for rc5
37076d7 Bump version to -rc5 (Pablo Greco) 5629cae fs: Make compatible with boost 1.78 (Andrew Chow) 60b913e Elements-qt: Correctly display the amount in the sender's wallet after using Send button (Andrea Bonel) 872478b docs: describe elements transaction serialization format (#1148) (James Dorfman) dd2d758 fixed minor issues found in review (Allen Piscitello) 2da7d75 removing test that fails due to blinded issuances, which results in incorrect reissuance token ids (Allen Piscitello) 420de43 removing code to blind issuances. PSET should be modified to include an option to blind or unblind issuances, defaulting to unblind. (Allen Piscitello) Pull request description: Backport #1150 #1154 and #1148 from master. Backport bitcoin/bitcoin#24104 from Bitcoin Core Bump to -rc5 ACKs for top commit: jamesdorfman: utACK 37076d7. delta1: utACK 37076d7 Tree-SHA512: 616322f94c17008cc7fd582203c22b33c73b922269ab33fd13b270f491eda9b30d4f18efa3f7887e247bef46b63c4810f4084e409bea98120702c426a83343a8
2 parents 580230f + 37076d7 commit 433a57a

14 files changed

+671
-109
lines changed

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ AC_PREREQ([2.69])
22
define(_CLIENT_VERSION_MAJOR, 22)
33
define(_CLIENT_VERSION_MINOR, 0)
44
define(_CLIENT_VERSION_BUILD, 0)
5-
define(_CLIENT_VERSION_RC, 4)
5+
define(_CLIENT_VERSION_RC, 5)
66
define(_CLIENT_VERSION_IS_RELEASE, true)
77
define(_COPYRIGHT_YEAR, 2022)
88
define(_COPYRIGHT_HOLDERS,[The %s developers])

doc/elements-tx-format.md

Lines changed: 595 additions & 0 deletions
Large diffs are not rendered by default.

src/blindpsbt.cpp

Lines changed: 34 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -386,99 +386,54 @@ BlindingStatus BlindPSBT(PartiallySignedTransaction& psbt, std::map<uint32_t, st
386386
}
387387

388388
// Handle issuances
389-
if (input.m_issuance_value) {
390-
if (!input.m_issuance_value_commitment.IsCommitment() && input.m_issuance_rangeproof.size() == 0 && input.m_issuance_inflation_keys_rangeproof.size() == 0) {
391-
CAsset issuance_asset;
392-
CAsset reissuance_asset;
393-
394-
uint256 entropy;
395-
if (!input.m_issuance_blinding_nonce.IsNull()) {
396-
// Reissuance, use assetEntropy as the asset entropy
397-
entropy = input.m_issuance_asset_entropy;
398-
} else {
399-
// New issuance, make new entropy
400-
GenerateAssetEntropy(entropy, input.GetOutPoint(), input.m_issuance_asset_entropy);
401-
}
389+
if (input.m_issuance_value != std::nullopt || input.m_issuance_value_commitment.IsCommitment() || input.m_issuance_inflation_keys_amount != std::nullopt || input.m_issuance_inflation_keys_commitment.IsCommitment()) {
390+
CAsset issuance_asset;
391+
CAsset reissuance_asset;
392+
393+
uint256 entropy;
394+
if (!input.m_issuance_blinding_nonce.IsNull()) {
395+
// Reissuance, use assetEntropy as the asset entropy
396+
entropy = input.m_issuance_asset_entropy;
397+
} else {
398+
// New issuance, make new entropy
399+
GenerateAssetEntropy(entropy, input.GetOutPoint(), input.m_issuance_asset_entropy);
400+
}
402401

402+
if (input.m_issuance_value != std::nullopt || input.m_issuance_value_commitment.IsCommitment()) {
403403
// Asset isn't blinded yet. Add it to the list of input assets
404404
CalculateAsset(issuance_asset, entropy);
405405
fixed_input_tags.emplace_back();
406406
memcpy(fixed_input_tags.back().data, issuance_asset.begin(), 32);
407407
ephemeral_input_tags.emplace_back();
408-
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), issuance_asset.begin()) != 1) {
409-
return BlindingStatus::INVALID_ASSET;
408+
if (input.m_issuance_value_commitment.IsNull()) {
409+
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), issuance_asset.begin()) != 1) {
410+
return BlindingStatus::INVALID_ASSET;
411+
}
410412
}
411-
unsigned int iss_to_blind = 1; // Always do the first issuance blinding iteration for the issuance value
413+
else {
414+
memcpy(ephemeral_input_tags.back().data, input.m_issuance_value_commitment.vchCommitment.data(), 33);
415+
}
416+
input_asset_blinders.emplace_back();
417+
}
412418

413-
bool blind_issuance = our_issuances_to_blind.count(i) > 0;
419+
bool blind_issuance = input.m_issuance_value_commitment.IsCommitment();
414420

415-
if (input.m_issuance_blinding_nonce.IsNull() && input.m_issuance_inflation_keys_amount) {
416-
// New issuance, do reissuance token things
417-
CalculateReissuanceToken(reissuance_asset, entropy, blind_issuance);
418-
// Add the reissuance_asset to the list of input assets
419-
fixed_input_tags.emplace_back();
420-
memcpy(fixed_input_tags.back().data, reissuance_asset.begin(), 32);
421-
ephemeral_input_tags.emplace_back();
421+
if (input.m_issuance_blinding_nonce.IsNull() && (input.m_issuance_inflation_keys_amount != std::nullopt || input.m_issuance_inflation_keys_commitment.IsCommitment())) {
422+
// New issuance, do reissuance token things
423+
CalculateReissuanceToken(reissuance_asset, entropy, blind_issuance);
424+
// Add the reissuance_asset to the list of input assets
425+
fixed_input_tags.emplace_back();
426+
memcpy(fixed_input_tags.back().data, reissuance_asset.begin(), 32);
427+
ephemeral_input_tags.emplace_back();
428+
if (input.m_issuance_inflation_keys_commitment.IsNull()) {
422429
if (secp256k1_generator_generate(secp256k1_blind_context, &ephemeral_input_tags.back(), reissuance_asset.begin()) != 1) {
423430
return BlindingStatus::INVALID_ASSET;
424431
}
425-
iss_to_blind++; // If we have a reissuance, do the second blinding iteration for the inflation keys
426-
}
427-
428-
if (blind_issuance) {
429-
for (unsigned int blind_i = 0; blind_i < iss_to_blind; ++blind_i) {
430-
// To blind an issuance, both the issuance value and the number of inflation keys need to be blinded
431-
// Since this process is basically the same for both, do it in a loop and switch based on the index
432-
bool blind_value = blind_i == 0; // True for blinding the value, false for blinding the inflation keys
433-
CAmount value = blind_value ? *input.m_issuance_value : *input.m_issuance_inflation_keys_amount;
434-
CAsset asset = blind_value ? issuance_asset : reissuance_asset;
435-
CKey blinding_privkey = blind_value ? our_issuances_to_blind.at(i).first : our_issuances_to_blind.at(i).second;
436-
437-
uint256 value_blinder;
438-
GetStrongRandBytes(value_blinder.begin(), value_blinder.size());
439-
440-
// Create unblinded generator. Throw away everything except asset_gen
441-
uint256 asset_blinder;
442-
CConfidentialAsset conf_asset;
443-
secp256k1_generator asset_gen;
444-
CreateAssetCommitment(conf_asset, asset_gen, asset, asset_blinder);
445-
input_asset_blinders.push_back(asset_blinder);
446-
447-
// Compute the scalar for this blinding and add to the input scalar
448-
if (!ComputeAndAddToScalarOffset(input_scalar, value, asset_blinder, value_blinder)) return BlindingStatus::SCALAR_UNABLE;
449-
450-
// Create value commitment
451-
secp256k1_pedersen_commitment value_commit;
452-
CConfidentialValue conf_value;
453-
CreateValueCommitment(conf_value, value_commit, value_blinder, asset_gen, value);
454-
455-
// Nonce is the blinding key
456-
uint256 nonce = uint256(std::vector<unsigned char>(blinding_privkey.begin(), blinding_privkey.end()));
457-
458-
// Generate rangeproof
459-
std::vector<unsigned char> rangeproof;
460-
bool rangeresult = CreateValueRangeProof(rangeproof, value_blinder, nonce, value, CScript(), value_commit, asset_gen, asset, asset_blinder);
461-
assert(rangeresult);
462-
463-
// Create explicit value rangeproofs
464-
std::vector<unsigned char> blind_value_proof;
465-
rangeresult = CreateBlindValueProof(blind_value_proof, value_blinder, value, value_commit, asset_gen);
466-
assert(rangeresult);
467-
468-
if (blind_value) {
469-
input.m_issuance_value_commitment = conf_value;
470-
input.m_issuance_rangeproof = rangeproof;
471-
input.m_blind_issuance_value_proof = blind_value_proof;
472-
} else {
473-
input.m_issuance_inflation_keys_commitment = conf_value;
474-
input.m_issuance_inflation_keys_rangeproof = rangeproof;
475-
input.m_blind_issuance_inflation_keys_proof = blind_value_proof;
476-
}
477-
}
478432
}
479-
else {
480-
input_asset_blinders.emplace_back();
433+
else if(input.m_issuance_inflation_keys_commitment.IsCommitment()){
434+
memcpy(ephemeral_input_tags.back().data, input.m_issuance_inflation_keys_commitment.vchCommitment.data(), 33);
481435
}
436+
input_asset_blinders.emplace_back();
482437
}
483438
}
484439
}

src/interfaces/wallet.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct PartiallySignedTransaction;
3636
struct WalletContext;
3737
struct bilingual_str;
3838
typedef uint8_t isminefilter;
39+
struct BlindDetails;
3940

4041
namespace interfaces {
4142

@@ -140,13 +141,14 @@ class Wallet
140141
bool sign,
141142
int& change_pos,
142143
CAmount& fee,
143-
std::vector<CAmount>& out_amounts,
144+
BlindDetails* blind_details,
144145
bilingual_str& fail_reason) = 0;
145146

146147
//! Commit transaction.
147148
virtual void commitTransaction(CTransactionRef tx,
148149
WalletValueMap value_map,
149-
WalletOrderForm order_form) = 0;
150+
WalletOrderForm order_form,
151+
BlindDetails* blind_details) = 0;
150152

151153
//! Return whether transaction can be abandoned.
152154
virtual bool transactionCanBeAbandoned(const uint256& txid) = 0;

src/psbt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ CMutableTransaction PartiallySignedTransaction::GetUnsignedTx(bool force_unblind
135135
txin.assetIssuance.nAmount.SetNull();
136136
}
137137
if (input.m_issuance_inflation_keys_amount != std::nullopt && (input.m_issuance_inflation_keys_commitment.IsNull() || force_unblinded)) {
138-
txin.assetIssuance.nInflationKeys.SetToAmount(*input.m_issuance_value);
138+
txin.assetIssuance.nInflationKeys.SetToAmount(*input.m_issuance_inflation_keys_amount);
139139
}
140140
else if(!input.m_issuance_inflation_keys_commitment.IsNull()) {
141141
txin.assetIssuance.nInflationKeys = input.m_issuance_inflation_keys_commitment;

src/qt/sendcoinsdialog.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,13 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
281281

282282
// prepare transaction for getting txFee earlier
283283
m_current_transaction = std::make_unique<WalletModelTransaction>(recipients);
284+
if (g_con_elementsmode)
285+
m_current_blind_details = std::make_unique<BlindDetails>();
284286
WalletModel::SendCoinsReturn prepareStatus;
285287

286288
updateCoinControlState();
287289

288-
prepareStatus = model->prepareTransaction(*m_current_transaction, *m_coin_control);
290+
prepareStatus = model->prepareTransaction(*m_current_transaction, m_current_blind_details.get(), *m_coin_control);
289291

290292
// process prepareStatus and on error generate message shown to user
291293
processSendCoinsReturn(prepareStatus,
@@ -403,6 +405,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
403405
QString question_string, informative_text, detailed_text;
404406
if (!PrepareSendText(question_string, informative_text, detailed_text)) return;
405407
assert(m_current_transaction);
408+
assert(!g_con_elementsmode || m_current_blind_details);
406409

407410
const QString confirmation = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
408411
const QString confirmButtonText = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Create Unsigned") : tr("Sign and send");
@@ -461,7 +464,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
461464
if (complete) {
462465
const CTransactionRef tx = MakeTransactionRef(mtx);
463466
m_current_transaction->setWtx(tx);
464-
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
467+
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction, m_current_blind_details.get());
465468
// process sendStatus and on error generate message shown to user
466469
processSendCoinsReturn(sendStatus);
467470

@@ -520,7 +523,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
520523
} // msgBox.exec()
521524
} else {
522525
// now send the prepared transaction
523-
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
526+
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction, m_current_blind_details.get());
524527
// process sendStatus and on error generate message shown to user
525528
processSendCoinsReturn(sendStatus);
526529

@@ -537,11 +540,13 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
537540
}
538541
fNewRecipientAllowed = true;
539542
m_current_transaction.reset();
543+
m_current_blind_details.reset();
540544
}
541545

542546
void SendCoinsDialog::clear()
543547
{
544548
m_current_transaction.reset();
549+
m_current_blind_details.reset();
545550

546551
// Clear coin control settings
547552
m_coin_control->UnSelectAll();

src/qt/sendcoinsdialog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public Q_SLOTS:
6464
WalletModel *model;
6565
std::unique_ptr<CCoinControl> m_coin_control;
6666
std::unique_ptr<WalletModelTransaction> m_current_transaction;
67+
std::unique_ptr<BlindDetails> m_current_blind_details;
6768
bool fNewRecipientAllowed;
6869
bool fFeeMinimized;
6970
const PlatformStyle *platformStyle;

src/qt/walletmodel.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ bool WalletModel::validateAddress(const QString &address)
176176
return IsValidDestinationString(address.toStdString());
177177
}
178178

179-
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
179+
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, BlindDetails *blind_details, const CCoinControl& coinControl)
180180
{
181181
CAmountMap total;
182182
bool fSubtractFeeFromAmount = false;
@@ -236,10 +236,13 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
236236

237237
auto& newTx = transaction.getWtx();
238238
std::vector<CAmount> out_amounts;
239-
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, out_amounts, error);
239+
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, blind_details, error);
240240
transaction.setTransactionFee(nFeeRequired);
241241
if (fSubtractFeeFromAmount && newTx) {
242-
assert(out_amounts.size() == newTx->vout.size());
242+
if(blind_details) {
243+
out_amounts = blind_details->o_amounts;
244+
assert(out_amounts.size() == newTx->vout.size());
245+
}
243246
transaction.reassignAmounts(out_amounts, nChangePosRet);
244247
}
245248

@@ -266,7 +269,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
266269
return SendCoinsReturn(OK);
267270
}
268271

269-
WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction)
272+
WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction, BlindDetails *blind_details)
270273
{
271274
QByteArray transaction_array; /* store serialized transaction */
272275

@@ -279,7 +282,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
279282
}
280283

281284
auto& newTx = transaction.getWtx();
282-
wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm));
285+
wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm), blind_details);
283286

284287
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
285288
ssTx << *newTx;

src/qt/walletmodel.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ class WalletModel : public QObject
100100
};
101101

102102
// prepare transaction for getting txfee before sending coins
103-
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl);
103+
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, BlindDetails *blind_details, const CCoinControl& coinControl);
104104

105105
// Send coins to a list of recipients
106-
SendCoinsReturn sendCoins(WalletModelTransaction &transaction);
106+
SendCoinsReturn sendCoins(WalletModelTransaction &transaction, BlindDetails *blind_details);
107107

108108
// Wallet encryption
109109
bool setWalletEncrypted(const SecureString& passphrase);

src/wallet/interfaces.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,26 +248,25 @@ class WalletImpl : public Wallet
248248
bool sign,
249249
int& change_pos,
250250
CAmount& fee,
251-
std::vector<CAmount>& out_amounts,
251+
BlindDetails* blind_details,
252252
bilingual_str& fail_reason) override
253253
{
254254
LOCK(m_wallet->cs_wallet);
255255
CTransactionRef tx;
256256
FeeCalculation fee_calc_out;
257-
BlindDetails blind_details;
258257
if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos,
259-
fail_reason, coin_control, fee_calc_out, sign, gArgs.GetBoolArg("-blindedaddresses", g_con_elementsmode) ? &blind_details : nullptr)) {
258+
fail_reason, coin_control, fee_calc_out, sign, blind_details)) {
260259
return {};
261260
}
262-
out_amounts = blind_details.o_amounts;
263261
return tx;
264262
}
265263
void commitTransaction(CTransactionRef tx,
266264
WalletValueMap value_map,
267-
WalletOrderForm order_form) override
265+
WalletOrderForm order_form,
266+
BlindDetails* blind_details) override
268267
{
269268
LOCK(m_wallet->cs_wallet);
270-
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
269+
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form), blind_details);
271270
}
272271
bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
273272
bool abandonTransaction(const uint256& txid) override

0 commit comments

Comments
 (0)