Implement read and write for (txid, recipient) -> ua mapping.
Co-authored-by: Kris Nuttycombe <kris@nutty.land> Co-authored-by: Jack Grigg <jack@z.cash>
This commit is contained in:
parent
c7346e802e
commit
94ab8e4c77
|
@ -13,6 +13,11 @@ UniValue SendTransaction(const CTransaction& tx, const std::vector<SendManyRecip
|
||||||
// Send the transaction
|
// Send the transaction
|
||||||
if (!testmode) {
|
if (!testmode) {
|
||||||
CWalletTx wtx(pwalletMain, tx);
|
CWalletTx wtx(pwalletMain, tx);
|
||||||
|
// save the mapping from (receiver, txid) to UA
|
||||||
|
if (!pwalletMain->SaveRecipientMappings(tx.GetHash(), recipients)) {
|
||||||
|
// More details in debug.log
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "SendTransaction: SaveRecipientMappings failed");
|
||||||
|
}
|
||||||
if (!pwalletMain->CommitTransaction(wtx, reservekey)) {
|
if (!pwalletMain->CommitTransaction(wtx, reservekey)) {
|
||||||
// More details in debug.log
|
// More details in debug.log
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "SendTransaction: CommitTransaction failed");
|
throw JSONRPCError(RPC_WALLET_ERROR, "SendTransaction: CommitTransaction failed");
|
||||||
|
|
|
@ -4845,6 +4845,31 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool CWallet::SaveRecipientMappings(const uint256& txid, const std::vector<SendManyRecipient>& recipients)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, cs_wallet);
|
||||||
|
LogPrintf("SaveRecipientMappings:\n%s", txid.ToString());
|
||||||
|
|
||||||
|
for (const SendManyRecipient& recipient : recipients)
|
||||||
|
{
|
||||||
|
if (recipient.ua.has_value()) {
|
||||||
|
CWalletDB(strWalletFile).WriteRecipientMapping(
|
||||||
|
txid,
|
||||||
|
recipient.address,
|
||||||
|
recipient.ua.value()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call after CreateTransaction unless you want to abort
|
* Call after CreateTransaction unless you want to abort
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1528,6 +1528,7 @@ public:
|
||||||
*/
|
*/
|
||||||
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
|
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
|
||||||
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
|
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
|
||||||
|
bool SaveRecipientMappings(const uint256& txid, const std::vector<SendManyRecipient>& recipients);
|
||||||
bool CommitTransaction(CWalletTx& wtxNew, std::optional<std::reference_wrapper<CReserveKey>> reservekey);
|
bool CommitTransaction(CWalletTx& wtxNew, std::optional<std::reference_wrapper<CReserveKey>> reservekey);
|
||||||
|
|
||||||
static CFeeRate minTxFee;
|
static CFeeRate minTxFee;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "proof_verifier.h"
|
#include "proof_verifier.h"
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
|
#include "script/standard.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utiltime.h"
|
#include "utiltime.h"
|
||||||
|
@ -313,6 +314,13 @@ bool CWalletDB::WriteMinVersion(int nVersion)
|
||||||
return Write(std::string("minversion"), nVersion);
|
return Write(std::string("minversion"), nVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWalletDB::WriteRecipientMapping(const uint256& txid, const libzcash::RecipientAddress& address, const libzcash::UnifiedAddress& ua)
|
||||||
|
{
|
||||||
|
std::pair<uint256, CSerializeRecipientAddress> key = std::make_pair(txid, CSerializeRecipientAddress(address));
|
||||||
|
std::string uaString = KeyIO(Params()).EncodePaymentAddress(ua);
|
||||||
|
return Write(std::make_pair(std::string("recipientmapping"), key), uaString);
|
||||||
|
}
|
||||||
|
|
||||||
class CWalletScanState {
|
class CWalletScanState {
|
||||||
public:
|
public:
|
||||||
unsigned int nKeys;
|
unsigned int nKeys;
|
||||||
|
@ -847,6 +855,45 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strType == "recipientmapping")
|
||||||
|
{
|
||||||
|
uint256 txid;
|
||||||
|
CSerializeRecipientAddress recipient;
|
||||||
|
std::string rawUa;
|
||||||
|
ssKey >> txid;
|
||||||
|
ssKey >> recipient;
|
||||||
|
ssValue >> rawUa;
|
||||||
|
|
||||||
|
auto pa = keyIO.DecodePaymentAddress(rawUa);
|
||||||
|
if (!pa.has_value()) {
|
||||||
|
strErr = "Error in wallet database: non-UnifiedAddress in recipientmapping";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto uaPtr = std::get_if<libzcash::UnifiedAddress>(&pa.value());
|
||||||
|
if (uaPtr == nullptr) {
|
||||||
|
strErr = "Error in wallet database: failed to deserialize unified address";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
libzcash::Receiver recipientReceiver;
|
||||||
|
std::visit(match {
|
||||||
|
[&](const CKeyID& key) { recipientReceiver = key; },
|
||||||
|
[&](const CScriptID& scriptId) { recipientReceiver = scriptId; },
|
||||||
|
[&](const libzcash::SaplingPaymentAddress& addr) { recipientReceiver = addr; }
|
||||||
|
}, recipient.recipient);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (const auto& receiver : uaPtr->GetReceiversAsParsed()) {
|
||||||
|
if (receiver == recipientReceiver) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
strErr = "Error in wallet database: recipientmapping UA does not contain recipient";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (...)
|
} catch (...)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -314,6 +314,61 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Serialization wrapper for reading and writing RecipientAddress
|
||||||
|
// in CompactSize format.
|
||||||
|
class CSerializeRecipientAddress {
|
||||||
|
libzcash::ReceiverType typecode;
|
||||||
|
|
||||||
|
public:
|
||||||
|
libzcash::RecipientAddress recipient;
|
||||||
|
CSerializeRecipientAddress() {} // for serialization only
|
||||||
|
CSerializeRecipientAddress(libzcash::RecipientAddress recipient): recipient(recipient) {}
|
||||||
|
|
||||||
|
template<typename Stream>
|
||||||
|
void Serialize(Stream& s) const {
|
||||||
|
std::visit(match {
|
||||||
|
[&](const CKeyID& keyId) {
|
||||||
|
ReceiverTypeSer(libzcash::ReceiverType::P2PKH).Serialize(s);
|
||||||
|
s << keyId;
|
||||||
|
},
|
||||||
|
[&](const CScriptID& scriptId) {
|
||||||
|
ReceiverTypeSer(libzcash::ReceiverType::P2SH).Serialize(s);
|
||||||
|
s << scriptId;
|
||||||
|
},
|
||||||
|
[&](const libzcash::SaplingPaymentAddress& saplingAddr) {
|
||||||
|
ReceiverTypeSer(libzcash::ReceiverType::Sapling).Serialize(s);
|
||||||
|
s << saplingAddr;
|
||||||
|
}
|
||||||
|
}, recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Stream>
|
||||||
|
void Unserialize(Stream& s) {
|
||||||
|
// This cast is fine because ZIP 316 uses CompactSize serialization including the
|
||||||
|
// size limit, which means it is at most a uint32_t.
|
||||||
|
typecode = (libzcash::ReceiverType) ReadCompactSize(s);
|
||||||
|
switch (typecode) {
|
||||||
|
case libzcash::ReceiverType::P2PKH: {
|
||||||
|
CKeyID key;
|
||||||
|
s >> key;
|
||||||
|
recipient = key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case libzcash::ReceiverType::P2SH: {
|
||||||
|
CScriptID script;
|
||||||
|
s >> script;
|
||||||
|
recipient = script;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case libzcash::ReceiverType::Sapling: {
|
||||||
|
libzcash::SaplingPaymentAddress saplingAddr;
|
||||||
|
s >> saplingAddr;
|
||||||
|
recipient = saplingAddr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Access to the wallet database */
|
/** Access to the wallet database */
|
||||||
class CWalletDB : public CDB
|
class CWalletDB : public CDB
|
||||||
|
@ -356,6 +411,8 @@ public:
|
||||||
|
|
||||||
bool WriteMinVersion(int nVersion);
|
bool WriteMinVersion(int nVersion);
|
||||||
|
|
||||||
|
bool WriteRecipientMapping(const uint256& txid, const libzcash::RecipientAddress& address, const libzcash::UnifiedAddress& ua);
|
||||||
|
|
||||||
/// Write destination data key,value tuple to database
|
/// Write destination data key,value tuple to database
|
||||||
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
|
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
|
||||||
/// Erase destination data tuple from wallet database
|
/// Erase destination data tuple from wallet database
|
||||||
|
|
|
@ -66,6 +66,13 @@ class UnifiedAddress {
|
||||||
public:
|
public:
|
||||||
UnifiedAddress() {}
|
UnifiedAddress() {}
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||||
|
READWRITE(receivers);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given receiver to this unified address.
|
* Adds the given receiver to this unified address.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue