Sapling transaction testing
This commit is contained in:
@@ -213,6 +213,7 @@ public:
|
||||
CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
|
||||
|
||||
bool operator()(const CKeyID& id) const { return addr->Set(id); }
|
||||
bool operator()(const CPubKey& key) const { return addr->Set(key); }
|
||||
bool operator()(const CScriptID& id) const { return addr->Set(id); }
|
||||
bool operator()(const CNoDestination& no) const { return false; }
|
||||
};
|
||||
@@ -225,6 +226,13 @@ bool CBitcoinAddress::Set(const CKeyID& id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::Set(const CPubKey& key)
|
||||
{
|
||||
CKeyID id = key.GetID();
|
||||
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::Set(const CScriptID& id)
|
||||
{
|
||||
SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
|
||||
|
||||
@@ -116,6 +116,7 @@ public:
|
||||
class CBitcoinAddress : public CBase58Data {
|
||||
public:
|
||||
bool Set(const CKeyID &id);
|
||||
bool Set(const CPubKey &key);
|
||||
bool Set(const CScriptID &id);
|
||||
bool Set(const CTxDestination &dest);
|
||||
bool IsValid() const;
|
||||
|
||||
@@ -115,9 +115,9 @@ public:
|
||||
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight =
|
||||
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170005;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 227520;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 1;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 227520;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 1;
|
||||
|
||||
// The best chain should have at least this much work.
|
||||
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000281b32ff3198a1");
|
||||
|
||||
@@ -34,6 +34,14 @@ public:
|
||||
return EncodeBase58Check(data);
|
||||
}
|
||||
|
||||
std::string operator()(const CPubKey& key) const
|
||||
{
|
||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
|
||||
CKeyID id = key.GetID();
|
||||
data.insert(data.end(), id.begin(), id.end());
|
||||
return EncodeBase58Check(data);
|
||||
}
|
||||
|
||||
std::string operator()(const CScriptID& id) const
|
||||
{
|
||||
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
|
||||
@@ -286,10 +294,7 @@ libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
|
||||
}
|
||||
data.clear();
|
||||
auto bech = bech32::Decode(str);
|
||||
bool allowSapling = Params().NetworkIDString() == "regtest" || (
|
||||
Params().NetworkIDString() == "test" &&
|
||||
GetBoolArg("-experimentalfeatures", false) &&
|
||||
GetBoolArg("-developersapling", false));
|
||||
bool allowSapling = true;
|
||||
if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
|
||||
bech.second.size() == ConvertedSaplingPaymentAddressSize) {
|
||||
// Bech32 decoding
|
||||
@@ -356,10 +361,7 @@ libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
|
||||
}
|
||||
data.clear();
|
||||
auto bech = bech32::Decode(str);
|
||||
bool allowSapling = Params().NetworkIDString() == "regtest" || (
|
||||
Params().NetworkIDString() == "test" &&
|
||||
GetBoolArg("-experimentalfeatures", false) &&
|
||||
GetBoolArg("-developersapling", false));
|
||||
bool allowSapling = true;
|
||||
if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
|
||||
bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
|
||||
// Bech32 decoding
|
||||
|
||||
@@ -870,6 +870,8 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
|
||||
txnouttype whichType;
|
||||
// get the scriptPubKey corresponding to this input:
|
||||
const CScript& prevScript = prev.scriptPubKey;
|
||||
//printf("Previous script: %s\n", prevScript.ToString().c_str());
|
||||
|
||||
if (!Solver(prevScript, whichType, vSolutions))
|
||||
return false;
|
||||
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
|
||||
@@ -883,6 +885,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
|
||||
// IsStandardTx() will have already returned false
|
||||
// and this method isn't called.
|
||||
vector<vector<unsigned char> > stack;
|
||||
//printf("Checking script: %s\n", tx.vin[i].scriptSig.ToString().c_str());
|
||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -224,12 +224,26 @@ public:
|
||||
CPubKey vchPubKey;
|
||||
obj.push_back(Pair("isscript", false));
|
||||
if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) {
|
||||
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
|
||||
obj.push_back(Pair("pubkey", HexStr(vchPubKey))); // should return pubkeyhash, but not sure about compatibility impact
|
||||
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
UniValue operator()(const CPubKey &key) const {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("isscript", false));
|
||||
if (pwalletMain && key.IsValid()) {
|
||||
obj.push_back(Pair("pubkey", HexStr(key)));
|
||||
obj.push_back(Pair("iscompressed", key.IsCompressed()));
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.push_back(Pair("pubkey", "invalid"));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
UniValue operator()(const CScriptID &scriptID) const {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
CScript subscript;
|
||||
|
||||
@@ -234,7 +234,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||
return whichType != TX_NONSTANDARD;
|
||||
}
|
||||
|
||||
bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet)
|
||||
bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet, bool returnPubKey)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
@@ -262,9 +262,13 @@ bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet
|
||||
return false;
|
||||
}
|
||||
|
||||
addressRet = pubKey.GetID();
|
||||
if (returnPubKey)
|
||||
addressRet = pubKey;
|
||||
else
|
||||
addressRet = pubKey.GetID();
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (whichType == TX_PUBKEYHASH)
|
||||
{
|
||||
addressRet = CKeyID(uint160(vSolutions[0]));
|
||||
@@ -355,6 +359,12 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(const CPubKey &key) const {
|
||||
script->clear();
|
||||
*script << ToByteVector(key) << OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(const CKeyID &keyID) const {
|
||||
script->clear();
|
||||
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
* * CScriptID: TX_SCRIPTHASH destination
|
||||
* A CTxDestination is the internal data type encoded in a bitcoin address
|
||||
*/
|
||||
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
|
||||
typedef boost::variant<CNoDestination, CPubKey, CKeyID, CScriptID> CTxDestination;
|
||||
|
||||
/** Check whether a CTxDestination is a CNoDestination. */
|
||||
bool IsValidDestination(const CTxDestination& dest);
|
||||
@@ -91,7 +91,7 @@ const char* GetTxnOutputType(txnouttype t);
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet, bool returnPubKey=false);
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||
|
||||
CScript GetScriptForDestination(const CTxDestination& dest);
|
||||
|
||||
@@ -342,8 +342,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
|
||||
// update the transaction with these inputs
|
||||
if (isUsingBuilder_) {
|
||||
CScript scriptPubKey = GetScriptForDestination(fromtaddr_);
|
||||
CScript scriptPubKey;
|
||||
for (auto t : t_inputs_) {
|
||||
scriptPubKey = GetScriptForDestination(std::get<4>(t));
|
||||
//printf("Checking new script: %s\n", scriptPubKey.ToString().c_str());
|
||||
uint256 txid = std::get<0>(t);
|
||||
int vout = std::get<1>(t);
|
||||
CAmount amount = std::get<2>(t);
|
||||
@@ -993,17 +995,20 @@ void AsyncRPCOperation_sendmany::sign_send_raw_transaction(UniValue obj)
|
||||
tx_ = tx;
|
||||
}
|
||||
|
||||
|
||||
bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
|
||||
std::set<CTxDestination> destinations;
|
||||
destinations.insert(fromtaddr_);
|
||||
|
||||
//printf("Looking for %s\n", boost::apply_visitor(AddressVisitorString(), fromtaddr_).c_str());
|
||||
|
||||
vector<COutput> vecOutputs;
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true, fAcceptCoinbase);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs) {
|
||||
CTxDestination dest;
|
||||
|
||||
if (!out.fSpendable) {
|
||||
continue;
|
||||
}
|
||||
@@ -1012,13 +1017,15 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const CScript &scriptPubKey = out.tx->vout[out.i].scriptPubKey;
|
||||
|
||||
if (destinations.size()) {
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
|
||||
if (!ExtractDestination(scriptPubKey, dest)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!destinations.count(address)) {
|
||||
//printf("%s\n", boost::apply_visitor(AddressVisitorString(), dest).c_str());
|
||||
if (!destinations.count(dest)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1029,8 +1036,12 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ExtractDestination(scriptPubKey, dest, true))
|
||||
continue;
|
||||
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, isCoinbase);
|
||||
|
||||
SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, isCoinbase, dest);
|
||||
t_inputs_.push_back(utxo);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ using namespace libzcash;
|
||||
typedef std::tuple<std::string, CAmount, std::string> SendManyRecipient;
|
||||
|
||||
// Input UTXO is a tuple (quadruple) of txid, vout, amount, coinbase)
|
||||
typedef std::tuple<uint256, int, CAmount, bool> SendManyInputUTXO;
|
||||
typedef std::tuple<uint256, int, CAmount, bool, CTxDestination> SendManyInputUTXO;
|
||||
|
||||
// Input JSOP is a tuple of JSOutpoint, note and amount
|
||||
typedef std::tuple<JSOutPoint, SproutNote, CAmount> SendManyInputJSOP;
|
||||
|
||||
@@ -77,7 +77,7 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
|
||||
auto address = DecodePaymentAddress(toAddress);
|
||||
if (IsValidPaymentAddress(address)) {
|
||||
// TODO: Add Sapling support. For now, ensure we can freely convert.
|
||||
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
|
||||
// assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
|
||||
tozaddr_ = address;
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address");
|
||||
|
||||
@@ -3451,7 +3451,9 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp)
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
std::string defaultType = ADDR_TYPE_SPROUT;
|
||||
bool allowSapling = (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= chainActive.LastTip()->nHeight);
|
||||
|
||||
std::string defaultType = allowSapling ? ADDR_TYPE_SAPLING : ADDR_TYPE_SPROUT;
|
||||
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
@@ -3478,10 +3480,6 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp)
|
||||
addrType = params[0].get_str();
|
||||
}
|
||||
|
||||
bool allowSapling = Params().NetworkIDString() == "regtest" || (
|
||||
Params().NetworkIDString() == "test" &&
|
||||
GetBoolArg("-experimentalfeatures", false) &&
|
||||
GetBoolArg("-developersapling", false));
|
||||
if (addrType == ADDR_TYPE_SPROUT) {
|
||||
return EncodePaymentAddress(pwalletMain->GenerateNewZKey());
|
||||
} else if (addrType == ADDR_TYPE_SAPLING && allowSapling) {
|
||||
|
||||
@@ -4406,6 +4406,12 @@ public:
|
||||
vKeys.push_back(keyId);
|
||||
}
|
||||
|
||||
void operator()(const CPubKey &key) {
|
||||
CKeyID keyId = key.GetID();
|
||||
if (keystore.HaveKey(keyId))
|
||||
vKeys.push_back(keyId);
|
||||
}
|
||||
|
||||
void operator()(const CScriptID &scriptId) {
|
||||
CScript script;
|
||||
if (keystore.GetCScript(scriptId, script))
|
||||
|
||||
@@ -1387,4 +1387,46 @@ public:
|
||||
boost::optional<libzcash::SpendingKey> operator()(const libzcash::InvalidEncoding& no) const;
|
||||
};
|
||||
|
||||
class GetPubKeyForPubKey : public boost::static_visitor<CPubKey> {
|
||||
private:
|
||||
const CKeyStore &keystore;
|
||||
|
||||
public:
|
||||
GetPubKeyForPubKey(const CKeyStore &keystoreIn) : keystore(keystoreIn) {}
|
||||
|
||||
CPubKey operator()(const CKeyID &id) const {
|
||||
return CPubKey();
|
||||
}
|
||||
|
||||
CPubKey operator()(const CPubKey &key) const {
|
||||
return key;
|
||||
}
|
||||
|
||||
CPubKey operator()(const CScriptID &sid) const {
|
||||
return CPubKey();
|
||||
}
|
||||
|
||||
CPubKey operator()(const CNoDestination &no) const {
|
||||
return CPubKey();
|
||||
}
|
||||
};
|
||||
|
||||
class AddressVisitorString : public boost::static_visitor<std::string>
|
||||
{
|
||||
public:
|
||||
std::string operator()(const CNoDestination &dest) const { return ""; }
|
||||
|
||||
std::string operator()(const CKeyID &keyID) const {
|
||||
return "key hash: " + keyID.ToString();
|
||||
}
|
||||
|
||||
std::string operator()(const CPubKey &key) const {
|
||||
return "public key: " + HexStr(key);
|
||||
}
|
||||
|
||||
std::string operator()(const CScriptID &scriptID) const {
|
||||
return "script hash: " + scriptID.ToString();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_WALLET_WALLET_H
|
||||
|
||||
Reference in New Issue
Block a user