diff --git a/src/Makefile.am b/src/Makefile.am index b1fce17fc2..bf9a508498 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -388,6 +388,7 @@ BITCOIN_CORE_H = \ qtum/qtumDGP.h \ qtum/storageresults.h \ qtum/qtumutils.h \ + qtum/qtumdelegation.h \ qtum/qtumtoken.h \ qtum/qtumledger.h \ qtum/delegationutils.h @@ -740,6 +741,7 @@ libbitcoin_common_a_SOURCES = \ qtum/qtumutils.cpp \ qtum/qtumDGP.cpp \ qtum/qtumtoken.cpp \ + qtum/qtumdelegation.cpp \ qtum/delegationutils.cpp \ util/contractabi.cpp \ libff/libff/algebra/curves/public_params.hpp \ diff --git a/src/addresstype.cpp b/src/addresstype.cpp index f199d1b479..6e50731c86 100644 --- a/src/addresstype.cpp +++ b/src/addresstype.cpp @@ -167,3 +167,8 @@ CScript GetScriptForDestination(const CTxDestination& dest) bool IsValidDestination(const CTxDestination& dest) { return std::visit(ValidDestinationVisitor(), dest); } + +PKHash ExtractPublicKeyHash(const CScript& scriptPubKey, bool* OK) +{ + return {}; +} diff --git a/src/addresstype.h b/src/addresstype.h index 522f58fef1..b8c27ceec4 100644 --- a/src/addresstype.h +++ b/src/addresstype.h @@ -150,4 +150,6 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) */ CScript GetScriptForDestination(const CTxDestination& dest); +PKHash ExtractPublicKeyHash(const CScript& scriptPubKey, bool* OK = nullptr); + #endif // BITCOIN_ADDRESSTYPE_H diff --git a/src/init.cpp b/src/init.cpp index 8baa642d30..7a57a9b740 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,11 @@ #include #include #include +#ifdef ENABLE_WALLET +#include +#include +#endif +#include #include #include @@ -154,7 +160,7 @@ static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map"; /** * The PID file facilities. */ -static const char* BITCOIN_PID_FILENAME = "bitcoind.pid"; +static const char* BITCOIN_PID_FILENAME = "qtumd.pid"; static fs::path GetPidFile(const ArgsManager& args) { @@ -238,6 +244,8 @@ void Interrupt(NodeContext& node) void Shutdown(NodeContext& node) { + StartShutdown(); + static Mutex g_shutdown_mutex; TRY_LOCK(g_shutdown_mutex, lock_shutdown); if (!lock_shutdown) return; @@ -248,7 +256,20 @@ void Shutdown(NodeContext& node) /// for example if the data directory was found to be locked. /// Be sure that anything that writes files or flushes caches only does this if the respective /// module was initialized. - util::ThreadRename("shutoff"); + util::ThreadRename("qtum-shutoff"); + +#ifdef ENABLE_WALLET + if(node.wallet_loader && node.wallet_loader->context()) + { + // Force stop the stakers before any other components + for (const std::shared_ptr& pwallet : GetWallets(*node.wallet_loader->context())) + { + pwallet->StopStake(); + } + } +#endif + if(node.peerman) node.peerman->StopCleanBlockIndex(); + if (node.mempool) node.mempool->AddTransactionsUpdated(1); StopHTTPRPC(); @@ -328,6 +349,9 @@ void Shutdown(NodeContext& node) chainstate->ResetCoinsViews(); } } + pstorageresult.reset(); + globalState.reset(); + globalSealEngine.reset(); } for (const auto& client : node.chain_clients) { client->stop(); @@ -465,6 +489,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-reindex", "If enabled, wipe chain state and block index, and rebuild them from blk*.dat files on disk. Also wipe and rebuild other optional indexes that are active. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-reindex-chainstate", "If enabled, wipe chain state, and rebuild it from blk*.dat files on disk. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-settings=", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-record-log-opcodes", "Logs all EVM LOG opcode operations to the file vmExecLogs.json", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #if HAVE_SYSTEM argsman.AddArg("-startupnotify=", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-shutdownnotify=", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -474,6 +499,10 @@ void SetupServerArgs(ArgsManager& argsman) strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) + " If is not supplied or if = 1, indexes for all known types are enabled.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-logevents", strprintf("Maintain a full EVM log index, used by searchlogs and gettransactionreceipt rpc calls (default: %u)", DEFAULT_LOGEVENTS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-addrindex", strprintf("Maintain a full address index (default: %u)", DEFAULT_ADDRINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-deleteblockchaindata", "Delete the local copy of the block chain data", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-forceinitialblocksdownloadmode", strprintf("Force initial blocks download mode for the node (default: %u)", DEFAULT_FORCE_INITIAL_BLOCKS_DOWNLOAD_MODE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-addnode=", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-asmap=", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -513,6 +542,9 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-peertimeout=", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-torcontrol=:", strprintf("Tor control host and port to use if onion listening enabled (default: %s). If no port is specified, the default port of %i will be used.", DEFAULT_TOR_CONTROL, DEFAULT_TOR_CONTROL_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-torpassword=", "Tor control port password (default: empty)", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::CONNECTION); + argsman.AddArg("-dgpstorage", "Receiving data from DGP via storage (default: -dgpevm)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-dgpevm", "Receiving data from DGP via a contract call (default: -dgpevm)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-hwitoolpath=", "Specify HWI tool path", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #ifdef USE_UPNP #if USE_UPNP argsman.AddArg("-upnp", "Use UPnP to map the listening port (default: 1 when listening and no -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -576,14 +608,31 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-addrmantest", "Allows to test address relay on localhost", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-showevmlogs", strprintf("Print evm logs to console (default: %u)", DEFAULT_SHOWEVMLOGS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-mocktime=", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-maxsigcachesize=", strprintf("Limit sum of signature cache and script execution cache sizes to MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", Ticks(DEFAULT_MAX_TIP_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-minmempoolgaslimit=", strprintf("The minimum transaction gas limit we are willing to accept into the mempool (default: %s)",MEMPOOL_MIN_GAS_LIMIT), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-uacomment=", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-opsenderheight=", "Use given block height to check opsender fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-btcecrecoverheight=", "Use given block height to check btc_ecrecover fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-constantinopleheight=", "Use given block height to check constantinople fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-difficultychangeheight=", "Use given block height to check difficulty change fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-offlinestakingheight=", "Use given block height to check offline staking fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-delegationsaddress=", "Use given contract delegations address for offline staking fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-lastmposheight=", "Use given block height to check remove mpos fork (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-reduceblocktimeheight=", "Use given block height to check blocks with reduced target spacing (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-powallowmindifficultyblocks", "Use given value for pow allow min difficulty blocks parameter (regtest-only, default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-pownoretargeting", "Use given value for pow no retargeting parameter (regtest-only, default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-posnoretargeting", "Use given value for pos no retargeting parameter (regtest-only, default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-muirglacierheight=", "Use given block height to check contracts with EVM Muir Glacier (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-londonheight=", "Use given block height to check contracts with EVM London (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-taprootheight=", "Use given block height to check taproot (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-shanghaiheight=", "Use given block height to check contracts with EVM Shanghai (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); SetupChainParamsBaseOptions(argsman); @@ -611,6 +660,12 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-blockmintxfee=", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockversion=", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-staker-min-tx-gas-price=", "Any contract execution with a gas price below this will not be included in a block (defaults to the value specified by the DGP)", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-staker-max-tx-gas-limit=", "Any contract execution with a gas limit over this amount will not be included in a block (defaults to soft block gas limit)", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-staker-soft-block-gas-limit=", "After this amount of gas is surpassed in a block, no more contract executions will be added to the block (defaults to consensus-critical maximum block gas limit)", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-aggressive-staking", "Check more often to publish immediately when valid block is found.", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-emergencystaking", "Emergency staking without blockchain synchronization.", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcallowip=", "Allow JSON-RPC connections from specified source. Valid values for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcauth=", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=/rpcpassword= pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC); @@ -635,6 +690,14 @@ void SetupServerArgs(ArgsManager& argsman) hidden_args.emplace_back("-daemon"); hidden_args.emplace_back("-daemonwait"); #endif + argsman.AddArg("-headerspamfilter=", strprintf("Use header spam filter (default: %u)", DEFAULT_HEADER_SPAM_FILTER), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-headerspamfiltermaxsize=", strprintf("Maximum size of the list of indexes in the header spam filter (default: %u)", DEFAULT_HEADER_SPAM_FILTER_MAX_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-headerspamfiltermaxavg=", strprintf("Maximum average size of an index occurrence in the header spam filter (default: %u)", DEFAULT_HEADER_SPAM_FILTER_MAX_AVG), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-headerspamfilterignoreport=", strprintf("Ignore the port in the ip address when looking for header spam, determine whether or not multiple nodes can be on the same IP (default: %u)", DEFAULT_HEADER_SPAM_FILTER_IGNORE_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-cleanblockindex=", "Clean block index (enabled by default)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-cleanblockindextimeout=", "Clean block index periodically after some time (default 600 seconds)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-stakingallowlist=
", "Allow list delegate address. Can be specified multiple times to add multiple addresses.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-stakingexcludelist=
", "Exclude list delegate address. Can be specified multiple times to add multiple addresses.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); // Add the hidden options argsman.AddHiddenArgs(hidden_args); @@ -655,6 +718,19 @@ static void BlockNotifyGenesisWait(const CBlockIndex* pBlockIndex) } } +// Delete local blockchain data +void DeleteBlockChainData() +{ + // Delete block chain data paths + fs::path datadir = gArgs.GetDataDirNet(); + fs::remove_all(datadir / "chainstate"); + fs::remove_all(gArgs.GetBlocksDirPath()); + fs::remove_all(datadir / "stateQtum"); + fs::remove(datadir / "banlist.dat"); + fs::remove(datadir / "fee_estimates.dat"); + fs::remove(datadir / "mempool.dat"); +} + #if HAVE_SYSTEM static void StartupNotify(const ArgsManager& args) { @@ -767,6 +843,19 @@ void InitParameterInteraction(ArgsManager& args) LogPrintf("%s: parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n", __func__); } } + +#ifdef ENABLE_WALLET + // Set the required parameters for super staking + if(args.GetBoolArg("-superstaking", node::DEFAULT_SUPER_STAKE)) + { + if (args.SoftSetBoolArg("-staking", true)) + LogPrintf("%s: parameter interaction: -superstaking=1 -> setting -staking=1\n", __func__); + if (args.SoftSetBoolArg("-logevents", true)) + LogPrintf("%s: parameter interaction: -superstaking=1 -> setting -logevents=1\n", __func__); + if (args.SoftSetBoolArg("-addrindex", true)) + LogPrintf("%s: parameter interaction: -superstaking=1 -> setting -addrindex=1\n", __func__); + } +#endif } /** @@ -1021,17 +1110,239 @@ bool AppInitParameterInteraction(const ArgsManager& args) } } + if (args.IsArgSet("-opsenderheight")) { + // Allow overriding opsender block for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Op Sender block height may only be overridden on regtest.")); + } + + int opsenderBlock = args.GetIntArg("-opsenderheight", 0); + if(opsenderBlock >= 0) + { + UpdateOpSenderBlockHeight(opsenderBlock); + LogPrintf("Activate Op Sender at block height %d\n.", opsenderBlock); + } + } + + if (args.IsArgSet("-btcecrecoverheight")) { + // Allow overriding btc_ecrecover block for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Btc_ecrecover block height may only be overridden on regtest.")); + } + + int btcEcrecoverBlock = args.GetIntArg("-btcecrecoverheight", 0); + if(btcEcrecoverBlock >= 0) + { + UpdateBtcEcrecoverBlockHeight(btcEcrecoverBlock); + LogPrintf("Activate btc_ecrecover at block height %d\n.", btcEcrecoverBlock); + } + } + + if (args.IsArgSet("-constantinopleheight")) { + // Allow overriding constantinople block for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Constantinople block height may only be overridden on regtest.")); + } + + int constantinopleBlock = args.GetIntArg("-constantinopleheight", 0); + if(constantinopleBlock >= 0) + { + UpdateConstantinopleBlockHeight(constantinopleBlock); + LogPrintf("Activate constantinople at block height %d\n.", constantinopleBlock); + } + } + + if (args.IsArgSet("-difficultychangeheight")) { + // Allow overriding difficulty change block for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Difficulty change block height may only be overridden on regtest.")); + } + + int difficultyChangeBlock = args.GetIntArg("-difficultychangeheight", 0); + if(difficultyChangeBlock >= 0) + { + UpdateDifficultyChangeBlockHeight(difficultyChangeBlock); + LogPrintf("Activate difficulty change at block height %d\n.", difficultyChangeBlock); + } + } + + if (args.IsArgSet("-offlinestakingheight")) { + // Allow overriding offline staking block for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Offline staking block height may only be overridden on regtest.")); + } + + int offlineStakingBlock = args.GetIntArg("-offlinestakingheight", 0); + if(offlineStakingBlock >= 0) + { + UpdateOfflineStakingBlockHeight(offlineStakingBlock); + LogPrintf("Activate offline staking at block height %d\n.", offlineStakingBlock); + } + } + + if (args.IsArgSet("-delegationsaddress")) { + // Allow overriding delegations address for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("delegations address may only be overridden on regtest.")); + } + + std::string delegationsAddress = args.GetArg("-delegationsaddress", std::string()); + if(IsHex(delegationsAddress)) + { + UpdateDelegationsAddress(uint160(ParseHex(delegationsAddress))); + LogPrintf("Activate delegations address %s\n.", delegationsAddress); + } + } + + if (args.IsArgSet("-lastmposheight")) { + // Allow overriding last MPoS block for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Last MPoS block height may only be overridden on regtest.")); + } + + int lastMPosBlockHeight = args.GetIntArg("-lastmposheight", 0); + if(lastMPosBlockHeight >= 0) + { + UpdateLastMPoSBlockHeight(lastMPosBlockHeight); + LogPrintf("Set last MPoS block height %d\n.", lastMPosBlockHeight); + } + } + + if (args.IsArgSet("-reduceblocktimeheight")) { + // Allow overriding short block time block height for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Short block time height may only be overridden on regtest.")); + } + + int reduceblocktimeheight = args.GetIntArg("-reduceblocktimeheight", 0); + if(reduceblocktimeheight >= 0) + { + UpdateReduceBlocktimeHeight(reduceblocktimeheight); + LogPrintf("Activate short block time at block height %d\n.", reduceblocktimeheight); + } + } + + if (args.IsArgSet("-powallowmindifficultyblocks")) { + // Allow overriding pow allow min difficulty blocks parameter for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Pow allow min difficulty blocks parameter may only be overridden on regtest.")); + } + + bool powallowmindifficultyblocks = args.GetBoolArg("-powallowmindifficultyblocks", 1); + UpdatePowAllowMinDifficultyBlocks(powallowmindifficultyblocks); + LogPrintf("Use given value for pow allow min difficulty blocks parameter %d\n.", powallowmindifficultyblocks); + } + + if (args.IsArgSet("-pownoretargeting")) { + // Allow overriding pow no retargeting parameter for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Pow no retargeting parameter may only be overridden on regtest.")); + } + + bool pownoretargeting = args.GetBoolArg("-pownoretargeting", 1); + UpdatePowNoRetargeting(pownoretargeting); + LogPrintf("Use given value for pow no retargeting parameter %d\n.", pownoretargeting); + } + + if (args.IsArgSet("-posnoretargeting")) { + // Allow overriding pos no retargeting parameter for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("PoS no retargeting parameter may only be overridden on regtest.")); + } + + bool posnoretargeting = args.GetBoolArg("-posnoretargeting", 1); + UpdatePoSNoRetargeting(posnoretargeting); + LogPrintf("Use given value for pos no retargeting parameter %d\n.", posnoretargeting); + } + + if (args.IsArgSet("-muirglacierheight")) { + // Allow overriding EVM Muir Glacier block height for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Short EVM Muir Glacier height may only be overridden on regtest.")); + } + + int muirglacierheight = args.GetIntArg("-muirglacierheight", 0); + if(muirglacierheight >= 0) + { + UpdateMuirGlacierHeight(muirglacierheight); + LogPrintf("Activate EVM Muir Glacier at block height %d\n.", muirglacierheight); + } + } + + if (args.IsArgSet("-londonheight")) { + // Allow overriding EVM London block height for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Short EVM London height may only be overridden on regtest.")); + } + + int londonheight = args.GetIntArg("-londonheight", 0); + if(londonheight >= 0) + { + UpdateLondonHeight(londonheight); + LogPrintf("Activate EVM London at block height %d\n.", londonheight); + } + } + + if (args.IsArgSet("-taprootheight")) { + // Allow overriding taproot block height for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Taproot height may only be overridden on regtest.")); + } + + int taprootheight = args.GetIntArg("-taprootheight", 0); + if(taprootheight >= 0) + { + UpdateTaprootHeight(taprootheight); + LogPrintf("Activate taproot at block height %d\n.", taprootheight); + } + } + + if (args.IsArgSet("-shanghaiheight")) { + // Allow overriding EVM Shanghai block height for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError(Untranslated("Short EVM Shanghai height may only be overridden on regtest.")); + } + + int shanghaiheight = args.GetIntArg("-shanghaiheight", 0); + if(shanghaiheight >= 0) + { + UpdateShanghaiHeight(shanghaiheight); + LogPrintf("Activate EVM Shanghai at block height %d\n.", shanghaiheight); + } + } + + if(args.IsArgSet("-stakingallowlist") && args.IsArgSet("-stakingexcludelist")) + { + return InitError(Untranslated("Either -stakingallowlist or -stakingexcludelist parameter can be specified to the staker, not both.")); + } + + // Check allow list + for (const std::string& strAddress : args.GetArgs("-stakingallowlist")) + { + CTxDestination dest = DecodeDestination(strAddress); + if(!std::holds_alternative(dest)) + return InitError(Untranslated(strprintf("-stakingallowlist, address %s does not refer to public key hash", strAddress))); + } + + // Check exclude list + for (const std::string& strAddress : args.GetArgs("-stakingexcludelist")) + { + CTxDestination dest = DecodeDestination(strAddress); + if(!std::holds_alternative(dest)) + return InitError(Untranslated(strprintf("-stakingexcludelist, address %s does not refer to public key hash", strAddress))); + } + return true; } -static bool LockDataDirectory(bool probeOnly) +static bool LockDataDirectory(bool probeOnly, bool try_lock = true) { // Make sure only a single Bitcoin process is using the data directory. const fs::path& datadir = gArgs.GetDataDirNet(); if (!DirIsWritable(datadir)) { return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir))); } - if (!LockDirectory(datadir, ".lock", probeOnly)) { + if (!LockDirectory(datadir, ".lock", probeOnly, try_lock)) { return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME)); } return true; @@ -1095,12 +1406,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Warn about relative -datadir path. if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) { LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " - "current working directory '%s'. This is fragile, because if bitcoin is started in the future " + "current working directory '%s'. This is fragile, because if qtum is started in the future " "from a different location, it will be unable to locate the current data files. There could " - "also be data loss if bitcoin is started while in a temporary directory.\n", + "also be data loss if qtum is started while in a temporary directory.\n", args.GetArg("-datadir", ""), fs::PathToString(fs::current_path())); } + if(args.GetBoolArg("-deleteblockchaindata", false)) + { + DeleteBlockChainData(); + } + ValidationCacheSizes validation_cache_sizes{}; ApplyArgsManOptions(args, validation_cache_sizes); if (!InitSignatureCache(validation_cache_sizes.signature_cache_bytes) @@ -1520,6 +1836,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) _("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR); }; + if((args.IsArgSet("-dgpstorage") && args.IsArgSet("-dgpevm")) || (!args.IsArgSet("-dgpstorage") && args.IsArgSet("-dgpevm")) || + (!args.IsArgSet("-dgpstorage") && !args.IsArgSet("-dgpevm"))){ + options.getting_values_dgp = true; + } else { + options.getting_values_dgp = false; + } + options.record_log_opcodes = args.IsArgSet("-record-log-opcodes"); + options.addrindex = args.GetBoolArg("-addrindex", DEFAULT_ADDRINDEX); + options.logevents = args.GetBoolArg("-logevents", DEFAULT_LOGEVENTS); uiInterface.InitMessage(_("Loading block index…").translated); const auto load_block_index_start_time{SteadyClock::now()}; @@ -1710,6 +2035,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } }); + node.peerman->InitCleanBlockIndex(); + // Wait for genesis block to be processed { WAIT_LOCK(g_genesis_wait_mutex, lock); @@ -1970,3 +2297,12 @@ bool StartIndexBackgroundSync(NodeContext& node) for (auto index : node.indexes) if (!index->StartBackgroundSync()) return false; return true; } + +void UnlockDataDirectory() +{ + // Unlock + const fs::path& datadir = gArgs.GetDataDirNet(); + if (DirIsWritable(datadir)) { + UnlockDirectory(datadir, ".lock"); + } +} diff --git a/src/init.h b/src/init.h index f27d6120ef..07151bc02d 100644 --- a/src/init.h +++ b/src/init.h @@ -76,4 +76,7 @@ void SetupServerArgs(ArgsManager& argsman); /** Validates requirements to run the indexes and spawns each index initial sync thread */ bool StartIndexBackgroundSync(node::NodeContext& node); +/** Unlock the data directory */ +void UnlockDataDirectory(); + #endif // BITCOIN_INIT_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b51cca62c4..b54a83a3aa 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -482,6 +482,7 @@ class PeerManagerImpl final : public PeerManager PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* banman, ChainstateManager& chainman, CTxMemPool& pool, Options opts); + ~PeerManagerImpl(); /** Overridden from CValidationInterface. */ void BlockConnected(ChainstateRole role, const std::shared_ptr& pblock, const CBlockIndex* pindexConnected) override @@ -518,6 +519,8 @@ class PeerManagerImpl final : public PeerManager const std::chrono::microseconds time_received, const std::atomic& interruptMsgProc) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; + void InitCleanBlockIndex() override; + void StopCleanBlockIndex() override; private: /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */ @@ -1912,6 +1915,12 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } +PeerManagerImpl::~PeerManagerImpl() +{ + // Stop clean block index thread + StopCleanBlockIndex(); +} + /** * Evict orphan txn pool entries based on a newly connected * block, remember the recently confirmed transactions, and delete tracked @@ -5995,3 +6004,16 @@ bool PeerManagerImpl::SendMessages(CNode* pto) MaybeSendFeefilter(*pto, *peer, current_time); return true; } + +void PeerManagerImpl::InitCleanBlockIndex() +{ +} + +void PeerManagerImpl::StopCleanBlockIndex() +{ +} + +unsigned int GefaultHeaderSpamFilterMaxSize() +{ + return Params().GetConsensus().MaxCheckpointSpan(); +} diff --git a/src/net_processing.h b/src/net_processing.h index 80d07648a4..ae41ad43dd 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -28,6 +28,22 @@ static const int DISCOURAGEMENT_THRESHOLD{100}; /** Maximum number of outstanding CMPCTBLOCK requests for the same block. */ static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK = 3; +/** Default maximum orphan blocks */ +static const unsigned int DEFAULT_MAX_ORPHAN_BLOCKS = 40; +/** Default for -headerspamfilter, use header spam filter */ +static const bool DEFAULT_HEADER_SPAM_FILTER = true; +/** Default for -headerspamfiltermaxsize, maximum size of the list of indexes in the header spam filter */ +static const unsigned int DEFAULT_HEADER_SPAM_FILTER_MAX_SIZE = 2000; +/** Default for -headerspamfiltermaxavg, maximum average size of an index occurrence in the header spam filter */ +static const unsigned int DEFAULT_HEADER_SPAM_FILTER_MAX_AVG = 10; +/** Default for -headerspamfilterignoreport, ignore the port in the ip address when looking for header spam, + multiple nodes on the same ip will be treated as the one when computing the filter*/ +static const unsigned int DEFAULT_HEADER_SPAM_FILTER_IGNORE_PORT = true; +/** Default for -cleanblockindex. */ +static const bool DEFAULT_CLEANBLOCKINDEX = true; +/** Default for -cleanblockindextimeout. */ +static const unsigned int DEFAULT_CLEANBLOCKINDEXTIMEOUT = 600; + struct CNodeStateStats { int nSyncHeight = -1; int nCommonHeight = -1; @@ -110,6 +126,15 @@ class PeerManager : public CValidationInterface, public NetEventsInterface /** This function is used for testing the stale tip eviction logic, see denialofservice_tests.cpp */ virtual void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) = 0; + + /** Initialize clean block index */ + virtual void InitCleanBlockIndex() = 0; + + /** Stop clean block index thread */ + virtual void StopCleanBlockIndex() = 0; }; +/** Default for -headerspamfiltermaxsize, maximum size of the list of indexes in the header spam filter */ +unsigned int GefaultHeaderSpamFilterMaxSize(); + #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index eb1994177a..135fb57b19 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -40,6 +42,9 @@ static ChainstateLoadResult CompleteChainstateInitialization( // new BlockTreeDB tries to delete the existing file, which // fails if it's still open from the previous loop. Close it first: pblocktree.reset(); + pstorageresult.reset(); + globalState.reset(); + globalSealEngine.reset(); pblocktree = std::make_unique(DBParams{ .path = chainman.m_options.datadir / "blocks" / "index", .cache_bytes = static_cast(cache_sizes.block_tree_db), @@ -141,6 +146,62 @@ static ChainstateLoadResult CompleteChainstateInitialization( } } + /////////////////////////////////////////////////////////// qtum + fGettingValuesDGP = options.getting_values_dgp; + + dev::eth::NoProof::init(); + fs::path qtumStateDir = gArgs.GetDataDirNet() / "stateQtum"; + bool fStatus = fs::exists(qtumStateDir); + const std::string dirQtum = PathToString(qtumStateDir); + const dev::h256 hashDB(dev::sha3(dev::rlp(""))); + dev::eth::BaseState existsQtumstate = fStatus ? dev::eth::BaseState::PreExisting : dev::eth::BaseState::Empty; + globalState = std::unique_ptr(new QtumState(dev::u256(0), QtumState::openDB(dirQtum, hashDB, dev::WithExisting::Trust), dirQtum, existsQtumstate)); + const CChainParams& chainparams = Params(); + dev::eth::ChainParams cp(chainparams.EVMGenesisInfo()); + globalSealEngine = std::unique_ptr(cp.createSealEngine()); + + pstorageresult.reset(new StorageResults(PathToString(qtumStateDir))); + if (options.reindex) { + pstorageresult->wipeResults(); + } + + { + LOCK(cs_main); + CChain& active_chain = chainman.ActiveChain(); + if(active_chain.Tip() != nullptr){ + globalState->setRoot(uintToh256(active_chain.Tip()->hashStateRoot)); + globalState->setRootUTXO(uintToh256(active_chain.Tip()->hashUTXORoot)); + } else { + globalState->setRoot(dev::sha3(dev::rlp(""))); + globalState->setRootUTXO(uintToh256(chainparams.GenesisBlock().hashUTXORoot)); + globalState->populateFrom(cp.genesisState); + } + globalState->db().commit(); + globalState->dbUtxo().commit(); + } + + fRecordLogOpcodes = options.record_log_opcodes; + fIsVMlogFile = fs::exists(gArgs.GetDataDirNet() / "vmExecLogs.json"); + /////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////// // qtum + if (fAddressIndex != options.addrindex) { + return {ChainstateLoadStatus::FAILURE, _("You need to rebuild the database using -reindex to change -addrindex")}; + } + /////////////////////////////////////////////////////////////// + // Check for changed -logevents state + if (fLogEvents != options.logevents && !fLogEvents) { + return {ChainstateLoadStatus::FAILURE, _("You need to rebuild the database using -reindex to enable -logevents")}; + } + + if (!options.logevents) + { + pstorageresult->wipeResults(); + pblocktree->WipeHeightIndex(); + fLogEvents = false; + pblocktree->WriteFlag("logevents", fLogEvents); + } + if (!options.reindex) { auto chainstates{chainman.GetAll()}; if (std::any_of(chainstates.begin(), chainstates.end(), @@ -251,6 +312,10 @@ ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const C LOCK(cs_main); + CChain& active_chain = chainman.ActiveChain(); + QtumDGP qtumDGP(globalState.get(), chainman.ActiveChainstate(), fGettingValuesDGP); + globalSealEngine->setQtumSchedule(qtumDGP.getGasSchedule(active_chain.Height() + (active_chain.Height()+1 >= chainman.GetConsensus().QIP7Height ? 0 : 1) )); + for (Chainstate* chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { const CBlockIndex* tip = chainstate->m_chain.Tip(); diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 7c740eebaa..fdf7a1d77f 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #if defined(HAVE_CONFIG_H) #include @@ -361,6 +363,13 @@ class NodeImpl : public Node } void getGasInfo(uint64_t& blockGasLimit, uint64_t& minGasPrice, uint64_t& nGasPrice) override { + LOCK(::cs_main); + + QtumDGP qtumDGP(globalState.get(), chainman().ActiveChainstate(), fGettingValuesDGP); + int numBlocks = chainman().ActiveChain().Height(); + blockGasLimit = qtumDGP.getBlockGasLimit(numBlocks); + minGasPrice = CAmount(qtumDGP.getMinGasPrice(numBlocks)); + nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE; } void getSyncInfo(int& numBlocks, bool& isSyncing) override { @@ -394,11 +403,13 @@ class NodeImpl : public Node } uint64_t getNetworkStakeWeight() override { - return {}; + LOCK(::cs_main); + return GetPoSKernelPS(chainman()); } double getEstimatedAnnualROI() override { - return {}; + LOCK(::cs_main); + return GetEstimatedAnnualROI(chainman()); } int64_t getMoneySupply() override { @@ -407,7 +418,7 @@ class NodeImpl : public Node } double getPoSKernelPS() override { - return {}; + return GetPoSKernelPS(chainman()); } std::unique_ptr handleInitMessage(InitMessageFn fn) override { @@ -945,11 +956,12 @@ class ChainImpl : public Chain #endif bool getDelegation(const uint160& address, Delegation& delegation) override { - return {}; + QtumDelegation qtumDelegation; + return qtumDelegation.ExistDelegationContract() ? qtumDelegation.GetDelegation(address, delegation, chainman().ActiveChainstate()) : false; } bool verifyDelegation(const uint160& address, const Delegation& delegation) override { - return {}; + return QtumDelegation::VerifyDelegation(address, delegation); } NodeContext& m_node; diff --git a/src/qtum/qtumdelegation.cpp b/src/qtum/qtumdelegation.cpp index 435e81efd4..2c879d799c 100644 --- a/src/qtum/qtumdelegation.cpp +++ b/src/qtum/qtumdelegation.cpp @@ -6,6 +6,7 @@ #include #include #include +#include const std::string strDelegationsABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_staker\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_delegate\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"fee\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockHeight\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"PoD\",\"type\":\"bytes\"}],\"name\":\"AddDelegation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_staker\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_delegate\",\"type\":\"address\"}],\"name\":\"RemoveDelegation\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_staker\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_fee\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_PoD\",\"type\":\"bytes\"}],\"name\":\"addDelegation\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegations\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"fee\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"blockHeight\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"PoD\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"removeDelegation\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; const ContractABI contractDelegationABI = strDelegationsABI; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 9a8f403bc4..23bd52a32b 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,8 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto throw std::runtime_error{error}; } } + m_args.SoftSetBoolArg("-staking", false); + gArgs.SoftSetBoolArg("-staking", false); SelectParams(chainType); SeedInsecureRand(); if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN); @@ -163,6 +166,26 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); }); GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler); +////////////////////////////////////////////////////////////// qtum + dev::eth::NoProof::init(); + std::filesystem::path pathTemp = fs::temp_directory_path() / strprintf("test_qtum_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + std::filesystem::create_directories(pathTemp); + const dev::h256 hashDB(dev::sha3(dev::rlp(""))); + globalState = std::unique_ptr(new QtumState(dev::u256(0), QtumState::openDB(pathTemp.string(), hashDB, dev::WithExisting::Trust), pathTemp.string(), dev::eth::BaseState::Empty)); + dev::eth::ChainParams cp(chainparams.EVMGenesisInfo()); + cp.EIP150ForkBlock = 0xffffffffffffffff; + cp.EIP158ForkBlock = 0xffffffffffffffff; + cp.byzantiumForkBlock = 0xffffffffffffffff; + cp.constantinopleForkBlock = 0xffffffffffffffff; + cp.constantinopleFixForkBlock = 0xffffffffffffffff; + globalSealEngine = std::unique_ptr(cp.createSealEngine()); + globalState->populateFrom(cp.genesisState); + globalState->setRootUTXO(uintToh256(chainparams.GenesisBlock().hashUTXORoot)); + globalState->db().commit(); + globalState->dbUtxo().commit(); + pstorageresult.reset(new StorageResults(pathTemp.string())); +////////////////////////////////////////////////////////////// + m_node.fee_estimator = std::make_unique(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES); m_node.mempool = std::make_unique(MemPoolOptionsForTest(m_node)); @@ -206,6 +229,11 @@ ChainTestingSetup::~ChainTestingSetup() m_node.mempool.reset(); m_node.scheduler.reset(); m_node.chainman.reset(); + +/////////////////////////////////////////////// // qtum + delete globalState.release(); + globalSealEngine.reset(); +/////////////////////////////////////////////// } void ChainTestingSetup::LoadVerifyActivateChainstate() @@ -281,13 +309,14 @@ TestChain100Setup::TestChain100Setup( coinbaseKey.Set(vchKey.begin(), vchKey.end(), true); // Generate a 100-block chain: - this->mineBlocks(COINBASE_MATURITY); + int coinbaseMaturity = Params().GetConsensus().CoinbaseMaturity(0); + this->mineBlocks(coinbaseMaturity); { LOCK(::cs_main); assert( m_node.chainman->ActiveChain().Tip()->GetBlockHash().ToString() == - "571d80a9967ae599cec0448b0b0ba1cfb606f584d8069bd7166b86854ba7a191"); + "5ce9c22662191ba24b8d930e606446fce116a4c022e2660c846ae1a7d70708ec"); } } @@ -468,7 +497,7 @@ void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate) CBlock getBlock13b8a() { CBlock block; - CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION); + CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf9321b463e3b52f6201c0ad6c991be0485b6ef8c092e64583ffa655cc1b171fe85621b463e3b52f6201c0ad6c991be0485b6ef8c092e64583ffa655cc1b171fe8560000000000000000000000000000000000000000000000000000000000000000ffffffff000901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; return block; } diff --git a/src/validation.h b/src/validation.h index d4874e40b0..ef2d04b4b8 100644 --- a/src/validation.h +++ b/src/validation.h @@ -89,6 +89,13 @@ namespace util { class SignalInterrupt; } // namespace util +/** Minimum gas limit that is allowed in a transaction within a block - prevent various types of tx and mempool spam **/ +static const uint64_t MINIMUM_GAS_LIMIT = 10000; + +static const uint64_t MEMPOOL_MIN_GAS_LIMIT = 22000; + +static const uint64_t ADD_DELEGATION_MIN_GAS_LIMIT = 2200000; + /** Maximum number of dedicated script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 15; /** -par default (number of script-checking threads, 0 = auto) */ diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index c04e5eb277..8af226f00e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1168,6 +1168,33 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const } } + // Update unspent addresses + if(fUpdateAddressUnspentCache) + { + std::map insertScriptCache; + for (unsigned int i = 0; i < tx->vout.size(); i++) { + isminetype mine = IsMine(tx->vout[i]); + COutPoint prevout = COutPoint(hash, i); + if (!(IsSpent(prevout)) && mine != ISMINE_NO && + !IsLockedCoin(prevout) && (tx->vout[i].nValue > 0) && + // Check if the staking coin is dust + tx->vout[i].nValue >= m_staker_min_utxo_size) + { + // Get the script data for the coin + const CScriptCache& scriptCache = GetScriptCache(prevout, tx->vout[i].scriptPubKey, &insertScriptCache); + + // Check that the script is not a contract script + if(scriptCache.contract || !scriptCache.keyIdOk) + continue; + + if(mapAddressUnspentCache.find(scriptCache.keyId) == mapAddressUnspentCache.end()) + { + mapAddressUnspentCache[scriptCache.keyId] = true; + } + } + } + } + //// debug print WalletLogPrintf("AddToWallet %s %s%s %s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""), TxStateString(state)); @@ -1560,7 +1587,7 @@ void CWallet::blockDisconnected(const interfaces::BlockInfo& block) int disconnect_height = block.height; for (const CTransactionRef& ptx : Assert(block.data)->vtx) { - SyncTransaction(ptx, TxStateInactive{}); + SyncTransaction(ptx, TxStateInactive{false, ptx->IsCoinStake()}); for (const CTxIn& tx_in : ptx->vin) { // No other wallet transactions conflicted with this transaction @@ -2162,6 +2189,44 @@ void MaybeResendWalletTxs(WalletContext& context) * @{ */ +const CScriptCache& CWallet::GetScriptCache(const COutPoint& prevout, const CScript& scriptPubKey, std::map* _insertScriptCache) const +{ + auto it = prevoutScriptCache.find(prevout); + if(it == prevoutScriptCache.end()) + { + std::map& insertScriptCache = _insertScriptCache == nullptr ? prevoutScriptCache : *_insertScriptCache; + if((int32_t)insertScriptCache.size() > m_staker_max_utxo_script_cache) + { + insertScriptCache.clear(); + } + + // The script check for utxo is expensive operations, so cache the data for further use + CScriptCache scriptCache; + scriptCache.contract = scriptPubKey.HasOpCall() || scriptPubKey.HasOpCreate(); + if(!scriptCache.contract) + { + scriptCache.keyId = ToKeyID(ExtractPublicKeyHash(scriptPubKey, &(scriptCache.keyIdOk))); + if(scriptCache.keyIdOk) + { + std::unique_ptr provider = GetSolvingProvider(scriptPubKey); + if(provider) + { + auto inferred = InferDescriptor(scriptPubKey, *provider); + scriptCache.solvable = inferred ? inferred->IsSolvable() : false; + } + else + { + scriptCache.solvable = false; + } + } + } + insertScriptCache[prevout] = scriptCache; + return insertScriptCache[prevout]; + } + + return it->second; +} + bool CWallet::HasAddressStakeScripts(const uint160& keyId, std::map* _insertAddressStake) const { auto it = addressStakeCache.find(keyId); @@ -2492,6 +2557,28 @@ bool CWallet::GetDelegationStaker(const uint160& keyid, Delegation& delegation) return true; } +const CWalletTx* CWallet::GetCoinSuperStaker(const std::set >& setCoins, const PKHash& superStaker, COutPoint& prevout, CAmount& nValueRet) +{ + for(const std::pair &pcoin : setCoins) + { + CAmount nValue = pcoin.first->tx->vout[pcoin.second].nValue; + if(nValue < DEFAULT_STAKING_MIN_UTXO_VALUE) + continue; + + CScript scriptPubKey = pcoin.first->tx->vout[pcoin.second].scriptPubKey; + bool OK = false; + PKHash pkhash = ExtractPublicKeyHash(scriptPubKey, &OK); + if(OK && pkhash == superStaker) + { + nValueRet = nValue; + prevout = COutPoint(pcoin.first->GetHash(), pcoin.second); + return pcoin.first; + } + } + + return 0; +} + bool CWallet::CanSuperStake(const std::set >& setCoins, const std::vector& setDelegateCoins) const { bool canSuperStake = false; @@ -5236,6 +5323,75 @@ bool CWallet::GetSuperStaker(CSuperStakerInfo &info, const uint160 &stakerAddres void CWallet::GetStakerAddressBalance(const PKHash &staker, CAmount &balance, CAmount &stake, CAmount& weight) const { + AssertLockHeld(cs_wallet); + + balance = 0; + stake = 0; + weight = 0; + int nHeight = GetLastBlockHeight() + 1; + int coinbaseMaturity = Params().GetConsensus().CoinbaseMaturity(nHeight); + std::map immatureStakes = chain().getImmatureStakes(); + for (auto& entry : mapWallet) + { + const uint256& wtxid = entry.first; + const CWalletTx* pcoin = &entry.second; + int nDepth = GetTxDepthInMainChain(*pcoin); + + if (nDepth < 1) + continue; + + bool fHasProofOfDelegation = false; + if (auto* conf = pcoin->state()) { + fHasProofOfDelegation = conf->has_delegation; + } + + bool isImature = GetTxBlocksToMaturity(*pcoin) == 0; + for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) + { + bool OK = false; + PKHash keyId = ExtractPublicKeyHash(pcoin->tx->vout[i].scriptPubKey, &OK); + if(OK && keyId == staker) + { + COutPoint prevout = COutPoint(wtxid, i); + isminetype mine = IsMine(pcoin->tx->vout[i]); + if (!(IsSpent(prevout)) && mine != ISMINE_NO && + !IsLockedCoin(prevout) && (pcoin->tx->vout[i].nValue > 0)) + { + CAmount nValue = pcoin->tx->vout[i].nValue; + if(isImature) + { + balance += nValue; + if(nDepth >= coinbaseMaturity && nValue >= DEFAULT_STAKING_MIN_UTXO_VALUE) + { + if(immatureStakes.find(prevout) == immatureStakes.end()) + { + weight += nValue; + } + } + } + else if(pcoin->IsCoinStake() && fHasProofOfDelegation) + { + stake += nValue; + } + } + } + } + } +} + +void CWallet::updateHaveCoinSuperStaker(const std::set > &setCoins) +{ + LOCK(cs_wallet); + m_have_coin_superstaker.clear(); + + COutPoint prevout; + CAmount nValueRet = 0; + for (const auto& entry : mapSuperStaker) { + if(GetCoinSuperStaker(setCoins, PKHash(entry.second.stakerAddress), prevout, nValueRet)) + { + m_have_coin_superstaker[entry.second.stakerAddress] = true; + } + } } void CWallet::CleanCoinStake() diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 243ad9de10..17baf5650e 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -745,6 +745,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati bool GetSenderDest(const CTransaction& tx, CTxDestination& txSenderDest, bool sign=true) const; bool GetHDKeyPath(const CTxDestination& dest, std::string& hdkeypath) const; bool GetDelegationStaker(const uint160& keyid, Delegation& delegation); + const CWalletTx* GetCoinSuperStaker(const std::set >& setCoins, const PKHash& superStaker, COutPoint& prevout, CAmount& nValueRet); + const CScriptCache& GetScriptCache(const COutPoint& prevout, const CScript& scriptPubKey, std::map* insertScriptCache = nullptr) const; bool HasAddressStakeScripts(const uint160& keyId, std::map* insertAddressStake = nullptr) const; void RefreshAddressStakeCache(); bool GetSuperStaker(CSuperStakerInfo &info, const uint160& stakerAddress) const; @@ -1226,6 +1228,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati void updateDelegationsStaker(const std::map& delegations_staker); void updateDelegationsWeight(const std::map& delegations_weight); + void updateHaveCoinSuperStaker(const std::set >& setCoins); std::map m_delegations_staker; std::map m_delegations_weight; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index cae67e411b..91597a1e0d 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -632,15 +632,15 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, } // Extract the index and internal from the path - // Path string is m/0'/k'/i' - // Path vector is [0', k', i'] (but as ints OR'd with the hardened bit + // Path string is m/88'/k'/i' + // Path vector is [88', k', i'] (but as ints OR'd with the hardened bit // k == 0 for external, 1 for internal. i is the index if (path.size() != 3) { strErr = "Error reading wallet database: keymeta found with unexpected path"; return DBErrors::NONCRITICAL_ERROR; } - if (path[0] != 0x80000000) { - strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000) for the element at index 0", path[0]); + if (path[0] != 0x80000058) { + strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000058) for the element at index 0", path[0]); return DBErrors::NONCRITICAL_ERROR; } if (path[1] != 0x80000000 && path[1] != (1 | 0x80000000)) {