Browse Source

Sapling transaction testing

metaverse
miketout 6 years ago
parent
commit
b8deecdc09
  1. 8
      src/base58.cpp
  2. 1
      src/base58.h
  3. 4
      src/chainparams.cpp
  4. 18
      src/key_io.cpp
  5. 3
      src/main.cpp
  6. 16
      src/rpc/misc.cpp
  7. 14
      src/script/standard.cpp
  8. 4
      src/script/standard.h
  9. 25
      src/wallet/asyncrpcoperation_sendmany.cpp
  10. 2
      src/wallet/asyncrpcoperation_sendmany.h
  11. 2
      src/wallet/asyncrpcoperation_shieldcoinbase.cpp
  12. 8
      src/wallet/rpcwallet.cpp
  13. 6
      src/wallet/wallet.cpp
  14. 42
      src/wallet/wallet.h

8
src/base58.cpp

@ -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);

1
src/base58.h

@ -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;

4
src/chainparams.cpp

@ -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");

18
src/key_io.cpp

@ -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

3
src/main.cpp

@ -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;

16
src/rpc/misc.cpp

@ -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;

14
src/script/standard.cpp

@ -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;

4
src/script/standard.h

@ -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);

25
src/wallet/asyncrpcoperation_sendmany.cpp

@ -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);
}

2
src/wallet/asyncrpcoperation_sendmany.h

@ -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;

2
src/wallet/asyncrpcoperation_shieldcoinbase.cpp

@ -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");

8
src/wallet/rpcwallet.cpp

@ -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) {

6
src/wallet/wallet.cpp

@ -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))

42
src/wallet/wallet.h

@ -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

Loading…
Cancel
Save