Skip to content

Commit c273308

Browse files
committed
Merge bitcoin#18027: "PSBT Operations" dialog
931dd47 Make lint-spelling.py happy (Glenn Willen) 11a0ffb [gui] Load PSBT from clipboard (Glenn Willen) a6cb0b0 [gui] PSBT Operations Dialog (sign & broadcast) (Glenn Willen) 5dd0c03 FillPSBT: report number of inputs signed (or would sign) (Glenn Willen) 9e7b23b Improve TransactionErrorString messages. (Glenn Willen) Pull request description: Add a "PSBT Operations" dialog, reached from the "Load PSBT..." menu item, giving options to sign or broadcast the loaded PSBT as appropriate, as well as copying the result to the clipboard or saving it to a file. This is based on Sjors' bitcoin#17509, and depends on that PR going in first. (It effectively replaces the small "load PSBT" dialog from that PR with a more feature-rich one.) Some notes: * The way I display status information is maybe unusual (a status bar, rather than messageboxes.) I think it's helpful to have the information in it be persistent rather than transitory. But if people dislike it, I would probably move the "current state of the transaction" info to the top line of the main label, and the "what action just happened, and did it succeed" info into a messagebox. * I don't really know much about the translation/localization stuff. I put tr() in all the places it seemed like it ought to go. I did not attempt to translate the result of TransactionErrorString (which is shared by GUI and non-GUI code); I don't know if that's correct, but it matches the "error messages in logs should be googleable in English" heuristic. I don't know whether there are things I should be doing to reduce translator effort (like minimizing the total number of distinct message strings I use, or something.) * I don't really know how (if?) automated testing is applied to GUI code. I can make a list of PSBTs exercising all the codepaths for manual testing, if that's the right approach. Input appreciated. ACKs for top commit: instagibbs: tested ACK bitcoin@931dd47 Sjors: re-tACK 931dd47 jb55: ACK 931dd47 achow101: ACK 931dd47 Tree-SHA512: ade52471a2242f839a8bd6a1fd231443cc4b43bb9c1de3fb5ace7c5eb59eca99b1f2e9f17dfdb4b08d84d91f5fd65677db1433dd03eef51c7774963ef4e2e74f
2 parents 47a30ef + 931dd47 commit c273308

24 files changed

+585
-89
lines changed

build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<ClCompile Include="..\..\src\qt\paymentserver.cpp" />
3636
<ClCompile Include="..\..\src\qt\peertablemodel.cpp" />
3737
<ClCompile Include="..\..\src\qt\platformstyle.cpp" />
38+
<ClCompile Include="..\..\src\qt\psbtoperationsdialog.cpp" />
3839
<ClCompile Include="..\..\src\qt\qrimagewidget.cpp" />
3940
<ClCompile Include="..\..\src\qt\qvalidatedlineedit.cpp" />
4041
<ClCompile Include="..\..\src\qt\qvaluecombobox.cpp" />
@@ -87,6 +88,7 @@
8788
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_paymentserver.cpp" />
8889
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_peertablemodel.cpp" />
8990
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_platformstyle.cpp" />
91+
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_psbtoperationsdialog.cpp" />
9092
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_qrimagewidget.cpp" />
9193
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_qvalidatedlineedit.cpp" />
9294
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_qvaluecombobox.cpp" />

src/Makefile.qt.include

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ QT_FORMS_UI = \
2525
qt/forms/openuridialog.ui \
2626
qt/forms/optionsdialog.ui \
2727
qt/forms/overviewpage.ui \
28+
qt/forms/psbtoperationsdialog.ui \
2829
qt/forms/receivecoinsdialog.ui \
2930
qt/forms/receiverequestdialog.ui \
3031
qt/forms/debugwindow.ui \
@@ -61,6 +62,7 @@ QT_MOC_CPP = \
6162
qt/moc_overviewpage.cpp \
6263
qt/moc_peertablemodel.cpp \
6364
qt/moc_paymentserver.cpp \
65+
qt/moc_psbtoperationsdialog.cpp \
6466
qt/moc_qrimagewidget.cpp \
6567
qt/moc_qvalidatedlineedit.cpp \
6668
qt/moc_qvaluecombobox.cpp \
@@ -132,6 +134,7 @@ BITCOIN_QT_H = \
132134
qt/paymentserver.h \
133135
qt/peertablemodel.h \
134136
qt/platformstyle.h \
137+
qt/psbtoperationsdialog.h \
135138
qt/qrimagewidget.h \
136139
qt/qvalidatedlineedit.h \
137140
qt/qvaluecombobox.h \
@@ -245,6 +248,7 @@ BITCOIN_QT_WALLET_CPP = \
245248
qt/openuridialog.cpp \
246249
qt/overviewpage.cpp \
247250
qt/paymentserver.cpp \
251+
qt/psbtoperationsdialog.cpp \
248252
qt/qrimagewidget.cpp \
249253
qt/receivecoinsdialog.cpp \
250254
qt/receiverequestdialog.cpp \

src/interfaces/wallet.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,10 @@ class WalletImpl : public Wallet
335335
bool sign,
336336
bool bip32derivs,
337337
PartiallySignedTransaction& psbtx,
338-
bool& complete) override
338+
bool& complete,
339+
size_t* n_signed) override
339340
{
340-
return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs);
341+
return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs, n_signed);
341342
}
342343
WalletBalances getBalances() override
343344
{

src/interfaces/wallet.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ class Wallet
197197
bool sign,
198198
bool bip32derivs,
199199
PartiallySignedTransaction& psbtx,
200-
bool& complete) = 0;
200+
bool& complete,
201+
size_t* n_signed) = 0;
201202

202203
//! Get balances.
203204
virtual WalletBalances getBalances() = 0;

src/psbt.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,17 @@ bool PSBTInputSigned(const PSBTInput& input)
214214
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
215215
}
216216

217+
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
218+
size_t count = 0;
219+
for (const auto& input : psbt.inputs) {
220+
if (!PSBTInputSigned(input)) {
221+
count++;
222+
}
223+
}
224+
225+
return count;
226+
}
227+
217228
void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index)
218229
{
219230
const CTxOut& out = psbt.tx->vout.at(index);

src/psbt.h

+3
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ bool PSBTInputSigned(const PSBTInput& input);
579579
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
580580
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool use_dummy = false);
581581

582+
/** Counts the unsigned inputs of a PSBT. */
583+
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt);
584+
582585
/** Updates a PSBTOutput with information from provider.
583586
*
584587
* This fills in the redeem_script, witness_script, and hd_keypaths where possible.

src/qt/bitcoingui.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,10 @@ void BitcoinGUI::createActions()
321321
signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
322322
verifyMessageAction = new QAction(tr("&Verify message..."), this);
323323
verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
324-
m_load_psbt_action = new QAction(tr("Load PSBT..."), this);
324+
m_load_psbt_action = new QAction(tr("&Load PSBT from file..."), this);
325325
m_load_psbt_action->setStatusTip(tr("Load Partially Signed Bitcoin Transaction"));
326+
m_load_psbt_clipboard_action = new QAction(tr("Load PSBT from clipboard..."), this);
327+
m_load_psbt_clipboard_action->setStatusTip(tr("Load Partially Signed Bitcoin Transaction from clipboard"));
326328

327329
openRPCConsoleAction = new QAction(tr("Node window"), this);
328330
openRPCConsoleAction->setStatusTip(tr("Open node debugging and diagnostic console"));
@@ -381,6 +383,7 @@ void BitcoinGUI::createActions()
381383
connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
382384
connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); });
383385
connect(m_load_psbt_action, &QAction::triggered, [this]{ gotoLoadPSBT(); });
386+
connect(m_load_psbt_clipboard_action, &QAction::triggered, [this]{ gotoLoadPSBT(true); });
384387
connect(verifyMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
385388
connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); });
386389
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
@@ -459,6 +462,7 @@ void BitcoinGUI::createMenuBar()
459462
file->addAction(signMessageAction);
460463
file->addAction(verifyMessageAction);
461464
file->addAction(m_load_psbt_action);
465+
file->addAction(m_load_psbt_clipboard_action);
462466
file->addSeparator();
463467
}
464468
file->addAction(quitAction);
@@ -878,9 +882,9 @@ void BitcoinGUI::gotoVerifyMessageTab(QString addr)
878882
{
879883
if (walletFrame) walletFrame->gotoVerifyMessageTab(addr);
880884
}
881-
void BitcoinGUI::gotoLoadPSBT()
885+
void BitcoinGUI::gotoLoadPSBT(bool from_clipboard)
882886
{
883-
if (walletFrame) walletFrame->gotoLoadPSBT();
887+
if (walletFrame) walletFrame->gotoLoadPSBT(from_clipboard);
884888
}
885889
#endif // ENABLE_WALLET
886890

src/qt/bitcoingui.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class BitcoinGUI : public QMainWindow
139139
QAction* signMessageAction = nullptr;
140140
QAction* verifyMessageAction = nullptr;
141141
QAction* m_load_psbt_action = nullptr;
142+
QAction* m_load_psbt_clipboard_action = nullptr;
142143
QAction* aboutAction = nullptr;
143144
QAction* receiveCoinsAction = nullptr;
144145
QAction* receiveCoinsMenuAction = nullptr;
@@ -278,8 +279,8 @@ public Q_SLOTS:
278279
void gotoSignMessageTab(QString addr = "");
279280
/** Show Sign/Verify Message dialog and switch to verify message tab */
280281
void gotoVerifyMessageTab(QString addr = "");
281-
/** Show load Partially Signed Bitcoin Transaction dialog */
282-
void gotoLoadPSBT();
282+
/** Load Partially Signed Bitcoin Transaction from file or clipboard */
283+
void gotoLoadPSBT(bool from_clipboard = false);
283284

284285
/** Show open dialog */
285286
void openClicked();

src/qt/forms/psbtoperationsdialog.ui

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>PSBTOperationsDialog</class>
4+
<widget class="QDialog" name="PSBTOperationsDialog">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>585</width>
10+
<height>327</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>Dialog</string>
15+
</property>
16+
<layout class="QVBoxLayout" name="verticalLayout">
17+
<property name="spacing">
18+
<number>12</number>
19+
</property>
20+
<property name="sizeConstraint">
21+
<enum>QLayout::SetDefaultConstraint</enum>
22+
</property>
23+
<property name="bottomMargin">
24+
<number>12</number>
25+
</property>
26+
<item>
27+
<layout class="QVBoxLayout" name="mainDialogLayout">
28+
<property name="spacing">
29+
<number>5</number>
30+
</property>
31+
<property name="topMargin">
32+
<number>0</number>
33+
</property>
34+
<property name="bottomMargin">
35+
<number>0</number>
36+
</property>
37+
<item>
38+
<widget class="QLabel" name="statusBar">
39+
<property name="font">
40+
<font>
41+
<weight>75</weight>
42+
<bold>true</bold>
43+
</font>
44+
</property>
45+
<property name="autoFillBackground">
46+
<bool>false</bool>
47+
</property>
48+
<property name="styleSheet">
49+
<string notr="true"/>
50+
</property>
51+
<property name="text">
52+
<string/>
53+
</property>
54+
</widget>
55+
</item>
56+
<item>
57+
<widget class="QTextEdit" name="transactionDescription">
58+
<property name="undoRedoEnabled">
59+
<bool>false</bool>
60+
</property>
61+
<property name="readOnly">
62+
<bool>true</bool>
63+
</property>
64+
</widget>
65+
</item>
66+
<item>
67+
<layout class="QHBoxLayout" name="buttonRowLayout">
68+
<property name="spacing">
69+
<number>5</number>
70+
</property>
71+
<item>
72+
<widget class="QPushButton" name="signTransactionButton">
73+
<property name="sizePolicy">
74+
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
75+
<horstretch>0</horstretch>
76+
<verstretch>0</verstretch>
77+
</sizepolicy>
78+
</property>
79+
<property name="font">
80+
<font>
81+
<weight>50</weight>
82+
<bold>false</bold>
83+
</font>
84+
</property>
85+
<property name="text">
86+
<string>Sign Tx</string>
87+
</property>
88+
<property name="autoDefault">
89+
<bool>true</bool>
90+
</property>
91+
<property name="default">
92+
<bool>false</bool>
93+
</property>
94+
<property name="flat">
95+
<bool>false</bool>
96+
</property>
97+
</widget>
98+
</item>
99+
<item>
100+
<widget class="QPushButton" name="broadcastTransactionButton">
101+
<property name="text">
102+
<string>Broadcast Tx</string>
103+
</property>
104+
</widget>
105+
</item>
106+
<item>
107+
<spacer name="horizontalSpacer">
108+
<property name="orientation">
109+
<enum>Qt::Horizontal</enum>
110+
</property>
111+
<property name="sizeHint" stdset="0">
112+
<size>
113+
<width>40</width>
114+
<height>20</height>
115+
</size>
116+
</property>
117+
</spacer>
118+
</item>
119+
<item>
120+
<widget class="QPushButton" name="copyToClipboardButton">
121+
<property name="text">
122+
<string>Copy to Clipboard</string>
123+
</property>
124+
</widget>
125+
</item>
126+
<item>
127+
<widget class="QPushButton" name="saveButton">
128+
<property name="text">
129+
<string>Save...</string>
130+
</property>
131+
</widget>
132+
</item>
133+
<item>
134+
<widget class="QPushButton" name="closeButton">
135+
<property name="text">
136+
<string>Close</string>
137+
</property>
138+
</widget>
139+
</item>
140+
</layout>
141+
</item>
142+
</layout>
143+
</item>
144+
</layout>
145+
</widget>
146+
<resources/>
147+
<connections/>
148+
</ui>

0 commit comments

Comments
 (0)