Browse Source

Merge pull request #132 from MyHush/dpow

dPoW to KMD
pull/137/head
Duke Leto 6 years ago
committed by GitHub
parent
commit
c3a449e8c2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      qa/rpc-tests/dpow.py
  2. 13
      src/chain.h
  3. 13
      src/init.cpp
  4. 227
      src/key_io.cpp
  5. 29
      src/key_io.h
  6. 103
      src/komodo_rpcblockchain.h
  7. 1238
      src/komodo_validation011.h
  8. 30
      src/main.cpp
  9. 1
      src/main.h
  10. 5
      src/primitives/transaction.h
  11. 1
      src/rpcclient.cpp
  12. 91
      src/rpcmisc.cpp
  13. 6
      src/rpcserver.cpp
  14. 9
      src/script/standard.cpp
  15. 3
      src/script/standard.h
  16. 38
      src/wallet/rpcdump.cpp
  17. 61
      src/wallet/wallet.cpp
  18. 83
      src/wallet/wallet.h

31
qa/rpc-tests/dpow.py

@ -0,0 +1,31 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Hush developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
start_node, stop_node, wait_bitcoinds
class DPoWTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def setup_network(self):
self.nodes = []
self.is_network_split = False
self.nodes.append(start_node(0, self.options.tmpdir))
def run_test(self):
self.nodes[0].generate(3)
rpc = self.nodes[0]
# Verify that basic RPC functions exist and work
result = rpc.calc_MoM(2,20)
print result
if __name__ == '__main__':
DPoWTest().main()

13
src/chain.h

@ -17,6 +17,8 @@
#include <boost/foreach.hpp>
static const int SPROUT_VALUE_VERSION = 1001400;
static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
struct CDiskBlockPos
{
@ -167,6 +169,9 @@ public:
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
uint32_t nSequenceId;
//! (memory only) Maximum nTime in the chain up to and including this block.
unsigned int nTimeMax;
void SetNull()
{
phashBlock = NULL;
@ -256,6 +261,11 @@ public:
return (int64_t)nTime;
}
int64_t GetBlockTimeMax() const
{
return (int64_t)nTimeMax;
}
enum { nMedianTimeSpan=11 };
int64_t GetMedianTimePast() const
@ -441,6 +451,9 @@ public:
/** Find the last common block between this chain and a block index entry. */
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
/** Find the earliest block with timestamp equal or greater than the given. */
CBlockIndex* FindEarliestAtLeast(int64_t nTime) const;
};
#endif // BITCOIN_CHAIN_H

13
src/init.cpp

@ -701,7 +701,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
/** Sanity checks
* Ensure that Bitcoin is running in a usable environment with all
* Ensure that Hush is running in a usable environment with all
* necessary library support.
*/
bool InitSanityCheck(void)
@ -764,7 +764,9 @@ bool AppInitServers(boost::thread_group& threadGroup)
return true;
}
/** Initialize bitcoin.
int32_t komodo_init();
/** Initialize Hush
* @pre Parameters should be parsed and config file should be read.
*/
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
@ -915,6 +917,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
komodo_init();
// if using block pruning, then disable txindex
// also disable the wallet (for now, until SPV support is implemented in wallet)
if (GetArg("-prune", 0)) {
@ -1108,7 +1112,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile))
return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir));
#endif
// Make sure only a single Bitcoin process is using the data directory.
// Make sure only a single Hush process is using the data directory.
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
@ -1579,6 +1583,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
strErrors << _("Error loading wallet.dat") << "\n";
}
// Wallet has been successfully loaded
vpwallets.push_back(pwalletMain);
if (GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = GetArg("-upgradewallet", 0);

227
src/key_io.cpp

@ -0,0 +1,227 @@
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h>
#include <base58.h>
#include <bech32.h>
#include <script/script.h>
#include <utilstrencodings.h>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <assert.h>
#include <string.h>
#include <algorithm>
namespace
{
class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
DestinationEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const CKeyID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
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);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}
std::string operator()(const WitnessV0KeyHash& id) const
{
std::vector<unsigned char> data = {0};
data.reserve(33);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
return bech32::Encode(m_params.Bech32HRP(), data);
}
std::string operator()(const WitnessV0ScriptHash& id) const
{
std::vector<unsigned char> data = {0};
data.reserve(53);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
return bech32::Encode(m_params.Bech32HRP(), data);
}
std::string operator()(const WitnessUnknown& id) const
{
if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) {
return {};
}
std::vector<unsigned char> data = {(unsigned char)id.version};
data.reserve(1 + (id.length * 8 + 4) / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.program, id.program + id.length);
return bech32::Encode(m_params.Bech32HRP(), data);
}
std::string operator()(const CNoDestination& no) const { return {}; }
};
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
{
std::vector<unsigned char> data;
uint160 hash;
if (DecodeBase58Check(str, data)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
return CKeyID(hash);
}
// Script-hash-addresses have version 5 (or 196 testnet).
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
return CScriptID(hash);
}
}
data.clear();
auto bech = bech32::Decode(str);
if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
// Bech32 decoding
int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
// The rest of the symbols are converted witness program bytes.
data.reserve(((bech.second.size() - 1) * 5) / 8);
if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin() + 1, bech.second.end())) {
if (version == 0) {
{
WitnessV0KeyHash keyid;
if (data.size() == keyid.size()) {
std::copy(data.begin(), data.end(), keyid.begin());
return keyid;
}
}
{
WitnessV0ScriptHash scriptid;
if (data.size() == scriptid.size()) {
std::copy(data.begin(), data.end(), scriptid.begin());
return scriptid;
}
}
return CNoDestination();
}
if (version > 16 || data.size() < 2 || data.size() > 40) {
return CNoDestination();
}
WitnessUnknown unk;
unk.version = version;
std::copy(data.begin(), data.end(), unk.program);
unk.length = data.size();
return unk;
}
}
return CNoDestination();
}
} // namespace
CKey DecodeSecret(const std::string& str)
{
CKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
bool compressed = data.size() == 33 + privkey_prefix.size();
key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
}
}
memory_cleanse(data.data(), data.size());
return key;
}
std::string EncodeSecret(const CKey& key)
{
assert(key.IsValid());
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
data.insert(data.end(), key.begin(), key.end());
if (key.IsCompressed()) {
data.push_back(1);
}
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
CExtPubKey DecodeExtPubKey(const std::string& str)
{
CExtPubKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}
std::string EncodeExtPubKey(const CExtPubKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
return ret;
}
CExtKey DecodeExtKey(const std::string& str)
{
CExtKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}
std::string EncodeExtKey(const CExtKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
std::string EncodeDestination(const CTxDestination& dest)
{
return boost::apply_visitor(DestinationEncoder(Params()), dest);
}
CTxDestination DecodeDestination(const std::string& str)
{
return DecodeDestination(str, Params());
}
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
return IsValidDestination(DecodeDestination(str, params));
}
bool IsValidDestinationString(const std::string& str)
{
return IsValidDestinationString(str, Params());
}

29
src/key_io.h

@ -0,0 +1,29 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYIO_H
#define BITCOIN_KEYIO_H
#include <chainparams.h>
#include <key.h>
#include <pubkey.h>
#include <script/standard.h>
#include <string>
CKey DecodeSecret(const std::string& str);
std::string EncodeSecret(const CKey& key);
CExtKey DecodeExtKey(const std::string& str);
std::string EncodeExtKey(const CExtKey& extkey);
CExtPubKey DecodeExtPubKey(const std::string& str);
std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
#endif // BITCOIN_KEYIO_H

103
src/komodo_rpcblockchain.h

@ -0,0 +1,103 @@
/******************************************************************************
* Copyright © 2014-2018 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#ifndef komodo_rpcblockchain_h
#define komodo_rpcblockchain_h
#include "main.h"
int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip);
uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
extern char ASSETCHAINS_SYMBOL[65];
int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip)
{
int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
depth = komodo_MoMdata(&notarized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip);
memset(MoMp,0,sizeof(*MoMp));
memset(kmdtxidp,0,sizeof(*kmdtxidp));
*notarized_heightp = 0;
if ( depth > 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
{
*MoMp = MoM;
*notarized_heightp = notarized_ht;
*kmdtxidp = kmdtxid;
}
return(depth);
}
UniValue calc_MoM(const UniValue& params, bool fHelp)
{
int32_t height,MoMdepth; uint256 MoM; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 2 )
throw runtime_error("calc_MoM height MoMdepth\n");
LOCK(cs_main);
height = atoi(params[0].get_str().c_str());
MoMdepth = atoi(params[1].get_str().c_str());
if ( height <= 0 )
throw runtime_error("calc_MoM illegal height, must be positive\n");
if ( MoMdepth <= 0 || MoMdepth >= height )
throw runtime_error("calc_MoM illegal MoMdepth, must be positive and less than height\n");
//fprintf(stderr,"height_MoM height.%d\n",height);
MoM = komodo_calcMoM(height,MoMdepth);
ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
ret.push_back(Pair("height",height));
ret.push_back(Pair("MoMdepth",MoMdepth));
ret.push_back(Pair("MoM",MoM.GetHex()));
return ret;
}
UniValue height_MoM(const UniValue& params, bool fHelp)
{
int32_t height,depth,notarized_height,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; uint256 MoM,MoMoM,kmdtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 1 )
throw runtime_error("height_MoM height\n");
LOCK(cs_main);
height = atoi(params[0].get_str().c_str());
if ( height <= 0 )
{
if ( chainActive.Tip() == 0 )
{
ret.push_back(Pair("error",(char *)"no active chain yet"));
return(ret);
}
height = chainActive.Tip()->nHeight;
}
//fprintf(stderr,"height_MoM height.%d\n",height);
depth = komodo_MoM(&notarized_height,&MoM,&kmdtxid,height,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
ret.push_back(Pair("height",height));
ret.push_back(Pair("timestamp",(uint64_t)timestamp));
if ( depth > 0 )
{
ret.push_back(Pair("depth",depth));
ret.push_back(Pair("notarized_height",notarized_height));
ret.push_back(Pair("MoM",MoM.GetHex()));
ret.push_back(Pair("kmdtxid",kmdtxid.GetHex()));
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
ret.push_back(Pair("MoMoM",MoMoM.GetHex()));
ret.push_back(Pair("MoMoMoffset",MoMoMoffset));
ret.push_back(Pair("MoMoMdepth",MoMoMdepth));
ret.push_back(Pair("kmdstarti",kmdstarti));
ret.push_back(Pair("kmdendi",kmdendi));
}
} else ret.push_back(Pair("error",(char *)"no MoM for height"));
return ret;
}
#endif /* komodo_rpcblockchain_h */

1238
src/komodo_validation011.h

File diff suppressed because it is too large

30
src/main.cpp

@ -4,7 +4,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
#include "sodium.h"
@ -29,6 +28,7 @@
#include "util.h"
#include "utilmoneystr.h"
#include "validationinterface.h"
#include "wallet/wallet.h"
#include "wallet/asyncrpcoperation_sendmany.h"
#include "wallet/asyncrpcoperation_shieldcoinbase.h"
@ -212,6 +212,9 @@ namespace {
set<int> setDirtyFileInfo;
} // anon namespace
char ASSETCHAINS_SYMBOL[65] = { "HUSH" };
#include "komodo_validation011.h"
//////////////////////////////////////////////////////////////////////////////
//
// Registration of network node signals.
@ -1358,7 +1361,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
if (txOut.GetHash() != hash)
return error("%s: txid mismatch", __func__);
return true;
}
}
}
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
@ -1953,6 +1956,8 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock(): block and undo data inconsistent");
komodo_disconnect((CBlockIndex *)pindex,(CBlock *)&block);
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex;
@ -2494,6 +2499,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001);
komodo_connectblock(pindex,*(CBlock *)&block);
return true;
}
@ -2666,6 +2672,15 @@ bool static DisconnectTip(CValidationState &state) {
CBlock block;
if (!ReadBlockFromDisk(block, pindexDelete))
return AbortNode(state, "Failed to read block");
int32_t prevMoMheight; uint256 notarizedhash,txid;
komodo_notarized_height(&prevMoMheight,&notarizedhash,&txid);
if ( block.GetHash() == notarizedhash )
{
fprintf(stderr,"DisconnectTip trying to disconnect notarized block at ht.%d\n",(int32_t)pindexDelete->nHeight);
return(false);
}
// Apply the block atomically to the chain state.
uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor();
int64_t nStart = GetTimeMicros();
@ -3327,6 +3342,8 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
const CChainParams& chainParams = Params();
const Consensus::Params& consensusParams = chainParams.GetConsensus();
uint256 hash = block.GetHash();
int32_t notarized_height;
if (hash == consensusParams.hashGenesisBlock)
return true;
@ -3350,6 +3367,15 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
else if ( komodo_checkpoint(&notarized_height,(int32_t)nHeight,hash) < 0 )
{
CBlockIndex *heightblock = chainActive[nHeight];
if ( heightblock != 0 && heightblock->GetBlockHash() == hash )
{
//fprintf(stderr,"got a pre notarization block that matches height.%d\n",(int32_t)nHeight);
return true;
} else return state.DoS(100, error("%s: forked chain %d older than last notarized (height %d) vs %d", __func__,nHeight, notarized_height));
}
}
// Reject block.nVersion < 4 blocks

1
src/main.h

@ -95,6 +95,7 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
static const bool DEFAULT_TXINDEX = false;
static const bool DEFAULT_ADDRESSINDEX = false;
static const bool DEFAULT_TIMESTAMPINDEX = false;
static const bool DEFAULT_SPENTINDEX = false;

5
src/primitives/transaction.h

@ -13,6 +13,7 @@
#include "uint256.h"
#include "consensus/consensus.h"
#include <memory>
#include <boost/array.hpp>
#include "zcash/NoteEncryption.hpp"
@ -407,6 +408,10 @@ public:
std::string ToString() const;
};
typedef std::shared_ptr<const CTransaction> CTransactionRef;
static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
/** A mutable version of CTransaction. */
struct CMutableTransaction
{

1
src/rpcclient.cpp

@ -86,6 +86,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "lockunspent", 1 },
{ "importprivkey", 2 },
{ "importaddress", 2 },
{ "importpubkey", 2 },
{ "verifychain", 0 },
{ "verifychain", 1 },
{ "keypoolrefill", 0 },

91
src/rpcmisc.cpp

@ -28,19 +28,6 @@
using namespace std;
/**
* @note Do not add or change anything in the information returned by this
* method. `getinfo` exists for backwards-compatibility only. It combines
* information from wildly different sources in the program, which is a mess,
* and is thus planned to be deprecated eventually.
*
* Based on the source of the information, new information should be added to:
* - `getblockchaininfo`,
* - `getnetworkinfo` or
* - `getwalletinfo`
*
* Or alternatively, create a specific query method for the information.
**/
UniValue getinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@ -108,6 +95,14 @@ UniValue getinfo(const UniValue& params, bool fHelp)
#endif
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
extern uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID;
extern int32_t NOTARIZED_HEIGHT;
obj.push_back(Pair("notarizedhash", NOTARIZED_HASH.GetHex()));
obj.push_back(Pair("notarizedtxid", NOTARIZED_DESTTXID.GetHex()));
obj.push_back(Pair("notarized", (int)NOTARIZED_HEIGHT));
return obj;
}
@ -941,7 +936,77 @@ UniValue getaddresstxids(const UniValue& params, bool fHelp)
}
return result;
}
//void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
UniValue importpubkey(const UniValue& params, bool fHelp)
{
CWallet * const pwallet = vpwallets[0];
if (!pwallet) {
return NullUniValue;
}
if (fHelp || params.size() < 1 || params.size() > 4)
throw std::runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nArguments:\n"
"1. \"pubkey\" (string, required) The hex-encoded public key\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"\nExamples:\n"
"\nImport a public key with rescan\n"
+ HelpExampleCli("importpubkey", "\"mypubkey\"") +
"\nImport using a label without rescan\n"
+ HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
);
std::string strLabel;
if (!params[1].isNull())
strLabel = params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
if (!params[2].isNull())
fRescan = params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
WalletRescanReserver reserver(pwallet);
if (fRescan && !reserver.reserve()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
}
if (!IsHex(params[0].get_str()))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
std::vector<unsigned char> data(ParseHex(params[0].get_str()));
CPubKey pubKey(data.begin(), data.end());
if (!pubKey.IsFullyValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
{
LOCK2(cs_main, pwallet->cs_wallet);
for (const auto& dest : GetAllDestinationsForKey(pubKey)) {
ImportAddress(pwallet, dest, strLabel);
}
//ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
//pwallet->LearnAllRelatedScripts(pubKey);
}
if (fRescan)
{
pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
pwallet->ReacceptWalletTransactions();
}
return NullUniValue;
}
UniValue getspentinfo(const UniValue& params, bool fHelp)

6
src/rpcserver.cpp

@ -27,6 +27,7 @@
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
#include "komodo_rpcblockchain.h"
using namespace RPCServer;
using namespace std;
@ -252,6 +253,8 @@ UniValue stop(const UniValue& params, bool fHelp)
return "Hush server stopping";
}
extern UniValue importpubkey(const UniValue &params, bool fHelp);
/**
* Call Table
*/
@ -295,6 +298,8 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
{ "blockchain", "verifychain", &verifychain, true },
{ "blockchain", "getspentinfo", &getspentinfo, false },
{ "blockchain", "calc_MoM", &calc_MoM, true },
{ "blockchain", "height_MoM", &height_MoM, true },
/* Mining */
{ "mining", "getblocktemplate", &getblocktemplate, true },
@ -366,6 +371,7 @@ static const CRPCCommand vRPCCommands[] =
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
{ "wallet", "getwalletinfo", &getwalletinfo, false },
{ "wallet", "importprivkey", &importprivkey, true },
{ "wallet", "importpubkey", &importpubkey, true },
{ "wallet", "importwallet", &importwallet, true },
{ "wallet", "importaddress", &importaddress, true },
{ "wallet", "keypoolrefill", &keypoolrefill, true },

9
src/script/standard.cpp

@ -306,6 +306,11 @@ CScript GetScriptForDestination(const CTxDestination& dest)
return script;
}
CScript GetScriptForRawPubKey(const CPubKey& pubKey)
{
return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
}
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
{
CScript script;
@ -316,3 +321,7 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
return script;
}
bool IsValidDestination(const CTxDestination& dest) {
return dest.which() != 0;
}

3
src/script/standard.h

@ -84,6 +84,8 @@ typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
const char* GetTxnOutputType(txnouttype t);
bool IsValidDestination(const CTxDestination& dest);
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);
@ -92,5 +94,6 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
CScript GetScriptForDestination(const CTxDestination& dest);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
#endif // BITCOIN_SCRIPT_STANDARD_H

38
src/wallet/rpcdump.cpp

@ -74,6 +74,44 @@ std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript);
void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
{
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
pwallet->MarkDirty();
if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
if (isRedeemScript) {
if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
ImportAddress(pwallet, CBitcoinAddress( CScriptID(script) ), strLabel);
} else {
CTxDestination destination;
if (ExtractDestination(script, destination)) {
pwallet->SetAddressBook(destination, strLabel, "receive");
}
}
}
void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel)
{
CScript script = GetScriptForDestination(address.Get());
ImportScript(pwallet, script, strLabel, false);
// add to address book or update label
if (address.IsValid())
pwallet->SetAddressBook(address.Get(), strLabel, "receive");
}
UniValue importprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))

61
src/wallet/wallet.cpp

@ -37,6 +37,7 @@ unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = true;
bool fSendFreeTransactions = false;
bool fPayAtLeastCustomFee = true;
std::vector<CWalletRef> vpwallets;
/**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
@ -1680,6 +1681,43 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
}
/**
* Scan active chain for relevant transactions after importing keys. This should
* be called whenever new keys are added to the wallet, with the oldest key
* creation time.
*
* @return Earliest timestamp that could be successfully scanned from. Timestamp
* returned will be higher than startTime if relevant blocks could not be read.
*/
int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update)
{
// Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs
// to be scanned.
CBlockIndex* startBlock = nullptr;
{
LOCK(cs_main);
startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
}
if (startBlock) {
//const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, false); //nullptr, reserver, update);
//if (failedBlock) {
// return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
//}
ScanForWalletTransactions(startBlock, false); //nullptr, reserver, update);
}
return startTime;
}
CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
{
std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
[](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
return (lower == vChain.end() ? nullptr : *lower);
}
void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
{
@ -3368,6 +3406,12 @@ void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
}
}
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
{
CKeyID keyid = key.GetID();
return std::vector<CTxDestination>{std::move(keyid)};
}
void CWallet::UpdatedTransaction(const uint256 &hashTx)
{
{
@ -3839,3 +3883,20 @@ void CWallet::GetUnspentFilteredNotes(
}
}
}
void CWallet::LearnRelatedScripts(const CPubKey& key, OutputType type)
{
if (key.IsCompressed() && (type == OutputType::P2SH_SEGWIT || type == OutputType::BECH32)) {
//CTxDestination witdest = WitnessV0KeyHash(key.GetID());
//CScript witprog = GetScriptForDestination(witdest);
// Make sure the resulting program is solvable.
//assert(IsSolvable(*this, witprog));
//AddCScript(witprog);
}
}
void CWallet::LearnAllRelatedScripts(const CPubKey& key)
{
// OutputType::P2SH_SEGWIT always adds all necessary scripts for all types.
LearnRelatedScripts(key, OutputType::P2SH_SEGWIT);
}

83
src/wallet/wallet.h

@ -32,6 +32,11 @@
#include <string>
#include <utility>
#include <vector>
#include <mutex>
typedef CWallet* CWalletRef;
extern std::vector<CWalletRef> vpwallets;
static const int64_t TIMESTAMP_MIN = 0;
/**
* Settings
@ -68,6 +73,13 @@ class CScript;
class CTxMemPool;
class CWalletTx;
enum class OutputType {
NONE,
LEGACY,
P2SH_SEGWIT,
BECH32,
};
/** (client) version numbers for particular wallet features */
enum WalletFeature
{
@ -285,6 +297,7 @@ private:
int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
public:
CTransactionRef tx;
uint256 hashBlock;
std::vector<uint256> vMerkleBranch;
int nIndex;
@ -295,6 +308,13 @@ public:
CMerkleTx()
{
SetTx(MakeTransactionRef());
Init();
}
explicit CMerkleTx(CTransactionRef arg)
{
SetTx(std::move(arg));
Init();
}
@ -310,6 +330,11 @@ public:
fMerkleVerified = false;
}
void SetTx(CTransactionRef arg)
{
tx = std::move(arg);
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@ -657,6 +682,8 @@ private:
};
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
/**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
@ -668,6 +695,10 @@ private:
CWalletDB *pwalletdbEncryption;
std::atomic<bool> fScanningWallet; //controlled by WalletRescanReserver
std::mutex mutexScanning;
friend class WalletRescanReserver;
//! the current wallet version: clients below this version are not able to load the wallet
int nWalletVersion;
@ -1002,6 +1033,8 @@ public:
std::vector<uint256> commitments,
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
uint256 &final_anchor);
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
//CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime);
@ -1148,6 +1181,19 @@ public:
int minDepth=1,
int maxDepth=INT_MAX,
bool ignoreUnspendable=true);
/**
* Explicitly make the wallet learn the related scripts for outputs to the
* given key. This is purely to make the wallet file compatible with older
* software, as CBasicKeyStore automatically does this implicitly for all
* keys now.
*/
void LearnRelatedScripts(const CPubKey& key, OutputType);
/**
* Same as LearnRelatedScripts, but when the OutputType is not known (and could
* be anything).
*/
void LearnAllRelatedScripts(const CPubKey& key);
};
/** A key allocated from the key pool. */
@ -1204,4 +1250,41 @@ public:
}
};
/** RAII object to check and reserve a wallet rescan */
class WalletRescanReserver
{
private:
CWalletRef m_wallet;
bool m_could_reserve;
public:
explicit WalletRescanReserver(CWalletRef w) : m_wallet(w), m_could_reserve(false) {}
bool reserve()
{
assert(!m_could_reserve);
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
if (m_wallet->fScanningWallet) {
return false;
}
m_wallet->fScanningWallet = true;
m_could_reserve = true;
return true;
}
bool isReserved() const
{
return (m_could_reserve && m_wallet->fScanningWallet);
}
~WalletRescanReserver()
{
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
if (m_could_reserve) {
m_wallet->fScanningWallet = false;
}
}
};
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
#endif // BITCOIN_WALLET_WALLET_H

Loading…
Cancel
Save