Skip to content

Commit

Permalink
[Refactoring] Initialize txbuilder inside sapling_operation
Browse files Browse the repository at this point in the history
Save a wallet reference when initializing sapling_operation, and pass it
to the txbuilder (so we are sure that the keystore used to sign the keys
belongs to the wallet used to retrieve the inputs).
  • Loading branch information
random-zebra committed Apr 3, 2021
1 parent 74a1592 commit 80054f7
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 20 deletions.
3 changes: 1 addition & 2 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,7 @@ OperationResult WalletModel::PrepareShieldedTransaction(WalletModelTransaction*
if (!opResult) return opResult;

// Create the operation
TransactionBuilder txBuilder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, wallet);
SaplingOperation operation(txBuilder);
SaplingOperation operation(Params().GetConsensus(), nextBlockHeight, wallet);
auto operationResult = operation.setRecipients(recipients)
->setTransparentKeyChange(modelTransaction->getPossibleKeyChange())
->setSelectTransparentCoins(fromTransparent)
Expand Down
12 changes: 12 additions & 0 deletions src/sapling/sapling_operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ struct TxValues
CAmount target{0};
};

SaplingOperation::SaplingOperation(const Consensus::Params& consensusParams, int nHeight, CWallet* _wallet) :
wallet(_wallet),
txBuilder(consensusParams, nHeight, _wallet)
{
assert (wallet != nullptr);
};

SaplingOperation::~SaplingOperation()
{
delete tkeyChange;
}

OperationResult SaplingOperation::checkTxValues(TxValues& txValues, bool isFromtAddress, bool isFromShielded)
{
assert(!isFromtAddress || txValues.shieldedInTotal == 0);
Expand Down
13 changes: 9 additions & 4 deletions src/sapling/sapling_operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,8 @@ class FromAddress {

class SaplingOperation {
public:
explicit SaplingOperation(const Consensus::Params& consensusParams, int chainHeight) : txBuilder(consensusParams, chainHeight) {};
explicit SaplingOperation(TransactionBuilder& _builder) : txBuilder(_builder) {};

~SaplingOperation() { delete tkeyChange; }
explicit SaplingOperation(const Consensus::Params& consensusParams, int nHeight, CWallet* _wallet);
~SaplingOperation();

OperationResult build();
OperationResult send(std::string& retTxHash);
Expand All @@ -107,6 +105,13 @@ class SaplingOperation {
CTransactionRef getFinalTxRef() { return finalTx; }

private:
/*
* Cannot be nullptr. A pointer to the wallet, used to retrieve the inputs to spend, the keys to create the outputs,
* sapling notes and nullifiers, as well as to commit transactions.
* The same keystore is passed to the transaction builder in order to produce the required signatures.
*/
CWallet* wallet;

FromAddress fromAddress;
// In case of no addressFrom filter selected, it will accept any utxo in the wallet as input.
bool selectFromtaddrs{false};
Expand Down
13 changes: 5 additions & 8 deletions src/test/librust/sapling_rpc_wallet_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ BOOST_AUTO_TEST_CASE(saplingOperationTests) {
// there are no utxos to spend
{
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, COIN, "DEADBEEF") };
SaplingOperation operation(consensusParams, 1);
SaplingOperation operation(consensusParams, 1, pwalletMain);
operation.setFromAddress(taddr1);
auto res = operation.setRecipients(recipients)->buildAndSend(ret);
BOOST_CHECK(!res);
Expand All @@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(saplingOperationTests) {
// minconf cannot be zero when sending from zaddr
{
std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, COIN, "DEADBEEF") };
SaplingOperation operation(consensusParams, 1);
SaplingOperation operation(consensusParams, 1, pwalletMain);
operation.setFromAddress(zaddr1);
auto res = operation.setRecipients(recipients)->setMinDepth(0)->buildAndSend(ret);
BOOST_CHECK(!res);
Expand All @@ -353,7 +353,7 @@ BOOST_AUTO_TEST_CASE(saplingOperationTests) {
// there are no unspent notes to spend
{
std::vector<SendManyRecipient> recipients = { SendManyRecipient(taddr1, COIN) };
SaplingOperation operation(consensusParams, 1);
SaplingOperation operation(consensusParams, 1, pwalletMain);
operation.setFromAddress(zaddr1);
auto res = operation.setRecipients(recipients)->buildAndSend(ret);
BOOST_CHECK(!res);
Expand Down Expand Up @@ -438,19 +438,16 @@ BOOST_AUTO_TEST_CASE(rpc_shieldsendmany_taddr_to_sapling)
pwalletMain->BlockConnected(std::make_shared<CBlock>(block), mi->second, vtxConflicted);
BOOST_CHECK_MESSAGE(pwalletMain->GetAvailableBalance() > 0, "tx not confirmed");

// Context that shieldsendmany requires
auto builder = TransactionBuilder(consensusParams, nextBlockHeight, pwalletMain);

std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 1 * COIN, "ABCD") };
SaplingOperation operation(builder);
SaplingOperation operation(consensusParams, nextBlockHeight, pwalletMain);
operation.setFromAddress(taddr);
BOOST_CHECK(operation.setRecipients(recipients)
->setMinDepth(0)
->build());

// try from auto-selected transparent address
std::vector<SendManyRecipient> recipients2 = { SendManyRecipient(zaddr1, 1 * COIN, "ABCD") };
SaplingOperation operation2(builder);
SaplingOperation operation2(consensusParams, nextBlockHeight, pwalletMain);
BOOST_CHECK(operation2.setSelectTransparentCoins(true)
->setRecipients(recipients2)
->setMinDepth(0)
Expand Down
6 changes: 2 additions & 4 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,8 +1168,7 @@ UniValue CreateColdStakeDelegation(const UniValue& params, CTransactionRef& txNe
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling not active yet");
}
std::vector<SendManyRecipient> recipients = {SendManyRecipient(ownerKey, *stakeKey, nValue)};
TransactionBuilder txBuilder = TransactionBuilder(consensus, nextBlockHeight, pwalletMain);
SaplingOperation operation(txBuilder);
SaplingOperation operation(consensus, nextBlockHeight, pwalletMain);
OperationResult res = operation.setSelectShieldedCoins(true)
->setRecipients(recipients)
->build();
Expand Down Expand Up @@ -1520,8 +1519,7 @@ static SaplingOperation CreateShieldedTransaction(const JSONRPCRequest& request)
EnsureWalletIsUnlocked();
LOCK2(cs_main, pwalletMain->cs_wallet);
int nextBlockHeight = chainActive.Height() + 1;
TransactionBuilder txBuilder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
SaplingOperation operation(txBuilder);
SaplingOperation operation(Params().GetConsensus(), nextBlockHeight, pwalletMain);

// Param 0: source of funds. Can either be a valid address, sapling address,
// or the string "from_transparent"|"from_trans_cold"|"from_shield"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ SaplingOperation createOperationAndBuildTx(std::vector<SendManyRecipient> recipi
bool selectTransparentCoins)
{
// Create the operation
TransactionBuilder txBuilder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
SaplingOperation operation(txBuilder);
SaplingOperation operation(Params().GetConsensus(), nextBlockHeight, pwalletMain);
auto operationResult = operation.setRecipients(recipients)
->setSelectTransparentCoins(selectTransparentCoins)
->setSelectShieldedCoins(!selectTransparentCoins)
Expand Down

0 comments on commit 80054f7

Please sign in to comment.