diff --git a/.gitignore b/.gitignore index 4ed4f7a1..83d75fd9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,9 +9,16 @@ src/multichain-cli src/multichain-util src/multichaind src/multichaind-cold +src/multichain-cli-wdebug +src/multichain-util-wdebug +src/multichaind-wdebug +src/multichaind-cold-wdebug src/test/test_bitcoin src/qt/test/test_bitcoin-qt +local/* +openssl* + # autoreconf Makefile.in aclocal.m4 diff --git a/V8_mac.md b/V8_mac.md index 34115b12..c5ce21c8 100644 --- a/V8_mac.md +++ b/V8_mac.md @@ -6,7 +6,7 @@ MultiChain uses V8 version 6.8, and requires at least 4 GB of RAM to build in a ## Clone Google's depot_tools -Google's [depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools) are used by the Google build system to manage Git checkouts. +Google's [depot_tools](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up) are used by the Google build system to manage Git checkouts. git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git cd depot_tools @@ -38,12 +38,12 @@ The selected release of the V8 sources requires relaxing two compiler checks to - Open the file `build/config/compiler/BUILD.gn` in your favorite editor. -- Locate the folllowing lines (currently at **1464**): +- Locate the following lines (currently at **1469**): if (is_clang) { cflags += [ -- Add the following two lines to **the end** of the block and save the file: +- Add the following two lines to **the end of the block** and save the file: "-Wno-defaulted-function-deleted", "-Wno-null-pointer-arithmetic", @@ -55,7 +55,11 @@ Build the V8 libraries: Create an additional library embedding the V8 initial snapshot blobs: - brew install python + brew install python@2 pip install pathlib2 cd $RELEASE python $MULTICHAIN_HOME/depends/v8_data_lib.py + +### Note + +The environment variable `$MULTICHAIN_HOME` should point to the parent of the V8 build folder (see [mac.md](mac.md) for details). diff --git a/configure.ac b/configure.ac index 703d4ca1..9f5ebec3 100644 --- a/configure.ac +++ b/configure.ac @@ -81,6 +81,12 @@ AC_ARG_ENABLE([wallet], [enable_wallet=$enableval], [enable_wallet=yes]) +AC_ARG_ENABLE([enterprise], + [AS_HELP_STRING([--enable-enterprise], + [enable enterprise (default is no)])], + [enable_enterprise=$enableval], + [enable_enterprise=no]) + AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], [enable UPNP (default is yes if libminiupnpc is found)])], @@ -757,6 +763,17 @@ else AC_MSG_RESULT(no) fi +dnl enable enterprise +AC_MSG_CHECKING([if enterprise should be enabled]) +if test x$enable_enterprise != xno; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED([ENABLE_ENTERPRISE],[1],[Define to 1 to enable enterprise functions]) + +else + AC_MSG_RESULT(no) +fi + + dnl enable upnp support AC_MSG_CHECKING([whether to build with support for UPnP]) if test x$have_miniupnpc = xno; then @@ -847,6 +864,7 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) +AM_CONDITIONAL([ENABLE_ENTERPRISE],[test x$enable_enterprise = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes]) diff --git a/mac.md b/mac.md index fd77eaa7..efd999c4 100644 --- a/mac.md +++ b/mac.md @@ -1,14 +1,42 @@ # Mac Build Notes (on MacOS Sierra) -## Install dependencies +## Install XCode and XCode command line tools + +- Test if XCode command line tools are installed: + + xcode-select -p + +- If the command does not print the location of the XCode command-line tools successfully: + + xcode-select --install + +- Select XCode locatioh: + + sudo xcode-select -s + +- Install brew (follow instructions on [brew.sh](https://brew.sh/)) + +## Clone MultiChain +Install git from git-scm, then -Install XCode and XCode command line tools + git clone https://github.com/MultiChain/multichain.git + + +## Prepare to download or build V8 + + cd multichain + set MULTICHAIN_HOME=$(pwd) + mkdir v8build + cd v8build -Install git from git-scm + +You can use pre-built headers and binaries of Google's V8 JavaScript engine by downloading and expanding [macos-v8.tar.gz](https://github.com/MultiChain/multichain-binaries/raw/master/macos-v8.tar.gz) in the current directory. If, on the other hand, you prefer to build the V8 component yourself, please follow the instructions in [V8_mac.md](/V8_mac.md/). -Install brew (follow instructions on brew.sh) +## Install dependencies - brew install autoconf automake berkeley-db4 libtool boost@1.57 openssl pkg-config rename python@2 + brew install autoconf automake berkeley-db4 libtool boost@1.57 pkg-config rename python@2 nasm + export LDFLAGS=-L/usr/local/opt/openssl/lib + export CPPFLAGS=-I/usr/local/opt/openssl/include brew link boost@1.57 --force If another Boost version was already installed, then do this: @@ -16,10 +44,6 @@ If another Boost version was already installed, then do this: brew uninstall boost brew install boost@1.57 brew link boost@1.57 --force - -The following command may be necessary if XCode was not used yet: - - sudo xcode-select -s /Applications/Xcode.app ## Prepare for static linking @@ -45,26 +69,13 @@ The default brew cookbook for berkeley-db and boost builds static libraries, but brew edit openssl - In 'def configure_args' change 'shared' to 'no-shared' + In 'def install' => 'args =' change 'shared' to 'no-shared' brew install openssl --force + ## Compile MultiChain for Mac (64-bit) @@ -80,7 +91,7 @@ You can use pre-built headers and binaries of Google's V8 JavaScript engine by d rename -e 's/.dylib.hidden/.dylib/' /usr/local/opt/openssl/lib/*.dylib.hidden brew edit openssl -In 'def configure_args' change 'no-shared' to 'shared' +In 'def install' => 'args =' change 'no-shared' to 'shared' ## Notes diff --git a/src/Makefile.am b/src/Makefile.am index 582b638a..38a6b745 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,7 @@ FwalDIST_SUBDIRS = secp256k1 AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) CXXFLAGS += -std=c++0x +CPPFLAGS += -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-result -DBOOST_SYSTEM_NO_DEPRECATED=1 if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include @@ -24,6 +25,8 @@ BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPP BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +LIBBITCOIN_ENTERPRISE=libbitcoin_enterprise.a +LIBBITCOIN_COMMUNITY=libbitcoin_community.a LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a @@ -49,6 +52,8 @@ EXTRA_LIBRARIES = \ libbitcoin_util.a \ libbitcoin_common.a \ univalue/libbitcoin_univalue.a \ + libbitcoin_enterprise.a \ + libbitcoin_community.a \ libbitcoin_server.a \ libbitcoin_cli.a if ENABLE_WALLET @@ -125,6 +130,7 @@ BITCOIN_CORE_H = \ utils/utilparse.h \ rpc/rpcclient.h \ rpc/rpcprotocol.h \ + rpc/rpcasio.h \ rpc/rpcutils.h \ rpc/rpcwallet.h \ rpc/rpcserver.h \ @@ -175,6 +181,22 @@ obj/build.h: FORCE $(abs_top_srcdir) libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h +libbitcoin_community_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_community_a_SOURCES = \ + community/community.cpp \ + wallet/db.cpp \ + wallet/dbwrap_com.cpp + +if ENABLE_ENTERPRISE +include entMakefile.am +else +libbitcoin_enterprise_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_enterprise_a_SOURCES = \ + community/community.cpp \ + wallet/db.cpp \ + wallet/dbwrap_com.cpp +endif + # server: shared between bitcoind and bitcoin-qt libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) libbitcoin_server_a_SOURCES = \ @@ -224,8 +246,6 @@ libbitcoin_server_a_SOURCES = \ libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ wallet/dbflat.cpp \ - wallet/db.cpp \ - wallet/dbwrap_com.cpp \ wallet/crypter.cpp \ rpc/rpcdump.cpp \ rpc/rpcwallet.cpp \ @@ -262,6 +282,9 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha1.h \ crypto/ripemd160.h + + + # multichain library multichain_libbitcoin_multichain_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) multichain_libbitcoin_multichain_a_SOURCES = \ @@ -460,6 +483,7 @@ multichaind_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_ENTERPRISE) \ $(LIBBITCOIN_MULTICHAIN) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ @@ -503,6 +527,7 @@ multichaind_cold_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_COMMUNITY) \ $(LIBBITCOIN_MULTICHAIN) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ diff --git a/src/chainparams/buildgenesis.cpp b/src/chainparams/buildgenesis.cpp index 35411022..2f9551f1 100644 --- a/src/chainparams/buildgenesis.cpp +++ b/src/chainparams/buildgenesis.cpp @@ -93,7 +93,12 @@ int mc_MultichainParams::Build(const unsigned char* pubkey, int pubkey_size) uint32_t nBits,timestamp; int i; const unsigned char *ptr; - const unsigned char *pubkey_hash=(unsigned char *)Hash160(pubkey,pubkey+pubkey_size).begin(); +// const unsigned char *pubkey_hash=(unsigned char *)Hash160(pubkey,pubkey+pubkey_size).begin(); + + unsigned char pubkey_hash[20]; + uint160 pkhash=Hash160(pubkey,pubkey+pubkey_size); + memcpy(pubkey_hash,&pkhash,20); + size_t elem_size; const unsigned char *elem; int root_stream_name_size; @@ -271,7 +276,7 @@ int mc_MultichainParams::Build(const unsigned char* pubkey, int pubkey_size) { return err; } - + CalculateHash(hash); diff --git a/src/chainparams/params.cpp b/src/chainparams/params.cpp index bf932df6..f162ab47 100644 --- a/src/chainparams/params.cpp +++ b/src/chainparams/params.cpp @@ -2245,4 +2245,32 @@ int mc_Features::LicenseTokens() return ret; } +int mc_Features::FixedJSDateFunctions() +{ + int ret=0; + if(mc_gState->m_NetworkParams->IsProtocolMultichain() == 0) + { + return 0; + } + int protocol=mc_gState->m_NetworkParams->ProtocolVersion(); + + if(protocol) + { + if(protocol >= 20008) + { + ret=1; + } + else + { + if(Filters() == 0) + { + ret=1; + } + } + } + + return ret; +} + + diff --git a/src/chainparams/state.h b/src/chainparams/state.h index a3bdb54a..a7a806cc 100644 --- a/src/chainparams/state.h +++ b/src/chainparams/state.h @@ -65,6 +65,7 @@ typedef struct mc_Params char** m_Arguments; int m_FirstArgumentType; char m_DataDirNetSpecific[MC_DCT_DB_MAX_PATH]; + char m_LogDirNetSpecific[MC_DCT_DB_MAX_PATH]; char m_DataDir[MC_DCT_DB_MAX_PATH]; mc_Params() @@ -153,6 +154,7 @@ typedef struct mc_Features int NonceInMinerSignature(); int ImplicitConnectPermission(); int LicenseTokens(); + int FixedJSDateFunctions(); } mc_Features; typedef struct mc_BlockHeaderInfo diff --git a/src/community/community.cpp b/src/community/community.cpp index defe4e0b..d07be507 100644 --- a/src/community/community.cpp +++ b/src/community/community.cpp @@ -21,6 +21,36 @@ int mc_EnterpriseFeatures::Initialize(const char *name,uint32_t mode) return MC_ERR_NOERROR; } +int mc_EnterpriseFeatures::STR_CreateSubscription(mc_TxEntity *entity,const std::string parameters) +{ + return MC_ERR_FOUND; +} + +int mc_EnterpriseFeatures::STR_IsIndexSkipped(mc_TxImport *import,mc_TxEntity *parent_entity,mc_TxEntity *entity) +{ + return 0; +} + +int mc_EnterpriseFeatures::STR_IsOutOfSync(mc_TxEntity *entity) +{ + return 0; +} + +int mc_EnterpriseFeatures::STR_SetSyncFlag(mc_TxEntity *entity,bool confirm) +{ + return MC_ERR_NOERROR; +} + +int mc_EnterpriseFeatures::STR_GetSubscriptions(mc_Buffer *subscriptions) +{ + return MC_ERR_NOERROR; +} + +int mc_EnterpriseFeatures::STR_PutSubscriptions(mc_Buffer *subscriptions) +{ + return MC_ERR_NOERROR; +} + int mc_EnterpriseFeatures::WLT_CreateSubscription(mc_TxEntity *entity,uint32_t retrieve,uint32_t indexes,uint32_t *rescan_mode) { *rescan_mode=0; @@ -57,9 +87,14 @@ string mc_EnterpriseFeatures::ENT_Edition() return "Community"; } +int mc_EnterpriseFeatures::ENT_EditionNumeric() +{ + return 0; +} + int mc_EnterpriseFeatures::ENT_MinWalletDatVersion() { - return 1; + return 2; } void mc_EnterpriseFeatures::ENT_RPCVerifyEdition() @@ -67,12 +102,17 @@ void mc_EnterpriseFeatures::ENT_RPCVerifyEdition() throw JSONRPCError(RPC_NOT_SUPPORTED, "This feature is available only in Enterprise edition of MultiChain, please call \"help enterprise\" for details"); } -void mc_EnterpriseFeatures::LIC_RPCVerifyFeature(uint32_t feature) +std::string mc_EnterpriseFeatures::ENT_TextConstant(const char* name) +{ + return ""; +} + +void mc_EnterpriseFeatures::LIC_RPCVerifyFeature(uint64_t feature) { throw JSONRPCError(RPC_NOT_SUPPORTED, "This feature is available only in Enterprise edition of MultiChain, please call \"help enterprise\" for details"); } -bool mc_EnterpriseFeatures::LIC_VerifyFeature(uint32_t feature,std::string& reason) +bool mc_EnterpriseFeatures::LIC_VerifyFeature(uint64_t feature,std::string& reason) { reason="Not available in Community efition"; return false; diff --git a/src/community/community.h b/src/community/community.h index 868498f1..7c6aab8b 100644 --- a/src/community/community.h +++ b/src/community/community.h @@ -5,11 +5,15 @@ #define MULTICHAIN_COMMUNITY_H #include "multichain/multichain.h" -#include "wallet/wallettxdb.h" +#include "wallet/wallettxs.h" #include "rpc/rpcutils.h" #define MC_EFT_NONE 0x0000000000000000 #define MC_EFT_LICENSE_TRANSFER 0x0000000000000002 +#define MC_EFT_STREAM_CONDITIONAL_INDEXING 0x0000000000000100 +#define MC_EFT_STREAM_MANUAL_RETRIEVAL 0x0000000000000200 +#define MC_EFT_STREAM_READ_PERMISSIONS 0x0000000000001000 +#define MC_EFT_ALL 0xFFFFFFFFFFFFFFFF typedef struct mc_EnterpriseFeatures @@ -32,6 +36,13 @@ typedef struct mc_EnterpriseFeatures const char *name, // Chain name uint32_t mode); // Unused + int STR_CreateSubscription(mc_TxEntity *entity,const std::string parameters); + int STR_IsIndexSkipped(mc_TxImport *import,mc_TxEntity *parent_entity,mc_TxEntity *entity); + int STR_IsOutOfSync(mc_TxEntity *entity); + int STR_SetSyncFlag(mc_TxEntity *entity,bool confirm); + int STR_GetSubscriptions(mc_Buffer *subscriptions); + int STR_PutSubscriptions(mc_Buffer *subscriptions); + int WLT_CreateSubscription(mc_TxEntity *entity,uint32_t retrieve,uint32_t indexes,uint32_t *rescan_mode); int WLT_DeleteSubscription(mc_TxEntity *entity,uint32_t rescan_mode); int WLT_StartImport(); @@ -40,11 +51,13 @@ typedef struct mc_EnterpriseFeatures int WLT_NoRetrieve(mc_TxEntity *entity); std::string ENT_Edition(); + int ENT_EditionNumeric(); int ENT_MinWalletDatVersion(); void ENT_RPCVerifyEdition(); + std::string ENT_TextConstant(const char* name); - void LIC_RPCVerifyFeature(uint32_t feature); - bool LIC_VerifyFeature(uint32_t feature,std::string& reason); + void LIC_RPCVerifyFeature(uint64_t feature); + bool LIC_VerifyFeature(uint64_t feature,std::string& reason); // bool LIC_VerifyConfirmation(uint160 address,void *confirmation, size_t size,std::string& reason); // string LIC_LicenseName(void *confirmation, size_t size); int LIC_VerifyLicenses(); diff --git a/src/core/init-cold.cpp b/src/core/init-cold.cpp index 0a12fb05..7c5ecc96 100644 --- a/src/core/init-cold.cpp +++ b/src/core/init-cold.cpp @@ -147,9 +147,9 @@ void Shutdown_Cold() if (pwalletMain) bitdbwrap.Flush(true); #endif -#ifndef WIN32 +//#ifndef WIN32 boost::filesystem::remove(GetPidFile()); -#endif +//#endif #ifdef ENABLE_WALLET delete pwalletMain; pwalletMain = NULL; @@ -226,6 +226,7 @@ std::string HelpMessage_Cold() strUsage += ".\n"; strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n"; + strUsage += " -logdir " + _("Send trace/debug info to specified directory") + "\n"; strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n"; strUsage += "\n" + _("RPC server options:") + "\n"; @@ -393,9 +394,9 @@ bool AppInit2_Cold(boost::thread_group& threadGroup,int OutputPipe) #endif /* MCHN END */ -#ifndef WIN32 - CreatePidFile(GetPidFile(), getpid()); -#endif +//#ifndef WIN32 + CreatePidFile(GetPidFile(), __US_GetPID()); +//#endif if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); @@ -608,33 +609,27 @@ bool AppInit2_Cold(boost::thread_group& threadGroup,int OutputPipe) return InitError(_(seed_error.c_str())); } - bool wallet_mode_valid=false; wallet_mode=GetArg("-walletdbversion",0); if(wallet_mode == 0) { mc_gState->m_WalletMode=MC_WMD_AUTO; - wallet_mode_valid=true; } if(wallet_mode == 3) { mc_gState->m_WalletMode=MC_WMD_TXS | MC_WMD_ADDRESS_TXS | MC_WMD_FLAT_DAT_FILE; - wallet_mode_valid=true; } if(wallet_mode == 2) { mc_gState->m_WalletMode=MC_WMD_TXS | MC_WMD_ADDRESS_TXS; - wallet_mode_valid=true; } if(wallet_mode == 1) { mc_gState->m_WalletMode=MC_WMD_NONE; - wallet_mode_valid=true; zap_wallet_txs=false; } if(wallet_mode == -1) { mc_gState->m_WalletMode=MC_WMD_TXS | MC_WMD_ADDRESS_TXS | MC_WMD_MAP_TXS; - wallet_mode_valid=true; zap_wallet_txs=false; } diff --git a/src/core/init.cpp b/src/core/init.cpp index 371c9e66..eedef9c5 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -29,6 +29,7 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" #endif +#include "community/community.h" /* MCHN START */ @@ -69,6 +70,7 @@ mc_WalletTxs* pwalletTxsMain = NULL; mc_RelayManager* pRelayManager = NULL; mc_FilterEngine* pFilterEngine = NULL; mc_MultiChainFilterEngine* pMultiChainFilterEngine = NULL; + bool fFeeEstimatesInitialized = false; extern int JSON_DOUBLE_DECIMAL_DIGITS; @@ -92,6 +94,11 @@ enum BindFlags { static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; CClientUIInterface uiInterface; +//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB +static const CAmount nHighTransactionFeeWarning = 0.01 * COIN; +//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) +static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning; + ////////////////////////////////////////////////////////////////////////////// // // Shutdown @@ -210,14 +217,15 @@ void Shutdown() if (pwalletMain) bitdbwrap.Flush(true); #endif -#ifndef WIN32 +//#ifndef WIN32 boost::filesystem::remove(GetPidFile()); -#endif +//#endif UnregisterAllValidationInterfaces(); #ifdef ENABLE_WALLET delete pwalletMain; pwalletMain = NULL; /* MCHN START */ + if(pwalletTxsMain) { delete pwalletTxsMain; @@ -234,6 +242,7 @@ void Shutdown() delete pMultiChainFilterEngine; pMultiChainFilterEngine=NULL; } + if(pFilterEngine) { @@ -455,6 +464,7 @@ std::string HelpMessage(HelpMessageMode mode) } strUsage += " -minrelaytxfee= " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())) + "\n"; strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n"; + strUsage += " -logdir " + _("Send trace/debug info to specified directory") + "\n"; if (GetBoolArg("-help-debug", false)) { strUsage += " -printpriority " + strprintf(_("Log transaction priority and fee per kB when mining blocks (default: %u)"), 0) + "\n"; @@ -930,9 +940,9 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) #endif /* MCHN END */ -#ifndef WIN32 - CreatePidFile(GetPidFile(), getpid()); -#endif +//#ifndef WIN32 + CreatePidFile(GetPidFile(), __US_GetPID()); +//#endif if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); @@ -1002,6 +1012,17 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) boost::filesystem::path pathWallet=GetDataDir() / "wallet"; LogPrintf("Wallet file exists. WalletDBVersion: %d.\n", currentwalletdatversion); + if(currentwalletdatversion != 1) + { + if(pEF->ENT_MinWalletDatVersion() > currentwalletdatversion) + { + return InitError(strprintf("Wallet version %d is not supported in this edition of MultiChain.\n" + "To upgrade to version %d, run MultiChain Offline Daemon: \n" + "multichaind-cold %s -datadir=%s -walletdbversion=3\n" + "and restart multichaind or use Community Edition.\n", + currentwalletdatversion,pEF->ENT_MinWalletDatVersion(), mc_gState->m_NetworkParams->Name(),mc_gState->m_Params->DataDir(0,0))); + } + } if( (currentwalletdatversion == 3) && (GetArg("-walletdbversion",MC_TDB_WALLET_VERSION) != 3) ) { return InitError(_("Wallet downgrade is not allowed")); @@ -1033,6 +1054,11 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) else { currentwalletdatversion=wallet_mode; + if(pEF->ENT_MinWalletDatVersion() > currentwalletdatversion) + { + return InitError(strprintf("Wallet version %d is not supported in this edition of MultiChain.\n",currentwalletdatversion)); + } + LogPrintf("Wallet file doesn't exist. New file will be created with version %d.\n", currentwalletdatversion); } switch(currentwalletdatversion) @@ -1209,6 +1235,7 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) bool zap_wallet_txs=false; bool new_wallet_txs=false; seed_node=mc_gState->GetSeedNode(); + mc_Buffer *rescan_subscriptions=NULL; int seed_attempt=1; if(init_privkey.size()) @@ -1444,34 +1471,28 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) string strBurnAddress=BurnAddress(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)); // Caching burn address LogPrint("mchn","mchn: Burn address: %s\n",strBurnAddress.c_str()); - bool wallet_mode_valid=false; wallet_mode=GetArg("-walletdbversion",0); if(wallet_mode == 0) { mc_gState->m_WalletMode=MC_WMD_AUTO; - wallet_mode_valid=true; } if(wallet_mode == 3) { mc_gState->m_WalletMode=MC_WMD_TXS | MC_WMD_ADDRESS_TXS | MC_WMD_FLAT_DAT_FILE; - wallet_mode_valid=true; } if(wallet_mode == 2) { mc_gState->m_WalletMode=MC_WMD_TXS | MC_WMD_ADDRESS_TXS; - wallet_mode_valid=true; } if(wallet_mode == 1) { mc_gState->m_WalletMode=MC_WMD_NONE; - wallet_mode_valid=true; zap_wallet_txs=false; } if(wallet_mode == -1) { mc_gState->m_WalletMode=MC_WMD_TXS | MC_WMD_ADDRESS_TXS | MC_WMD_MAP_TXS; - wallet_mode_valid=true; zap_wallet_txs=false; } @@ -1500,6 +1521,16 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) } } __US_Sleep(1000); + rescan_subscriptions=new mc_Buffer; + mc_EnterpriseFeatures* pRescanEF = new mc_EnterpriseFeatures; + if(pRescanEF->Initialize(mc_gState->m_Params->NetworkName(),0)) + { + fprintf(stderr,"\nError: Cannot intitialize Enterprise features. Exiting...\n\n"); + return false; + } + pRescanEF->STR_GetSubscriptions(rescan_subscriptions); + pRescanEF->Destroy(); + delete pRescanEF; } pwalletTxsMain->Destroy(); delete pwalletTxsMain; @@ -2365,6 +2396,18 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) } } + + if(pEF->Initialize(mc_gState->m_Params->NetworkName(),0)) + { + fprintf(stderr,"\nError: Cannot intitialize Enterprise features. Exiting...\n\n"); + return false; + } + if(rescan_subscriptions) + { + pEF->STR_PutSubscriptions(rescan_subscriptions); + delete rescan_subscriptions; + } + // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET @@ -2563,6 +2606,7 @@ bool AppInit2(boost::thread_group& threadGroup,int OutputPipe) return InitError(strErrors.str()); pRelayManager->Initialize(); + // RandAddSeedPerfmon(); diff --git a/src/core/init.h b/src/core/init.h index 7c1abe24..6458b904 100644 --- a/src/core/init.h +++ b/src/core/init.h @@ -14,6 +14,7 @@ struct mc_WalletTxs; struct mc_RelayManager; struct mc_FilterEngine; struct mc_MultiChainFilterEngine; +struct mc_EnterpriseFeatures; namespace boost { @@ -25,6 +26,7 @@ extern mc_WalletTxs* pwalletTxsMain; extern mc_RelayManager* pRelayManager; extern mc_FilterEngine* pFilterEngine; extern mc_MultiChainFilterEngine* pMultiChainFilterEngine; +extern mc_EnterpriseFeatures* pEF; void StartShutdown(); diff --git a/src/core/main.cpp b/src/core/main.cpp index 6981476d..cde8c33e 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -537,93 +537,6 @@ int MultichainNode_ApplyUpgrades(int current_height) } -int MultichainNode_ApplyUpgrades_Old(int current_height) -{ - mc_EntityDetails entity; - mc_Buffer *permissions; - permissions=NULL; - map map_sorted; - - int OriginalProtocolVersion=(int)mc_gState->m_NetworkParams->GetInt64Param("protocolversion"); - int CurrentProtocolVersion=mc_gState->m_NetworkParams->ProtocolVersion();//mc_gState->m_ProtocolVersionToUpgrade; - int NewProtocolVersion=OriginalProtocolVersion; - int version; - - permissions=mc_gState->m_Permissions->GetUpgradeList(NULL,NULL); - - for(int i=0;iGetCount();i++) - { - mc_PermissionDetails *plsRow; - plsRow=(mc_PermissionDetails *)(permissions->GetRow(i)); - if(plsRow->m_Type == MC_PTP_UPGRADE) - { - map_sorted.insert(std::make_pair(plsRow->m_LastRow,i)); - } - } - - BOOST_FOREACH(PAIRTYPE(const uint64_t, int)& item, map_sorted) -// for(int i=0;iGetCount();i++) - { - int i=item.second; - mc_PermissionDetails *plsRow; - plsRow=(mc_PermissionDetails *)(permissions->GetRow(i)); - if(plsRow->m_Type == MC_PTP_UPGRADE) - { - if(plsRow->m_BlockFrom < plsRow->m_BlockTo) - { - if(mc_gState->m_Assets->FindEntityByShortTxID(&entity,plsRow->m_Address)) - { - int applied_height=entity.UpgradeStartBlock(); - if((int)plsRow->m_BlockReceived > applied_height) - { - applied_height=plsRow->m_BlockReceived; - } - if(current_height >=applied_height) - { - version=entity.UpgradeProtocolVersion(); - if(version >= mc_gState->MinProtocolDowngradeVersion()) - { - if((NewProtocolVersion < mc_gState->MinProtocolForbiddenDowngradeVersion()) || (version >= NewProtocolVersion)) - { - NewProtocolVersion=version; - } - } - } - } - } - } - } - - mc_gState->m_Permissions->FreePermissionList(permissions); - mc_gState->m_ProtocolVersionToUpgrade=NewProtocolVersion; - - if(mc_gState->m_ProtocolVersionToUpgrade != CurrentProtocolVersion) - { - LogPrintf("New protocol upgrade version: %d (was %d)\n",mc_gState->m_ProtocolVersionToUpgrade,CurrentProtocolVersion); -// if(mc_gState->m_ProtocolVersionToUpgrade > mc_gState->GetProtocolVersion()) - if( (mc_gState->m_ProtocolVersionToUpgrade > 0) && (mc_gState->IsSupported(mc_gState->m_ProtocolVersionToUpgrade) == 0) ) - { - LogPrintf("NODE SHOULD BE UPGRADED FROM %d TO %d\n",mc_gState->GetProtocolVersion(),mc_gState->m_ProtocolVersionToUpgrade); - } - else - { - if(mc_gState->m_ProtocolVersionToUpgrade != mc_gState->m_NetworkParams->ProtocolVersion()) - { - LogPrintf("NODE IS UPGRADED FROM %d TO %d\n",mc_gState->m_NetworkParams->ProtocolVersion(),mc_gState->m_ProtocolVersionToUpgrade); - mc_gState->m_NetworkParams->m_ProtocolVersion=mc_gState->m_ProtocolVersionToUpgrade;// UPGRADE CODE HERE - mc_gState->m_NetworkParams->SetGlobals(); - SetMultiChainParams(); - } - } - } - else - { - mc_gState->m_ProtocolVersionToUpgrade=0; - } - - return MC_ERR_NOERROR; -} - void MultichainNode_UpdateBlockByHeightList(CBlockIndex *pindex) { if(pindex->nHeight < 0) diff --git a/src/entMakefile.am b/src/entMakefile.am new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/entMakefile.am @@ -0,0 +1 @@ + diff --git a/src/filters/filter_win.cpp b/src/filters/filter_win.cpp index 656efabc..42cdb29a 100644 --- a/src/filters/filter_win.cpp +++ b/src/filters/filter_win.cpp @@ -115,7 +115,7 @@ int mc_FilterEngine::CreateFilter(std::string script, std::string main_name, std auto v8filter = static_cast(filter->m_Impl); char result[RESULT_SIZE]; retval = V8Engine_CreateFilter(v8engine, script.c_str(), main_name.c_str(), callbackNames, n_callbackNames, - v8filter, mc_gState->m_Features->FilterLimitedMathSet(), result); + v8filter, mc_gState->m_Features->FilterLimitedMathSet(), mc_gState->m_Features->FixedJSDateFunctions(), result); delete [] callbackNames; if (fDebug) LogPrint("v8filter", "v8filter: retval=%d result=%s\n", retval, result); diff --git a/src/miner/miner.cpp b/src/miner/miner.cpp index 885a514a..8dd036bd 100644 --- a/src/miner/miner.cpp +++ b/src/miner/miner.cpp @@ -654,8 +654,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,CWallet *pwallet,CP { if(canMine) { - const unsigned char *pubkey_hash=(unsigned char *)Hash160(ppubkey->begin(),ppubkey->end()).begin(); - *canMine=mc_gState->m_Permissions->CanMine(NULL,pubkey_hash); +// const unsigned char *pubkey_hash=(unsigned char *)Hash160(ppubkey->begin(),ppubkey->end()).begin(); +// *canMine=mc_gState->m_Permissions->CanMine(NULL,pubkey_hash); + uint160 pubkey_hash=Hash160(ppubkey->begin(),ppubkey->end()); + *canMine=mc_gState->m_Permissions->CanMine(NULL,&pubkey_hash); if((*canMine & MC_PTP_MINE) == 0) { if(prevCanMine & MC_PTP_MINE) @@ -826,7 +828,11 @@ CBlockTemplate* CreateNewBlockWithDefaultKey(CWallet *pwallet,int *canMine,const return NULL; } - const unsigned char *pubkey_hash=(unsigned char *)Hash160(pubkey.begin(),pubkey.end()).begin(); +// const unsigned char *pubkey_hash=(unsigned char *)Hash160(pubkey.begin(),pubkey.end()).begin(); + + unsigned char pubkey_hash[20]; + uint160 pkhash=Hash160(pubkey.begin(),pubkey.end()); + memcpy(pubkey_hash,&pkhash,20); CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << vector(pubkey_hash, pubkey_hash + 20) << OP_EQUALVERIFY << OP_CHECKSIG; @@ -1454,7 +1460,10 @@ void static BitcoinMiner(CWallet *pwallet) if(canMine & MC_PTP_MINE) { - const unsigned char *pubkey_hash=(unsigned char *)Hash160(kMiner.begin(),kMiner.end()).begin(); +// const unsigned char *pubkey_hash=(unsigned char *)Hash160(kMiner.begin(),kMiner.end()).begin(); + unsigned char pubkey_hash[20]; + uint160 pkhash=Hash160(kMiner.begin(),kMiner.end()); + memcpy(pubkey_hash,&pkhash,20); CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << vector(pubkey_hash, pubkey_hash + 20) << OP_EQUALVERIFY << OP_CHECKSIG; canMine=prevCanMine; auto_ptr pblocktemplate(CreateNewBlock(scriptPubKey,pwallet,&kMiner,&canMine,&pindexPrev)); diff --git a/src/multichain/multichain-cli.cpp b/src/multichain/multichain-cli.cpp index e6e67c6b..be84f1e1 100644 --- a/src/multichain/multichain-cli.cpp +++ b/src/multichain/multichain-cli.cpp @@ -7,6 +7,7 @@ #include "version/clientversion.h" #include "rpc/rpcclient.h" #include "rpc/rpcprotocol.h" +#include "rpc/rpcasio.h" #include "utils/util.h" #include "utils/utilstrencodings.h" @@ -411,6 +412,19 @@ int main(int argc, char* argv[]) boost::filesystem::create_directories(path_cli_log); path_cli_log /= string(mc_gState->m_Params->NetworkName() + string(".log")); + if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") + { + string strMethod=strprintf("%s",mc_gState->m_Params->NetworkName()); + if(HaveAPIWithThisName(strMethod)) + { + fprintf(stdout,"\nMultiChain %s RPC client\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str()); + printf("ERROR: Couldn't read configuration file for blockchain %s. \n\n" + "Be sure include the blockchain name before the command name, e.g.:\n\n" + "multichain-cli chain1 %s\n\n",mc_gState->m_Params->NetworkName(),mc_gState->m_Params->NetworkName()); + return EXIT_FAILURE; + } + } + #ifndef WIN32 if(mc_gState->m_Params->m_NumArguments == 1) // Interactive mode { @@ -517,7 +531,7 @@ int main(int argc, char* argv[]) return 0; } #endif - + int ret = EXIT_FAILURE; try { mc_SaveCliCommandToLog(path_cli_log.string().c_str(), argc, argv); diff --git a/src/multichain/multichaind-cold.cpp b/src/multichain/multichaind-cold.cpp index 60337143..1f3e8a94 100644 --- a/src/multichain/multichaind-cold.cpp +++ b/src/multichain/multichaind-cold.cpp @@ -19,6 +19,7 @@ #include "multichain/multichain.h" #include "chainparams/globals.h" static bool fDaemon; +mc_EnterpriseFeatures* pEF = NULL; void DebugPrintClose(); std::string HelpMessage_Cold(); @@ -54,6 +55,19 @@ bool mc_DoesParentDataDirExist() return true; } +bool mc_DoesParentLogDirExist() +{ + if (mapArgs.count("-logdir")) + { + boost::filesystem::path path=boost::filesystem::system_complete(mapArgs["-logdir"]); + if (!boost::filesystem::is_directory(path)) + { + return false; + } + } + return true; +} + ////////////////////////////////////////////////////////////////////////////// // // Start @@ -102,6 +116,12 @@ bool AppInit(int argc, char* argv[]) return false; } + if(!mc_DoesParentLogDirExist()) + { + fprintf(stderr,"\nError: Log directory %s needs to exist before calling multichaind-cold. Exiting...\n\n",mapArgs["-logdir"].c_str()); + return false; + } + mc_gState->m_Params->HasOption("-?"); diff --git a/src/multichain/multichaind.cpp b/src/multichain/multichaind.cpp index 96310f24..20771708 100644 --- a/src/multichain/multichaind.cpp +++ b/src/multichain/multichaind.cpp @@ -10,6 +10,7 @@ #include "ui/noui.h" #include "ui/ui_interface.h" #include "utils/util.h" +#include "community/community.h" #include @@ -20,6 +21,8 @@ #include "chainparams/globals.h" static bool fDaemon; +mc_EnterpriseFeatures* pEF = NULL; + void DebugPrintClose(); void DetectShutdownThread(boost::thread_group* threadGroup) @@ -51,6 +54,20 @@ bool mc_DoesParentDataDirExist() return true; } +bool mc_DoesParentLogDirExist() +{ + if (mapArgs.count("-logdir")) + { + boost::filesystem::path path=boost::filesystem::system_complete(mapArgs["-logdir"]); + if (!boost::filesystem::is_directory(path)) + { + return false; + } + } + return true; +} + + ////////////////////////////////////////////////////////////////////////////// // // Start @@ -90,15 +107,37 @@ bool AppInit(int argc, char* argv[]) return false; } } - + if(!mc_DoesParentDataDirExist()) { fprintf(stderr,"\nError: Data directory %s needs to exist before calling multichaind. Exiting...\n\n",mapArgs["-datadir"].c_str()); + delete mc_gState; return false; } + if(!mc_DoesParentLogDirExist()) + { + fprintf(stderr,"\nError: Log directory %s needs to exist before calling multichaind. Exiting...\n\n",mapArgs["-logdir"].c_str()); + return false; + } + + pEF=new mc_EnterpriseFeatures; +/* + if(pEF->Initialize(mc_gState->m_Params->NetworkName(),0)) + { + fprintf(stderr,"\nError: Data directory %s needs to exist before calling multichaind. Exiting...\n\n",mapArgs["-datadir"].c_str()); + delete mc_gState; + return false; + } +*/ + string edition=pEF->ENT_Edition(); + if(edition.size()) + { + edition=edition+" Edition, "; + } + mc_gState->m_Params->HasOption("-?"); @@ -108,7 +147,7 @@ bool AppInit(int argc, char* argv[]) mc_gState->m_Params->HasOption("-version") || (mc_gState->m_Params->NetworkName() == NULL)) { - fprintf(stdout,"\nMultiChain %s Daemon (protocol %s)\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str(),mc_SupportedProtocols().c_str()); + fprintf(stdout,"\nMultiChain %s Daemon (%sprotocol %s)\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str(),edition.c_str(),mc_SupportedProtocols().c_str()); std::string strUsage = ""; if (mc_gState->m_Params->HasOption("-version")) { @@ -124,13 +163,14 @@ bool AppInit(int argc, char* argv[]) fprintf(stdout, "%s", strUsage.c_str()); + delete pEF; delete mc_gState; return true; } if(!GetBoolArg("-shortoutput", false)) { - fprintf(stdout,"\nMultiChain %s Daemon (latest protocol %d)\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str(),mc_gState->GetProtocolVersion()); + fprintf(stdout,"\nMultiChain %s Daemon (%slatest protocol %d)\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str(),edition.c_str(),mc_gState->GetProtocolVersion()); } pipes[1]=STDOUT_FILENO; @@ -140,6 +180,7 @@ bool AppInit(int argc, char* argv[]) if (fDaemon) { + delete pEF; delete mc_gState; if(!GetBoolArg("-shortoutput", false)) @@ -196,6 +237,8 @@ bool AppInit(int argc, char* argv[]) mc_gState->m_Params->Parse(argc, argv, MC_ETP_DAEMON); mc_CheckDataDirInConfFile(); + + pEF=new mc_EnterpriseFeatures; } #endif @@ -206,6 +249,7 @@ bool AppInit(int argc, char* argv[]) if(err) { fprintf(stderr,"ERROR: Couldn't read parameter file for blockchain %s. Exiting...\n",mc_gState->m_Params->NetworkName()); + delete pEF; delete mc_gState; return false; } @@ -214,6 +258,7 @@ bool AppInit(int argc, char* argv[]) if(err) { fprintf(stderr,"ERROR: Couldn't read configuration file for blockchain %s. Please try upgrading MultiChain. Exiting...\n",mc_gState->m_Params->NetworkName()); + delete pEF; delete mc_gState; return false; } @@ -222,6 +267,7 @@ bool AppInit(int argc, char* argv[]) if(err) { fprintf(stderr,"ERROR: Couldn't validate parameter set for blockchain %s. Exiting...\n",mc_gState->m_Params->NetworkName()); + delete pEF; delete mc_gState; return false; } @@ -245,6 +291,7 @@ bool AppInit(int argc, char* argv[]) { fprintf(stderr,"\nERROR: Couldn't initialize permission database for blockchain %s. Probably multichaind for this blockchain is already running. Exiting...\n",mc_gState->m_Params->NetworkName()); } + delete pEF; delete mc_gState; return false; } @@ -260,6 +307,7 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr,"ERROR: The protocol version (%d) for blockchain %s has been deprecated and was last supported in MultiChain %s\n\n", protocol_version,mc_gState->m_Params->NetworkName(), mc_BuildDescription(-mc_gState->VersionInfo(protocol_version)).c_str()); + delete pEF; delete mc_gState; return false; } @@ -268,6 +316,7 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr,"ERROR: Parameter set for blockchain %s was generated by MultiChain running newer protocol version (%d)\n\n", mc_gState->m_Params->NetworkName(),protocol_version); fprintf(stderr,"Please upgrade MultiChain\n\n"); + delete pEF; delete mc_gState; return false; } @@ -297,6 +346,7 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr,"If you want to connect to existing blockchain please specify seed node:\n\n"); fprintf(stderr," multichaind %s@\n",mc_gState->m_Params->NetworkName()); fprintf(stderr," multichaind %s@:\n\n\n",mc_gState->m_Params->NetworkName()); + delete pEF; delete mc_gState; return false; } @@ -306,11 +356,13 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr," multichain-util create %s\n",mc_gState->m_Params->NetworkName()); fprintf(stderr," multichain-util clone %s\n",mc_gState->m_Params->NetworkName()); fprintf(stderr,"\nAnd rerun multichaind %s\n",mc_gState->m_Params->NetworkName()); + delete pEF; delete mc_gState; return false; case MC_PRM_STATUS_INVALID: fprintf(stderr,"ERROR: Parameter set for blockchain %s is invalid. You may generate new network using these parameters by running:\n\n",mc_gState->m_Params->NetworkName()); fprintf(stderr," multichain-util clone %s \n",mc_gState->m_Params->NetworkName()); + delete pEF; delete mc_gState; return false; case MC_PRM_STATUS_GENERATED: @@ -318,6 +370,7 @@ bool AppInit(int argc, char* argv[]) break; default: fprintf(stderr,"INTERNAL ERROR: Unknown parameter set status %d\n",mc_gState->m_NetworkParams->m_Status); + delete pEF; delete mc_gState; return false; break; @@ -399,6 +452,7 @@ bool AppInit(int argc, char* argv[]) } } + delete pEF; delete mc_gState; if(datadir_to_delete.size()) diff --git a/src/permissions/permission.cpp b/src/permissions/permission.cpp index abc3d480..8971839f 100644 --- a/src/permissions/permission.cpp +++ b/src/permissions/permission.cpp @@ -328,7 +328,7 @@ int mc_Permissions::Initialize(const char *name,int mode) m_Ledger->SetName(name); m_Database->SetName(name); - mc_GetFullFileName(name,"permissions",".log",MC_FOM_RELATIVE_TO_DATADIR,m_LogFileName); + mc_GetFullFileName(name,"permissions",".log",MC_FOM_RELATIVE_TO_LOGDIR | MC_FOM_CREATE_DIR,m_LogFileName); err=m_Database->Open(); @@ -1386,7 +1386,6 @@ int mc_Permissions::CanWrite(const void* lpEntity,const void* lpAddress) int mc_Permissions::FilterApproved(const void* lpEntity,const void* lpAddress) { int result; - mc_MempoolPermissionRow row; if(mc_gState->m_NetworkParams->IsProtocolMultichain() == 0) { diff --git a/src/protocol/multichaintx.cpp b/src/protocol/multichaintx.cpp index dde67155..ea484415 100644 --- a/src/protocol/multichaintx.cpp +++ b/src/protocol/multichaintx.cpp @@ -1322,9 +1322,7 @@ bool MultiChainTransaction_CheckLicenseTokenTransfer(const CTransaction& tx, string& reason) { bool token_transfer=false; - int err; mc_EntityDetails entity; - uint32_t script_type=MC_SCR_ASSET_SCRIPT_TYPE_TRANSFER; if(mc_gState->m_Features->LicenseTokens() == 0) { @@ -1632,7 +1630,6 @@ bool MultiChainTransaction_CheckLicenseTokenDetails(CMultiChainTxDetails *detail uint32_t offset,next_offset,param_value_start; unsigned int timestamp; size_t param_value_size; - bool is_open=false; size_t value_sizes[256]; int value_starts[256]; unsigned char code; @@ -2479,8 +2476,6 @@ bool MultiChainTransaction_VerifyNotFilteredRestrictions(const CTransaction& tx, CMultiChainTxDetails *details, // Tx details object string& reason) // Error message { - int change_count=0; - if(details->emergency_disapproval_output < 0) { return true; @@ -2531,7 +2526,7 @@ bool MultiChainTransaction_VerifyNotFilteredRestrictions(const CTransaction& tx, MultiChainTransaction_SetTmpOutputScript(tx.vout[vout].scriptPubKey); - if(vout == details->emergency_disapproval_output) + if((int)vout == details->emergency_disapproval_output) { if(mc_gState->m_TmpScript->GetNumElements() > 1) { diff --git a/src/rpc/rpcasio.h b/src/rpc/rpcasio.h new file mode 100644 index 00000000..05055f30 --- /dev/null +++ b/src/rpc/rpcasio.h @@ -0,0 +1,89 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Original code was distributed under the MIT software license. +// Copyright (c) 2014-2019 Coin Sciences Ltd +// MultiChain code distributed under the GPLv3 license, see COPYING file. + +#ifndef BITCOIN_RPCASIO_H +#define BITCOIN_RPCASIO_H + +#include +#include +#include +#include +#include + +#include +#include + +/** + * IOStream device that speaks SSL but can also speak non-SSL + */ +template +class SSLIOStreamDevice : public boost::iostreams::device { +public: + SSLIOStreamDevice(boost::asio::ssl::stream &streamIn, bool fUseSSLIn) : stream(streamIn) + { + fUseSSL = fUseSSLIn; + fNeedHandshake = fUseSSLIn; + } + + void handshake(boost::asio::ssl::stream_base::handshake_type role) + { + if (!fNeedHandshake) return; + fNeedHandshake = false; + stream.handshake(role); + } + std::streamsize read(char* s, std::streamsize n) + { + handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first + if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n)); + return stream.next_layer().read_some(boost::asio::buffer(s, n)); + } + std::streamsize write(const char* s, std::streamsize n) + { + handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first + if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n)); + return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n)); + } + bool connect(const std::string& server, const std::string& port) + { + using namespace boost::asio::ip; + tcp::resolver resolver(stream.get_io_service()); + tcp::resolver::iterator endpoint_iterator; +#if BOOST_VERSION >= 104300 + try { +#endif + // The default query (flags address_configured) tries IPv6 if + // non-localhost IPv6 configured, and IPv4 if non-localhost IPv4 + // configured. + tcp::resolver::query query(server.c_str(), port.c_str()); + endpoint_iterator = resolver.resolve(query); +#if BOOST_VERSION >= 104300 + } catch(boost::system::system_error &e) + { + // If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces) + tcp::resolver::query query(server.c_str(), port.c_str(), resolver_query_base::flags()); + endpoint_iterator = resolver.resolve(query); + } +#endif + boost::system::error_code error = boost::asio::error::host_not_found; + tcp::resolver::iterator end; + while (error && endpoint_iterator != end) + { + stream.lowest_layer().close(); + stream.lowest_layer().connect(*endpoint_iterator++, error); + } + if (error) + return false; + return true; + } + +private: + bool fNeedHandshake; + bool fUseSSL; + boost::asio::ssl::stream& stream; +}; + + +#endif // BITCOIN_RPCASIO_H diff --git a/src/rpc/rpcblockchain.cpp b/src/rpc/rpcblockchain.cpp index 3990526f..e9819000 100644 --- a/src/rpc/rpcblockchain.cpp +++ b/src/rpc/rpcblockchain.cpp @@ -552,7 +552,6 @@ Value getfiltertxinput(const Array& params, bool fHelp) // throw JSONRPCError(RPC_INVALID_PARAMS, "Wrong number of parameters"); int64_t vin = params[0].get_int64(); - int64_t n; if(pMultiChainFilterEngine->m_Vout >= 0) { diff --git a/src/rpc/rpcclient.cpp b/src/rpc/rpcclient.cpp index 341774b8..2efbfc95 100644 --- a/src/rpc/rpcclient.cpp +++ b/src/rpc/rpcclient.cpp @@ -23,6 +23,203 @@ class CRPCConvertParam int paramIdx; //! 0-based idx of param to convert }; +static const std::string vAPINames[] = +{ +"addmultisigaddress", +"addnode", +"addresses-all", +"appendbinarycache", +"appendrawchange", +"appendrawdata", +"appendrawexchange", +"appendrawmetadata", +"appendrawtransaction", +"approvefrom", +"backupwallet", +"clearmempool", +"combineunspent", +"completerawexchange", +"create", +"createbinarycache", +"createfrom", +"createkeypairs", +"createmultisig", +"createrawexchange", +"createrawsendfrom", +"createrawtransaction", +"data-all", +"data-with", +"debug", +"decoderawexchange", +"decoderawtransaction", +"decodescript", +"deletebinarycache", +"disablerawtransaction", +"dumpprivkey", +"dumpwallet", +"encryptwallet", +"estimatefee", +"estimatepriority", +"filters", +"getaccount", +"getaccountaddress", +"getaddednodeinfo", +"getaddressbalances", +"getaddresses", +"getaddressesbyaccount", +"getaddresstransaction", +"getassetbalances", +"getassetinfo", +"getassettransaction", +"getbalance", +"getbestblockhash", +"getblock", +"getblockchaininfo", +"getblockchainparams", +"getblockcount", +"getblockhash", +"getblocktemplate", +"getchaintips", +"getchunkqueueinfo", +"getchunkqueuetotals", +"getconnectioncount", +"getdifficulty", +"getfilterassetbalances", +"getfiltercode", +"getfilterstreamitem", +"getfiltertransaction", +"getfiltertxid", +"getfiltertxinput", +"getgenerate", +"gethashespersec", +"getinfo", +"getlastblockinfo", +"getmempoolinfo", +"getmininginfo", +"getmultibalances", +"getnettotals", +"getnetworkhashps", +"getnetworkinfo", +"getnewaddress", +"getpeerinfo", +"getrawchangeaddress", +"getrawmempool", +"getrawtransaction", +"getreceivedbyaccount", +"getreceivedbyaddress", +"getruntimeparams", +"getstreaminfo", +"getstreamitem", +"getstreamkeysummary", +"getstreampublishersummary", +"gettotalbalances", +"gettransaction", +"gettxout", +"gettxoutdata", +"gettxoutsetinfo", +"getunconfirmedbalance", +"getwalletinfo", +"getwallettransaction", +"grant", +"grantfrom", +"grantwithdata", +"grantwithdatafrom", +"grantwithmetadata", +"grantwithmetadatafrom", +"help", +"importaddress", +"importprivkey", +"importwallet", +"invalidateblock", +"issue", +"issuefrom", +"issuemore", +"issuemorefrom", +"keypoolrefill", +"listaccounts", +"listaddresses", +"listaddressgroupings", +"listaddresstransactions", +"listassets", +"listassettransactions", +"listblocks", +"listlockunspent", +"listpermissions", +"listreceivedbyaccount", +"listreceivedbyaddress", +"listsinceblock", +"liststreamblockitems", +"liststreamfilters", +"liststreamitems", +"liststreamkeyitems", +"liststreamkeys", +"liststreampublisheritems", +"liststreampublishers", +"liststreamqueryitems", +"liststreams", +"liststreamtxitems", +"listtransactions", +"listtxfilters", +"listunspent", +"listupgrades", +"listwallettransactions", +"lockunspent", +"move", +"pause", +"ping", +"preparelockunspent", +"preparelockunspentfrom", +"prioritisetransaction", +"publish", +"publishfrom", +"publishmulti", +"publishmultifrom", +"reconsiderblock", +"resendwallettransactions", +"resume", +"revoke", +"revokefrom", +"runstreamfilter", +"runtxfilter", +"send", +"sendasset", +"sendassetfrom", +"sendassettoaddress", +"sendfrom", +"sendfromaccount", +"sendfromaddress", +"sendmany", +"sendrawtransaction", +"sendtoaddress", +"sendwithdata", +"sendwithdatafrom", +"sendwithmetadata", +"sendwithmetadatafrom", +"setaccount", +"setfilterparam", +"setgenerate", +"setlastblock", +"setmocktime", +"setruntimeparam", +"settxfee", +"signmessage", +"signrawtransaction", +"stop", +"storechunk", +"submitblock", +"subscribe", +"teststreamfilter", +"testtxfilter", +"unsubscribe", +"validateaddress", +"verifychain", +"verifymessage", +"verifypermission", +"walletlock", +"walletpassphrase", +"walletpassphrasechange" +}; + static const CRPCConvertParam vRPCConvertParams[] = { { "stop", 0 }, @@ -201,6 +398,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "gettxoutdata", 1 }, { "gettxoutdata", 2 }, { "gettxoutdata", 3 }, + { "txouttobinarycache", 2 }, + { "txouttobinarycache", 3 }, + { "txouttobinarycache", 4 }, { "liststreamkeys", 1 }, { "liststreamkeys", 2 }, { "liststreamkeys", 3 }, @@ -310,6 +510,30 @@ class CRPCConvertTable } }; +class CRPCNameTable +{ +private: + std::set members; + +public: + CRPCNameTable(); + + bool found(const std::string& method) { + return (members.count(method) > 0); + } +}; + +CRPCNameTable::CRPCNameTable() +{ + const unsigned int n_elem = + (sizeof(vAPINames) / sizeof(vAPINames[0])); + + for (unsigned int i = 0; i < n_elem; i++) { + members.insert(vAPINames[i]); + } +} + + CRPCConvertTable::CRPCConvertTable() { const unsigned int n_elem = @@ -322,6 +546,7 @@ CRPCConvertTable::CRPCConvertTable() } static CRPCConvertTable rpcCvtTable; +static CRPCNameTable rpcNamTable; /* MCHN START */ @@ -400,6 +625,12 @@ CRPCConvertTableMayBeString::CRPCConvertTableMayBeString() static CRPCConvertTableMayBeString rpcCvtTableMayBeString; + +bool HaveAPIWithThisName(const std::string &strMethod) +{ + return rpcNamTable.found(strMethod); +} + /* MCHN END */ /** Convert strings to command-specific RPC representation */ diff --git a/src/rpc/rpcclient.h b/src/rpc/rpcclient.h index 32b1d6a9..9213854c 100644 --- a/src/rpc/rpcclient.h +++ b/src/rpc/rpcclient.h @@ -12,5 +12,6 @@ #include "json/json_spirit_writer_template.h" json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +bool HaveAPIWithThisName(const std::string &strMethod); #endif // BITCOIN_RPCCLIENT_H diff --git a/src/rpc/rpcdebug.cpp b/src/rpc/rpcdebug.cpp index 7b786088..a8c42cea 100644 --- a/src/rpc/rpcdebug.cpp +++ b/src/rpc/rpcdebug.cpp @@ -479,6 +479,9 @@ Value debug(const Array& params, bool fHelp) mc_ChunkCollector collector; bool res_found=false; + delay=1000; + attempts=10; + if(params[0].type() == str_type) { if(params[0].get_str() == "findaddress") diff --git a/src/rpc/rpchelp.cpp b/src/rpc/rpchelp.cpp index d1e9ed3e..fb5a5382 100644 --- a/src/rpc/rpchelp.cpp +++ b/src/rpc/rpchelp.cpp @@ -7,6 +7,7 @@ #include "core/main.h" #include "rpc/rpcserver.h" #include "rpc/rpcutils.h" +#include "community/community.h" std::string HelpRequiringPassphraseWrapper() { @@ -3552,7 +3553,7 @@ void mc_InitRPCHelpMap15() )); mapHelpStrings.insert(std::make_pair("subscribe", - "subscribe entity-identifier(s) ( rescan )\n" + "subscribe entity-identifier(s) ( rescan" + pEF->ENT_TextConstant("help-subscribe-parameters") + " )\n" "\nSubscribes to the stream.\n" "\nArguments:\n" "1. \"stream-identifier\" (string, required) Stream identifier - one of: create txid, stream reference, stream name.\n" @@ -3561,6 +3562,7 @@ void mc_InitRPCHelpMap15() " or\n" "1. entity-identifier(s) (array, optional) A json array of stream or asset identifiers \n" "2. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" + + pEF->ENT_TextConstant("help-subscribe-parameters-details") + "\nNote: This call can take minutes to complete if rescan is true.\n" "\nResult:\n" "\nExamples:\n" @@ -4636,6 +4638,24 @@ void mc_InitRPCHelpMap20() + HelpExampleRpc("publishmultifrom", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", \"test\", [{\"key\":\"hello world\",\"data\":\"48656C6C6F20576F726C64210A\"}]") )); + mapHelpStrings.insert(std::make_pair("txouttobinarycache", + "txouttobinarycache \"identifier\" \"txid\" vout ( count-bytes start-byte )\n" + "\nStores metadata of transaction output in binary cache.\n" + "\nArguments:\n" + "1. \"identifier\" (string, required) Binary cache item identifier\n" + "2. \"txid\" (string, required) The transaction id\n" + "3. vout (numeric, required) vout value\n" + "4. count-bytes (numeric, optional, default=INT_MAX) Number of bytes to return\n" + "5. start-byte (numeric, optional, default=0) start from specific byte \n" + "\nResult:\n" + "size (numeric) Size of the binary cache item\n" + "\nExamples:\n" + "\nView the data\n" + + HelpExampleCli("txouttobinarycache", "\"TjnVWwHYEg4\" \"txid\" 1") + + "\nAs a json rpc call\n" + + HelpExampleRpc("txouttobinarycache", "\"TjnVWwHYEg4\", \"txid\", 1") + )); + mapHelpStrings.insert(std::make_pair("AAAAAAA", "" )); diff --git a/src/rpc/rpclist.cpp b/src/rpc/rpclist.cpp index 226fc107..fa3f5caf 100644 --- a/src/rpc/rpclist.cpp +++ b/src/rpc/rpclist.cpp @@ -267,6 +267,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "liststreamkeys", &liststreamkeys, false, false, true }, { "wallet", "liststreampublishers", &liststreampublishers, false, false, true }, { "wallet", "gettxoutdata", &gettxoutdata, false, false, true }, + { "wallet", "txouttobinarycache", &txouttobinarycache, false, false, true }, { "wallet", "liststreamblockitems", &liststreamblockitems, false, false, false }, { "wallet", "getstreamkeysummary", &getstreamkeysummary, false, false, true }, { "wallet", "getstreampublishersummary", &getstreampublishersummary, false, false, true }, diff --git a/src/rpc/rpcprotocol.h b/src/rpc/rpcprotocol.h index 49247afc..044844a9 100644 --- a/src/rpc/rpcprotocol.h +++ b/src/rpc/rpcprotocol.h @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include "json/json_spirit_reader_template.h" #include "json/json_spirit_utils.h" @@ -101,75 +99,6 @@ enum RPCErrorCode }; -/** - * IOStream device that speaks SSL but can also speak non-SSL - */ -template -class SSLIOStreamDevice : public boost::iostreams::device { -public: - SSLIOStreamDevice(boost::asio::ssl::stream &streamIn, bool fUseSSLIn) : stream(streamIn) - { - fUseSSL = fUseSSLIn; - fNeedHandshake = fUseSSLIn; - } - - void handshake(boost::asio::ssl::stream_base::handshake_type role) - { - if (!fNeedHandshake) return; - fNeedHandshake = false; - stream.handshake(role); - } - std::streamsize read(char* s, std::streamsize n) - { - handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first - if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n)); - return stream.next_layer().read_some(boost::asio::buffer(s, n)); - } - std::streamsize write(const char* s, std::streamsize n) - { - handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first - if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n)); - return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n)); - } - bool connect(const std::string& server, const std::string& port) - { - using namespace boost::asio::ip; - tcp::resolver resolver(stream.get_io_service()); - tcp::resolver::iterator endpoint_iterator; -#if BOOST_VERSION >= 104300 - try { -#endif - // The default query (flags address_configured) tries IPv6 if - // non-localhost IPv6 configured, and IPv4 if non-localhost IPv4 - // configured. - tcp::resolver::query query(server.c_str(), port.c_str()); - endpoint_iterator = resolver.resolve(query); -#if BOOST_VERSION >= 104300 - } catch(boost::system::system_error &e) - { - // If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces) - tcp::resolver::query query(server.c_str(), port.c_str(), resolver_query_base::flags()); - endpoint_iterator = resolver.resolve(query); - } -#endif - boost::system::error_code error = boost::asio::error::host_not_found; - tcp::resolver::iterator end; - while (error && endpoint_iterator != end) - { - stream.lowest_layer().close(); - stream.lowest_layer().connect(*endpoint_iterator++, error); - } - if (error) - return false; - return true; - } - -private: - bool fNeedHandshake; - bool fUseSSL; - boost::asio::ssl::stream& stream; -}; - std::string HTTPPost(const std::string& strMsg, const std::map& mapRequestHeaders); std::string HTTPError(int nStatus, bool keepalive, bool headerOnly = false); diff --git a/src/rpc/rpcrawtransaction.cpp b/src/rpc/rpcrawtransaction.cpp index 74ddc6d3..12f5bba7 100644 --- a/src/rpc/rpcrawtransaction.cpp +++ b/src/rpc/rpcrawtransaction.cpp @@ -161,6 +161,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) int chunk_count; int64_t total_chunk_size,out_size; uint32_t retrieve_status; + mc_EntityDetails entity; Array aFormatMetaData; Array aFullFormatMetaData; @@ -320,7 +321,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) if( (mc_GetABRefType(ptr) != MC_AST_ASSET_REF_TYPE_SPECIAL) && (mc_GetABRefType(ptr) != MC_AST_ASSET_REF_TYPE_GENESIS) ) { - mc_EntityDetails entity; + entity.Zero(); if(mc_gState->m_Assets->FindEntityByFullRef(&entity,ptr)) { is_genesis=false; @@ -462,21 +463,21 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) if(is_issuemore) { issue.push_back(Pair("type", "issuemore")); - mc_EntityDetails genesis_entity; + entity.Zero(); unsigned char *ptr; uint256 genesis_hash; - if(mc_gState->m_Assets->FindEntityByShortTxID(&genesis_entity,short_txid)) + if(mc_gState->m_Assets->FindEntityByShortTxID(&entity,short_txid)) { - ptr=(unsigned char *)genesis_entity.GetName(); + ptr=(unsigned char *)entity.GetName(); if(ptr && strlen((char*)ptr)) { issue.push_back(Pair("name", string((char*)ptr))); } - genesis_hash=*(uint256*)genesis_entity.GetTxID(); + genesis_hash=*(uint256*)entity.GetTxID(); issue.push_back(Pair("issuetxid", genesis_hash.GetHex())); - ptr=(unsigned char *)genesis_entity.GetRef(); + ptr=(unsigned char *)entity.GetRef(); string assetref=""; - if(genesis_entity.IsUnconfirmedGenesis()) + if(entity.IsUnconfirmedGenesis()) { Value null_value; issue.push_back(Pair("assetref",null_value)); @@ -504,7 +505,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) { uint256 txid=tx.GetHash(); - mc_EntityDetails entity; mc_EntityDetails *lpEntity=NULL; entity.Zero(); if(mc_gState->m_Assets->FindEntityByTxID(&entity,(unsigned char*)&txid) == 0) diff --git a/src/rpc/rpcserver.cpp b/src/rpc/rpcserver.cpp index c925ac00..828dd49d 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -5,6 +5,7 @@ // MultiChain code distributed under the GPLv3 license, see COPYING file. #include "rpc/rpcserver.h" +#include "rpc/rpcasio.h" #include "structs/base58.h" #include "core/init.h" @@ -48,6 +49,10 @@ static boost::asio::io_service::work *rpc_dummy_work = NULL; static std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from static std::vector< boost::shared_ptr > rpc_acceptors; +//! Convert boost::asio address to CNetAddr +extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address); + + string JSONRPCRequestForLog(const string& strMethod, const Array& params, const Value& id) { Object request; @@ -834,9 +839,21 @@ void StartRPCThreads(string& strError) } rpc_worker_group = new boost::thread_group(); + + +#ifdef MAC_OSX + boost::thread::attributes attrs; + attrs.set_stack_size(8*1024*1024); + + for (int i = 0; i < GetArg("-rpcthreads", 4); i++) + { + boost::thread *lpThread=new thread(attrs,boost::bind(&asio::io_service::run, rpc_io_service)); + rpc_worker_group->add_thread(lpThread); + } +#else for (int i = 0; i < GetArg("-rpcthreads", 4); i++) rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); - +#endif fRPCRunning = true; if(strError.size()) diff --git a/src/rpc/rpcserver.h b/src/rpc/rpcserver.h index 94b8e9ea..c44504d2 100644 --- a/src/rpc/rpcserver.h +++ b/src/rpc/rpcserver.h @@ -77,8 +77,6 @@ void RPCTypeCheck(const json_spirit::Object& o, */ void RPCRunLater(const std::string& name, boost::function func, int64_t nSeconds); -//! Convert boost::asio address to CNetAddr -extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address); typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); @@ -281,6 +279,7 @@ extern json_spirit::Value liststreampublisheritems(const json_spirit::Array& par extern json_spirit::Value liststreamkeys(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value liststreampublishers(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxoutdata(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value txouttobinarycache(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value listblocks(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value liststreamblockitems(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getstreamkeysummary(const json_spirit::Array& params, bool fHelp); diff --git a/src/rpc/rpcstreams.cpp b/src/rpc/rpcstreams.cpp index 6a41e77a..917fcd1c 100644 --- a/src/rpc/rpcstreams.cpp +++ b/src/rpc/rpcstreams.cpp @@ -9,6 +9,7 @@ #include "json/json_spirit_ubjson.h" #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" +#include "community/community.h" #define MC_QPR_MAX_UNCHECKED_TX_LIST_SIZE 1048576 #define MC_QPR_MAX_MERGED_TX_LIST_SIZE 1024 @@ -682,7 +683,7 @@ Value publishmultifrom(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Items should be array"); } - if(params[2].get_array().size() > MCP_MAX_STD_OP_RETURN_COUNT) + if((int)params[2].get_array().size() > MCP_MAX_STD_OP_RETURN_COUNT) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Number of items exceeds %d (max-std-op-returns-count)",MCP_MAX_STD_OP_RETURN_COUNT)); } @@ -814,7 +815,7 @@ Value publishmultifrom(const Array& params, bool fHelp) } CTxOut txout; - uint256 hash=deepest_coin.GetHashAndTxOut(txout); + deepest_coin.GetHashAndTxOut(txout); if (!ExtractDestination(txout.scriptPubKey, out_address)) { @@ -1054,7 +1055,7 @@ Value publishfrom(const Array& params, bool fHelp) Value subscribe(const Array& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > ((pEF->ENT_EditionNumeric() == 0) ? 2 : 3)) throw runtime_error("Help message not found\n"); if((mc_gState->m_WalletMode & MC_WMD_TXS) == 0) @@ -1064,9 +1065,22 @@ Value subscribe(const Array& params, bool fHelp) // Whether to perform rescan after import bool fRescan = true; + string indexes="all"; + if (params.size() > 1) - fRescan = params[1].get_bool(); + { + if(params[1].type() == bool_type) + { + fRescan = params[1].get_bool(); + } + } + if (params.size() > 2) + { + pEF->ENT_RPCVerifyEdition(); + indexes=params[2].get_str(); + } + vector inputEntities; vector inputStrings; if(params[0].type() == str_type) @@ -1111,6 +1125,11 @@ Value subscribe(const Array& params, bool fHelp) entity.m_EntityType=MC_TET_STREAM_PUBLISHER | MC_TET_TIMERECEIVED; pwalletTxsMain->AddEntity(&entity,MC_EFL_NOT_IN_SYNC); fNewFound=true; + } + entity.m_EntityType=MC_TET_STREAM | MC_TET_CHAINPOS; + if(pEF->STR_CreateSubscription(&entity,indexes) != MC_ERR_FOUND) + { + fNewFound=true; } } @@ -1562,6 +1581,10 @@ void getSubKeyEntityFromKey(string str,mc_TxEntityStat entStat,mc_TxEntity *enti mc_GetCompoundHash160(&stream_subkey_hash,entStat.m_Entity.m_EntityID,&key_string_hash); memcpy(entity->m_EntityID,&stream_subkey_hash,MC_TDB_ENTITY_ID_SIZE); entity->m_EntityType=entStat.m_Entity.m_EntityType | MC_TET_SUBKEY; + if(pEF->STR_IsIndexSkipped(NULL,&(entStat.m_Entity),entity)) + { + CheckWalletError(MC_ERR_NOT_ALLOWED); + } } void getSubKeyEntityFromPublisher(string str,mc_TxEntityStat entStat,mc_TxEntity *entity) @@ -1597,6 +1620,10 @@ void getSubKeyEntityFromPublisher(string str,mc_TxEntityStat entStat,mc_TxEntity memcpy(entity->m_EntityID,&stream_subkey_hash,MC_TDB_ENTITY_ID_SIZE); entity->m_EntityType=entStat.m_Entity.m_EntityType | MC_TET_SUBKEY; + if(pEF->STR_IsIndexSkipped(NULL,&(entStat.m_Entity),entity)) + { + CheckWalletError(MC_ERR_NOT_ALLOWED); + } } Value getstreamsummary(const Array& params, bool fPublisher) diff --git a/src/rpc/rpcutils.cpp b/src/rpc/rpcutils.cpp index 134e5e81..f585308b 100644 --- a/src/rpc/rpcutils.cpp +++ b/src/rpc/rpcutils.cpp @@ -173,6 +173,9 @@ void CheckWalletError(int err) case MC_ERR_NOT_SUPPORTED: throw JSONRPCError(RPC_NOT_SUPPORTED, "This feature is not supported in this build"); break; + case MC_ERR_NOT_ALLOWED: + throw JSONRPCError(RPC_NOT_SUPPORTED, "The index required for this API is not built for this subscription."); + break; case MC_ERR_INTERNAL_ERROR: throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal wallet error"); break; @@ -699,15 +702,15 @@ Object FilterEntry(const unsigned char *txid,uint32_t output_level,uint32_t filt for(int i=0;i<(int)value_size/MC_AST_SHORT_TXID_SIZE;i++) { mc_EntityDetails relevant_entity; - Object asset_entry; +// Object asset_entry; if(mc_gState->m_Assets->FindEntityByShortTxID(&relevant_entity,ptr+i*MC_AST_SHORT_TXID_SIZE)) { switch(relevant_entity.GetEntityType()) { case MC_ENT_TYPE_ASSET: - asset_entry=AssetEntry(relevant_entity.GetTxID(),-1,0x00); - asset_entry.push_back(Pair("type", "asset")); - entities.push_back(asset_entry); + entities.push_back(AssetEntry(relevant_entity.GetTxID(),-1,0x0104)); +// asset_entry.push_back(Pair("type", "asset")); +// entities.push_back(asset_entry); break; default: entities.push_back(StreamEntry(relevant_entity.GetTxID(),0x03)); @@ -1187,7 +1190,7 @@ int mc_IsUTF8(const unsigned char *elem,size_t elem_size) return 1; } -const unsigned char *GetChunkDataInRange(int64_t *out_size,unsigned char* hashes,int chunk_count,int64_t start,int64_t count) +const unsigned char *GetChunkDataInRange(int64_t *out_size,unsigned char* hashes,int chunk_count,int64_t start,int64_t count,int fHan) { mc_ChunkDBRow chunk_def; int size,shift,chunk; @@ -1215,8 +1218,7 @@ const unsigned char *GetChunkDataInRange(int64_t *out_size,unsigned char* hashes if(size > MAX_CHUNK_SIZE) { return NULL; - } - + } ptr+=shift; if(pwalletTxsMain->m_ChunkDB->GetChunkDef(&chunk_def,ptr,NULL,NULL,-1) == MC_ERR_NOERROR) @@ -1237,7 +1239,21 @@ const unsigned char *GetChunkDataInRange(int64_t *out_size,unsigned char* hashes elem=pwalletTxsMain->m_ChunkDB->GetChunk(&chunk_def,0,-1,&elem_size); if(elem) { - mc_gState->m_TmpBuffers->m_RpcChunkScript1->SetData(elem+read_from,read_size); + if(fHan) + { + if(read_size) + { + if(write(fHan,elem+read_from,read_size) != read_size) + { + return NULL; + } + } + } + else + { + mc_gState->m_TmpBuffers->m_RpcChunkScript1->SetData(elem+read_from,read_size); + } + *out_size+=read_size; } } @@ -1745,12 +1761,18 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev // 0x0020 issuers // 0x0040 put given quantity into qty field, even negative // 0x0080 put issueqty into qty field +// 0x0100 skip all quantities and add "type":"asset| Object entry; mc_EntityDetails entity; - mc_EntityDetails genesis_entity; + mc_EntityDetails sec_entity; + mc_EntityDetails *genesis_entity; + mc_EntityDetails *followon; mc_TxEntityStat entStat; unsigned char *ptr; + genesis_entity=&sec_entity; + followon=&sec_entity; + if(txid == NULL) { entry.push_back(Pair("assetref", "")); @@ -1763,16 +1785,22 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev if(mc_gState->m_Assets->FindEntityByTxID(&entity,txid)) { + genesis_entity->Zero(); if(entity.IsFollowOn()) { - mc_gState->m_Assets->FindEntityByFollowOn(&genesis_entity,txid); + mc_gState->m_Assets->FindEntityByFollowOn(genesis_entity,txid); } else { - memcpy(&genesis_entity,&entity,sizeof(mc_EntityDetails)); + memcpy(genesis_entity,&entity,sizeof(mc_EntityDetails)); } - ptr=(unsigned char *)genesis_entity.GetName(); + if(output_level & 0x100) + { + entry.push_back(Pair("type", "asset")); + } + + ptr=(unsigned char *)genesis_entity->GetName(); if(ptr && strlen((char*)ptr)) { entry.push_back(Pair("name", string((char*)ptr))); @@ -1781,9 +1809,9 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev { entry.push_back(Pair("issuetxid", hash.GetHex())); } - ptr=(unsigned char *)genesis_entity.GetRef(); + ptr=(unsigned char *)genesis_entity->GetRef(); string assetref=""; - if(genesis_entity.IsUnconfirmedGenesis()) + if(genesis_entity->IsUnconfirmedGenesis()) { Value null_value; entry.push_back(Pair("assetref",null_value)); @@ -1798,6 +1826,9 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev entry.push_back(Pair("assetref", assetref)); } + entStat.Zero(); + memcpy(&entStat,genesis_entity->GetShortRef(),mc_gState->m_NetworkParams->m_AssetRefSize); + size_t value_size; int64_t offset,new_offset; int64_t raw_output; @@ -1808,8 +1839,8 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev uint32_t permissions; ptr=entity.GetScript(); - multiple=genesis_entity.GetAssetMultiple(); - permissions=genesis_entity.Permissions(); + multiple=genesis_entity->GetAssetMultiple(); + permissions=genesis_entity->Permissions(); units= 1./(double)multiple; if(output_level & 0x0002) { @@ -1880,26 +1911,27 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev for(int i=followons->GetCount()-1;i>=0;i--) { Object issue; - mc_EntityDetails followon; - if(mc_gState->m_Assets->FindEntityByTxID(&followon,followons->GetRow(i))) +// mc_EntityDetails followon; + followon->Zero(); + if(mc_gState->m_Assets->FindEntityByTxID(followon,followons->GetRow(i))) { - qty=followon.GetQuantity(); + qty=followon->GetQuantity(); total+=qty; if(output_level & 0x0020) { - issue.push_back(Pair("txid", ((uint256*)(followon.GetTxID()))->ToString().c_str())); + issue.push_back(Pair("txid", ((uint256*)(followon->GetTxID()))->ToString().c_str())); issue.push_back(Pair("qty", (double)qty*units)); issue.push_back(Pair("raw", qty)); Object followon_fields; Array followon_issuers; - vfields=mc_ExtractDetailsJSONObject(&followon); - ptr=followon.GetScript(); + vfields=mc_ExtractDetailsJSONObject(followon); + ptr=followon->GetScript(); offset=0; while(offset>=0) { - new_offset=followon.NextParam(offset,&value_offset,&value_size); + new_offset=followon->NextParam(offset,&value_offset,&value_size); if(value_offset > 0) { if(ptr[offset]) @@ -1956,26 +1988,29 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev } raw_output=quantity; - if(output_level & 0x0080) + if( (output_level & 0x0100) == 0) { - raw_output=entity.GetQuantity(); - entry.push_back(Pair("qty", (double)raw_output*units)); - entry.push_back(Pair("raw", raw_output)); - } - else - { - if( (raw_output < 0) && ( (output_level & 0x0040) == 0) ) + if(output_level & 0x0080) { - raw_output=total; - entry.push_back(Pair("issueqty", (double)raw_output*units)); - entry.push_back(Pair("issueraw", raw_output)); + raw_output=entity.GetQuantity(); + entry.push_back(Pair("qty", (double)raw_output*units)); + entry.push_back(Pair("raw", raw_output)); } else { - entry.push_back(Pair("qty", (double)raw_output*units)); - if(output_level & 0x0001) + if( (raw_output < 0) && ( (output_level & 0x0040) == 0) ) { - entry.push_back(Pair("raw", raw_output)); + raw_output=total; + entry.push_back(Pair("issueqty", (double)raw_output*units)); + entry.push_back(Pair("issueraw", raw_output)); + } + else + { + entry.push_back(Pair("qty", (double)raw_output*units)); + if(output_level & 0x0001) + { + entry.push_back(Pair("raw", raw_output)); + } } } } @@ -1983,8 +2018,6 @@ Object AssetEntry(const unsigned char *txid,int64_t quantity,uint32_t output_lev if( ((output_level & 0x0008) != 0) && ((mc_gState->m_WalletMode & MC_WMD_TXS) != 0) && (pMultiChainFilterEngine->m_TxID == 0) ) { - entStat.Zero(); - memcpy(&entStat,genesis_entity.GetShortRef(),mc_gState->m_NetworkParams->m_AssetRefSize); entStat.m_Entity.m_EntityType=MC_TET_ASSET | MC_TET_CHAINPOS; if(pwalletTxsMain->FindEntity(&entStat)) { diff --git a/src/rpc/rpcutils.h b/src/rpc/rpcutils.h index 870c328f..db013c35 100644 --- a/src/rpc/rpcutils.h +++ b/src/rpc/rpcutils.h @@ -112,7 +112,7 @@ Array PermissionEntries(const CTxOut& txout,mc_Script *lpScript,bool fLong); Object StreamEntry(const unsigned char *txid,uint32_t output_level); Object StreamEntry(const unsigned char *txid,uint32_t output_level,mc_EntityDetails *raw_entity); Object UpgradeEntry(const unsigned char *txid); -const unsigned char *GetChunkDataInRange(int64_t *out_size,unsigned char* hashes,int chunk_count,int64_t start,int64_t count); +const unsigned char *GetChunkDataInRange(int64_t *out_size,unsigned char* hashes,int chunk_count,int64_t start,int64_t count,int fHan); uint32_t GetFormattedData(mc_Script *lpScript,const unsigned char **elem,int64_t *out_size,unsigned char* hashes,int chunk_count,int64_t total_size); Value OpReturnEntry(const unsigned char *elem,size_t elem_size,uint256 txid, int vout); Value OpReturnFormatEntry(const unsigned char *elem,int64_t elem_size,uint256 txid, int vout, uint32_t format, string *format_text_out,uint32_t status); diff --git a/src/rpc/rpcwallet.cpp b/src/rpc/rpcwallet.cpp index eb519817..2ea0c44e 100644 --- a/src/rpc/rpcwallet.cpp +++ b/src/rpc/rpcwallet.cpp @@ -594,13 +594,8 @@ Value storechunk(const Array& params, bool fHelp) - - -Value gettxoutdata(const Array& params, bool fHelp) +Value txoutdata_operation(const Array& params,int fHan) { - if (fHelp || params.size() < 2 || params.size() > 4) // MCHN - throw runtime_error("Help message not found\n"); - uint256 hash(params[0].get_str()); int n = params[1].get_int(); @@ -648,7 +643,7 @@ Value gettxoutdata(const Array& params, bool fHelp) uint32_t format; unsigned char *chunk_hashes; - int chunk_count; + int chunk_count=0; int64_t total_chunk_size,out_size; uint32_t retrieve_status; size_t elem_size; @@ -720,7 +715,6 @@ Value gettxoutdata(const Array& params, bool fHelp) start=paramtoint64(params[3],false,0,"Invalid start"); } - if(start < 0) { start=out_size+start; @@ -741,6 +735,10 @@ Value gettxoutdata(const Array& params, bool fHelp) if( (format == MC_SCR_DATA_FORMAT_UBJSON) || (format == MC_SCR_DATA_FORMAT_UTF8) ) { + if(fHan) + { + throw JSONRPCError(RPC_NOT_SUPPORTED, "This API is not supported for text and JSON data"); + } if(start != 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start, must be 0 for text and JSON data"); @@ -750,16 +748,41 @@ Value gettxoutdata(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid count, must include all text or JSON data"); } } + + if(fHan) + { + if(chunk_count > 1) + { + if(elem == NULL) + { + elem=GetChunkDataInRange(&out_size,chunk_hashes,chunk_count,start,count,fHan); + if(elem == NULL) + { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't retrieve data for this output"); + } + return count; + } + } + else + { + if(write(fHan,elem+start,count) != count) + { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Cannot store binary cache item"); + } + return count; + } + } + if(count > 0x4000000) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid count, must be below 64MB"); } - + if(chunk_count > 1) { if(elem == NULL) { - elem=GetChunkDataInRange(&out_size,chunk_hashes,chunk_count,start,count); + elem=GetChunkDataInRange(&out_size,chunk_hashes,chunk_count,start,count,0); if(elem == NULL) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't retrieve data for this output"); @@ -767,7 +790,55 @@ Value gettxoutdata(const Array& params, bool fHelp) return OpReturnFormatEntry(elem,count,0,0,format,NULL); } } - return OpReturnFormatEntry(elem+start,count,0,0,format,NULL); + return OpReturnFormatEntry(elem+start,count,0,0,format,NULL); +} + +Value txouttobinarycache(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 5) // MCHN + throw runtime_error("Help message not found\n"); + + int64_t size; + + int fHan=mc_BinaryCacheFile(params[0].get_str(),2); + if(fHan <= 0) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Binary cache item with this identifier not found"); + } + + size=lseek64(fHan,0,SEEK_END); + + if(size) + { + close(fHan); + throw JSONRPCError(RPC_INTERNAL_ERROR, "Binary cache item is not empty"); + } + + Array ext_params; + int param_count=0; + BOOST_FOREACH(const Value& value, params) + { + if(param_count) + { + ext_params.push_back(value); + } + param_count++; + } + + size=txoutdata_operation(ext_params,fHan).get_int64(); + + close(fHan); + + return size; + +} + +Value gettxoutdata(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) // MCHN + throw runtime_error("Help message not found\n"); + + return txoutdata_operation(params,0); } /* MCHN END */ diff --git a/src/rpc/rpcwalletutils.cpp b/src/rpc/rpcwalletutils.cpp index e1c4b251..9f2b3cf0 100644 --- a/src/rpc/rpcwalletutils.cpp +++ b/src/rpc/rpcwalletutils.cpp @@ -1091,7 +1091,7 @@ void AppendOffChainFormatData(uint32_t data_format, mc_TxEntity entity; entity.Zero(); entity.m_EntityType=MC_TET_AUTHOR; - + if(out_options & MC_RFD_OPTION_OFFCHAIN) { chunk_count=(int)vValue.size()/MC_CDB_CHUNK_HASH_SIZE; @@ -1100,7 +1100,7 @@ void AppendOffChainFormatData(uint32_t data_format, *strError="Too many chunks in the script"; return; } - + lpDetailsScript->SetChunkDefHeader(data_format,chunk_count); for(int i=0;iSetChunkDefHeader(data_format,0); + } if(fHan > 0) { close(fHan); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 8852c032..77c46a98 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1109,9 +1109,10 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn { if(mc_gState->m_NetworkParams->IsProtocolMultichain()) { - const unsigned char *pubkey_hash=(unsigned char *)Hash160(vchPubKey.begin(),vchPubKey.end()).begin(); - - if(mc_gState->m_Permissions->CanSend(NULL,pubkey_hash)) +// const unsigned char *pubkey_hash=(unsigned char *)Hash160(vchPubKey.begin(),vchPubKey.end()).begin(); +// if(mc_gState->m_Permissions->CanSend(NULL,pubkey_hash)) + uint160 hash=Hash160(vchPubKey.begin(),vchPubKey.end()); + if(mc_gState->m_Permissions->CanSend(NULL,&hash)) { CheckSendPermission=false; } diff --git a/src/storage/addrman.cpp b/src/storage/addrman.cpp index 3fd5237d..ff39505d 100644 --- a/src/storage/addrman.cpp +++ b/src/storage/addrman.cpp @@ -581,11 +581,10 @@ bool CAddrMan::SCSelect_(int nUnkBias,int nNodes,CAddress &addr) for (std::map::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ++it) { - double dNewChance; bool fNewInvalid; bool fNewDead; int64_t nLastTried; - dNewChance=it->second.GetSC(&fNewInvalid,&fNewDead,&nLastTried); + it->second.GetSC(&fNewInvalid,&fNewDead,&nLastTried); if(!fNewInvalid) { diff --git a/src/utils/declare.h b/src/utils/declare.h index c52b72a2..fb81f224 100644 --- a/src/utils/declare.h +++ b/src/utils/declare.h @@ -288,6 +288,7 @@ void __US_FlushFileWithMode(int FileHan,uint32_t use_data_sync); int __US_LockFile(int FileHan); int __US_UnLockFile(int FileHan); int __US_DeleteFile(const char *file_name); +int __US_GetPID(); void sprintf_hex(char *hex,const unsigned char *bin,int size); diff --git a/src/utils/define.h b/src/utils/define.h index 52a432aa..e44dfcf1 100644 --- a/src/utils/define.h +++ b/src/utils/define.h @@ -61,6 +61,7 @@ #define MC_FOM_NONE 0x00000000 #define MC_FOM_RELATIVE_TO_DATADIR 0x00000001 +#define MC_FOM_RELATIVE_TO_LOGDIR 0x00000002 #define MC_FOM_RELATIVE_MASK 0x0000000F #define MC_FOM_CREATE_DIR 0x00000100 diff --git a/src/utils/systemdependent.cpp b/src/utils/systemdependent.cpp index 05c4e5e0..4983c3e8 100644 --- a/src/utils/systemdependent.cpp +++ b/src/utils/systemdependent.cpp @@ -260,6 +260,10 @@ int __US_DeleteFile(const char *file_name) return unlink(file_name); } +int __US_GetPID() +{ + return getpid(); +} #else #include "windows.h" @@ -371,5 +375,9 @@ int __US_DeleteFile(const char *file_name) return (int)DeleteFile(file_name); } +int __US_GetPID() +{ + return (int)GetCurrentProcessId(); +} #endif diff --git a/src/utils/util.cpp b/src/utils/util.cpp index 1b2e0259..ad995bc0 100644 --- a/src/utils/util.cpp +++ b/src/utils/util.cpp @@ -177,7 +177,7 @@ static void DebugPrintInit() assert(fileout == NULL); assert(mutexDebugLog == NULL); - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + boost::filesystem::path pathDebug = GetLogDir() / "debug.log"; fileout = fopen(pathDebug.string().c_str(), "a"); if (fileout) setbuf(fileout, NULL); // unbuffered @@ -247,7 +247,7 @@ int LogPrintStr(const std::string &str) // reopen the log file, if requested if (fReopenDebugLog) { fReopenDebugLog = false; - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + boost::filesystem::path pathDebug = GetLogDir() / "debug.log"; if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) setbuf(fileout, NULL); // unbuffered } @@ -413,6 +413,7 @@ void PrintExceptionContinue(std::exception* pex, const char* pszThread) /* MCHN START */ static boost::filesystem::path pathCachedMultiChain; +static boost::filesystem::path pathCachedMultiChainLog; static CCriticalSection csPathCached; /* MCHN END */ @@ -457,6 +458,19 @@ static boost::filesystem::path pathCached; static boost::filesystem::path pathCachedNetSpecific; //static CCriticalSection csPathCached; +const boost::filesystem::path &GetLogDir(bool fNetSpecific) +{ + namespace fs = boost::filesystem; + + LOCK(csPathCached); + +/* MCHN START */ + fs::path &path =pathCachedMultiChainLog; + if (!path.empty()) + return path; + path=fs::path(string(mc_gState->m_Params->DataDir(2,1))); + return pathCachedMultiChainLog; +} const boost::filesystem::path &GetDataDir(bool fNetSpecific) { @@ -538,7 +552,7 @@ void ReadConfigFile(map& mapSettingsRet, ClearDatadirCache(); } -#ifndef WIN32 +//#ifndef WIN32 boost::filesystem::path GetPidFile() { boost::filesystem::path pathPidFile(GetArg("-pid", "multichain.pid")); @@ -546,7 +560,7 @@ boost::filesystem::path GetPidFile() return pathPidFile; } -void CreatePidFile(const boost::filesystem::path &path, pid_t pid) +void CreatePidFile(const boost::filesystem::path &path, int pid) { FILE* file = fopen(path.string().c_str(), "w"); if (file) @@ -555,7 +569,7 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid) fclose(file); } } -#endif +//#endif bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) { @@ -684,7 +698,7 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { void ShrinkDebugFile(const char* FileName) { // Scroll debug.log if it's getting too big - boost::filesystem::path pathLog = GetDataDir() / string(FileName); + boost::filesystem::path pathLog = GetLogDir() / string(FileName); FILE* file = fopen(pathLog.string().c_str(), "r"); /* MCHN START */ size_t bytes_written; @@ -727,7 +741,7 @@ void ShrinkDebugFile() ShrinkDebugFile("wallet/txs.log"); // Scroll debug.log if it's getting too big /* - boost::filesystem::path pathLog = GetDataDir() / "debug.log"; + boost::filesystem::path pathLog = GetLogDir() / "debug.log"; FILE* file = fopen(pathLog.string().c_str(), "r"); int64_t shrink_size=GetArg("-shrinkdebugfilesize",200000); if(shrink_size > 67108864) diff --git a/src/utils/util.h b/src/utils/util.h index 27d3c475..fc720e0d 100644 --- a/src/utils/util.h +++ b/src/utils/util.h @@ -99,11 +99,12 @@ std::string mc_BuildDescription(int build); boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); +const boost::filesystem::path &GetLogDir(bool fNetSpecific = true); boost::filesystem::path GetConfigFile(); -#ifndef WIN32 +//#ifndef WIN32 boost::filesystem::path GetPidFile(); -void CreatePidFile(const boost::filesystem::path &path, pid_t pid); -#endif +void CreatePidFile(const boost::filesystem::path &path, int pid); +//#endif void ReadConfigFile(std::map& mapSettingsRet, std::map >& mapMultiSettingsRet); #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); diff --git a/src/utils/utilwrapper.cpp b/src/utils/utilwrapper.cpp index 4a834b42..8f23114d 100644 --- a/src/utils/utilwrapper.cpp +++ b/src/utils/utilwrapper.cpp @@ -71,6 +71,7 @@ using namespace std; const boost::filesystem::path mc_GetDataDir(const char *network_name,int create); +const boost::filesystem::path mc_GetLogDir(const char *network_name,int create); void mc_Params::Parse(int argc, const char* const argv[],int exe_type) { @@ -243,12 +244,26 @@ const char *mc_Params::DataDir(int network_specific,int create) name=NetworkName(); } - boost::filesystem::path path=mc_GetDataDir(name,create); + boost::filesystem::path path; if(network_specific) { - strcpy(m_DataDirNetSpecific,path.string().c_str()); - return m_DataDirNetSpecific; + if(network_specific == 1) + { + path=mc_GetDataDir(name,create); + strcpy(m_DataDirNetSpecific,path.string().c_str()); + return m_DataDirNetSpecific; + } + else + { + path=mc_GetLogDir(name,create); + strcpy(m_LogDirNetSpecific,path.string().c_str()); + return m_LogDirNetSpecific; + } + } + else + { + path=mc_GetDataDir(name,create); } strcpy(m_DataDir,path.string().c_str()); @@ -342,6 +357,22 @@ void mc_ExpandDataDirParam() } } } + if (mapArgs.count("-logdir")) + { + string original=mapArgs["-logdir"]; + if(original.size() > 1) + { + if( (*(original.c_str()) == '~') && (*(original.c_str() + 1) == '/') ) + { + const char *homedir=__US_UserHomeDir(); + + if(homedir) + { + mapArgs["-logdir"]=strprintf("%s%s",homedir,original.c_str()+1); + } + } + } + } } void mc_CheckDataDirInConfFile() @@ -390,6 +421,31 @@ const boost::filesystem::path mc_GetDataDir(const char *network_name,int create) return path; } +const boost::filesystem::path mc_GetLogDir(const char *network_name,int create) +{ + boost::filesystem::path path; + if (mapArgs.count("-logdir")) { + path = boost::filesystem::system_complete(mapArgs["-logdir"]); + if (!boost::filesystem::is_directory(path)) + { + return path; + } + } + else + { + return mc_GetDataDir(network_name,create); + } + if(network_name) + { + path /= std::string(network_name); + } + if(create) + { + boost::filesystem::create_directories(path); + } + return path; +} + void mc_CreateDir(const char *dir_name) { boost::filesystem::create_directories(boost::filesystem::path(dir_name)); @@ -456,6 +512,9 @@ string mc_GetFullFileName(const char *network_name,const char *filename, const c case MC_FOM_RELATIVE_TO_DATADIR: pathFile = mc_GetDataDir(network_name,create) / fullName; break; + case MC_FOM_RELATIVE_TO_LOGDIR: + pathFile = mc_GetLogDir(network_name,create) / fullName; + break; } return pathFile.string(); diff --git a/src/v8/v8filter.cpp b/src/v8/v8filter.cpp index a20f052a..710a4462 100644 --- a/src/v8/v8filter.cpp +++ b/src/v8/v8filter.cpp @@ -14,6 +14,39 @@ #define MC_ERR_NOERROR 0x00000000 #define MC_ERR_INTERNAL_ERROR 0x00000006 +/* Unlocked date functions: + +//Date.prototype.getTime = function() {return 0;}; + +//Date.prototype.getUTCDate = function() {return 0;}; +//Date.prototype.getUTCFullYear = function() {return 0;}; +//Date.prototype.getUTCHours = function() {return 0;}; +//Date.prototype.getUTCMonth = function() {return 0;}; +//Date.prototype.getUTCMinutes = function() {return 0;}; +//Date.prototype.getUTCDay = function() {return 0;}; +//Date.prototype.getUTCSeconds = function() {return 0;}; +//Date.prototype.getUTCMilliseconds = function() {return 0;}; +//Date.prototype.getUTCTime = function() {return 0;}; + +//Date.prototype.toGMTString = function() {return 0;}; +//Date.prototype.toISOString = function() {return 0;}; +//Date.prototype.toJSON = function() {return 0;}; +//Date.prototype.toUTCString = function() {return 0;}; +//Date.prototype.valueOf = function() {return 0;}; + +//Date.prototype.setTime = function() {return 0;}; +//Date.prototype.setUTCDate = function() {return 0;}; +//Date.prototype.setUTCFullYear = function() {return 0;}; +//Date.prototype.setUTCHours = function() {return 0;}; +//Date.prototype.setUTCMinutes = function() {return 0;}; +//Date.prototype.setUTCMonth = function() {return 0;}; +//Date.prototype.setUTCYear = function() {return 0;}; +//Date.prototype.setUTCSeconds = function() {return 0;}; +//Date.prototype.setUTCMilliseconds = function() {return 0;}; +//Date.prototype.setUTCTime = function() {return 0;}; +}; +*/ + namespace mc_v8 { @@ -56,6 +89,77 @@ Date = function (Date) { }(Date); )"; +static std::string jsFixtureDateFunctions = R"( +Math.random = function() { + return 0; +}; + +Date.now = function() { + return 0; +}; + +var bind = Function.bind; +var unbind = bind.bind(bind); + +function instantiate(constructor, args) { + return new (unbind(constructor, null).apply(null, args)); +} + +Date.prototype.getDate = function() {return 0;}; +Date.prototype.getFullYear = function() {return 0;}; +Date.prototype.getHours = function() {return 0;}; +Date.prototype.getMonth = function() {return 0;}; +Date.prototype.getMinutes = function() {return 0;}; +Date.prototype.getDay = function() {return 0;}; +Date.prototype.getYear = function() {return 0;}; +Date.prototype.getSeconds = function() {return 0;}; +Date.prototype.getMilliseconds = function() {return 0;}; +Date.prototype.getTimezoneOffset = function() {return 0;}; + +Date.prototype.toDateString = function() {return "";}; +Date.prototype.toGMTString = function() {return "";}; +Date.prototype.toISOString = function() {return "";}; +Date.prototype.toJSON = function() {return "";}; +Date.prototype.toLocaleDateString = function() {return "";}; +Date.prototype.toLocaleFormat = function() {return "";}; +Date.prototype.toLocaleString = function() {return "";}; +Date.prototype.toLocaleTimeString = function() {return "";}; +Date.prototype.toString = function() {return "";}; +Date.prototype.toTimeString = function() {return "";}; +Date.prototype.toUTCString = function() {return "";}; + +Date.prototype.setDate = function() {return 0;}; +Date.prototype.setFullYear = function() {return 0;}; +Date.prototype.setHours = function() {return 0;}; +Date.prototype.setMinutes = function() {return 0;}; +Date.prototype.setMonth = function() {return 0;}; +Date.prototype.setYear = function() {return 0;}; +Date.prototype.setSeconds = function() {return 0;}; +Date.prototype.setMilliseconds = function() {return 0;}; + +Date = function (Date) { + var names = Object.getOwnPropertyNames(Date); + // Loop through them + for (var i = 0; i < names.length; i++) { + // Skip props already in the MyDate object + if (names[i] in MyDate) continue; + // Get property description from o + var desc = Object.getOwnPropertyDescriptor(Date, names[i]); + // Use it to create property on MyDate + Object.defineProperty(MyDate, names[i], desc); + } + + return MyDate; + + function MyDate() { + if (arguments.length >= 0) { + arguments = [0]; + } + return instantiate(Date, arguments); + } +}(Date); +)"; + static std::string jsLimitMathSet = R"( var mathKeep = new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc", "log", "log10", "log2", "pow", "sqrt", "E", "LN10", "LN2", "LOG10E", "LOG2E", "PI", "SQRT1_2", "SQRT2" ]); @@ -104,6 +208,10 @@ int V8Filter::Initialize(V8Engine *engine, std::string script, std::string funct m_context.Reset(isolate, context); std::string jsPreamble = jsFixture; + if(mc_gState->m_Features->FixedJSDateFunctions()) + { + jsPreamble=jsFixtureDateFunctions; + } if (mc_gState->m_Features->FilterLimitedMathSet()) { jsPreamble += jsLimitMathSet; diff --git a/src/v8_win/v8_win.cpp b/src/v8_win/v8_win.cpp index 643a2e60..91596c83 100644 --- a/src/v8_win/v8_win.cpp +++ b/src/v8_win/v8_win.cpp @@ -79,14 +79,14 @@ bool V8Filter_IsRunning(V8Filter_t *filter_) } int V8Filter_Initialize(V8Filter_t *filter_, V8Engine_t *engine_, const char *script_, const char *functionName_, - const char **callbackNames_, size_t nCallbackNames_, bool isFilterLimitedMathSet_, + const char **callbackNames_, size_t nCallbackNames_, bool isFilterLimitedMathSet_, bool isFixedJSDateFunctions_, char *strResult_) { auto filter = reinterpret_cast(filter_); auto engine = reinterpret_cast(engine_); std::vector callbackNames = cstrs2vec(callbackNames_, nCallbackNames_); std::string strResult; - int retval = filter->Initialize(engine, script_, functionName_, callbackNames, isFilterLimitedMathSet_, strResult); + int retval = filter->Initialize(engine, script_, functionName_, callbackNames, isFilterLimitedMathSet_, isFixedJSDateFunctions_, strResult); strcpy_s(strResult_, RESULT_SIZE, strResult.c_str()); return retval; } @@ -127,13 +127,13 @@ int V8Engine_Initialize(V8Engine_t *engine_, IFilterCallback_t *filterCallback_, } int V8Engine_CreateFilter(V8Engine_t *engine_, const char *script_, const char *mainName_, const char **callbackNames_, - size_t nCallbackNames_, V8Filter_t *filter_, bool isFilterLimitedMathSet_, char *strResult_) + size_t nCallbackNames_, V8Filter_t *filter_, bool isFilterLimitedMathSet_, bool isFixedJSDateFunctions_, char *strResult_) { auto engine = reinterpret_cast(engine_); auto filter = reinterpret_cast(filter_); std::vector callbackNames = cstrs2vec(callbackNames_, nCallbackNames_); std::string strResult; - int retval = engine->CreateFilter(script_, mainName_, callbackNames, filter, isFilterLimitedMathSet_, strResult); + int retval = engine->CreateFilter(script_, mainName_, callbackNames, filter, isFilterLimitedMathSet_, isFixedJSDateFunctions_, strResult); strcpy_s(strResult_, RESULT_SIZE, strResult.c_str()); return retval; } diff --git a/src/v8_win/v8_win.h b/src/v8_win/v8_win.h index 5f1b8941..7c34fc53 100644 --- a/src/v8_win/v8_win.h +++ b/src/v8_win/v8_win.h @@ -83,7 +83,7 @@ DLLEXPORT bool V8Filter_IsRunning(V8Filter_t* filter_); */ DLLEXPORT int V8Filter_Initialize(V8Filter_t* filter_, V8Engine_t* engine_, const char* script_, const char* functionName_, const char** callbackNames_, size_t nCallbackNames_, - bool isFilterLimitedMathSet_, char* strResult_); + bool isFilterLimitedMathSet_, bool isFixedJSDateFunctions_, char* strResult_); /** * Run the filter function in the JS script. @@ -128,12 +128,13 @@ DLLEXPORT int V8Engine_Initialize(V8Engine_t* engine_, IFilterCallback_t* filter * @param nCallbackNames_ The number of callback names in @p callback_names_ * @param filter_ The filter object to initialize. * @param isFilterLimitedMathSet_ @c true if JS Math functions have to be suppressed. + * @param isFixedJSDateFunctions_ @c true if limited set of JS Date functions is allowed. * @param strResult_ Reason for failure if unsuccessful. * @return MC_ERR_INTERNAL_ERROR if the engine failed, MC_ERR_NOERROR otherwise. */ DLLEXPORT int V8Engine_CreateFilter(V8Engine_t* engine_, const char* script_, const char* mainName_, const char** callbackNames_, size_t nCallbackNames_, V8Filter_t* filter_, - bool isFilterLimitedMathSet_, char* strResult_); + bool isFilterLimitedMathSet_, bool FixedJSDateFunctions_, char* strResult_); /** * Run the filter function in the JS script. diff --git a/src/v8_win/v8engine.cpp b/src/v8_win/v8engine.cpp index 5774ad07..418e5917 100644 --- a/src/v8_win/v8engine.cpp +++ b/src/v8_win/v8engine.cpp @@ -49,11 +49,11 @@ int V8Engine::Initialize(IFilterCallback *filterCallback, std::string dataDir_, } int V8Engine::CreateFilter(std::string script, std::string mainName, const std::vector &callbackNames, - V8Filter *filter, bool isFilterLimitedMathSet, std::string &strResult) + V8Filter *filter, bool isFilterLimitedMathSet, bool isFixedJSDateFunctions_, std::string &strResult) { logger->debug("V8Engine::CreateFilter - enter"); strResult.clear(); - int retval = filter->Initialize(this, script, mainName, callbackNames, isFilterLimitedMathSet, strResult); + int retval = filter->Initialize(this, script, mainName, callbackNames, isFilterLimitedMathSet, isFixedJSDateFunctions_, strResult); logger->debug("V8Engine::CreateFilter - leave retval={} strResult='{}'", retval, strResult); return retval; } diff --git a/src/v8_win/v8engine.h b/src/v8_win/v8engine.h index 433aaf01..7fabe121 100644 --- a/src/v8_win/v8engine.h +++ b/src/v8_win/v8engine.h @@ -49,7 +49,7 @@ class V8Engine * @return MC_ERR_INTERNAL_ERROR if the engine failed, MC_ERR_NOERROR otherwise. */ int CreateFilter(std::string script, std::string mainName, const std::vector &callbackNames, - V8Filter *filter, bool isFilterLimitedMathSet, std::string &strResult); + V8Filter *filter, bool isFilterLimitedMathSet, bool isFixedJSDateFunctions_, std::string &strResult); /** * Run the filter function in the JS script. diff --git a/src/v8_win/v8filter.cpp b/src/v8_win/v8filter.cpp index 85f35be8..8d145cd2 100644 --- a/src/v8_win/v8filter.cpp +++ b/src/v8_win/v8filter.cpp @@ -48,6 +48,77 @@ Date = function (Date) { }(Date); )"; +static std::string jsFixtureDateFunctions = R"( +Math.random = function() { + return 0; +}; + +Date.now = function() { + return 0; +}; + +var bind = Function.bind; +var unbind = bind.bind(bind); + +function instantiate(constructor, args) { + return new (unbind(constructor, null).apply(null, args)); +} + +Date.prototype.getDate = function() {return 0;}; +Date.prototype.getFullYear = function() {return 0;}; +Date.prototype.getHours = function() {return 0;}; +Date.prototype.getMonth = function() {return 0;}; +Date.prototype.getMinutes = function() {return 0;}; +Date.prototype.getDay = function() {return 0;}; +Date.prototype.getYear = function() {return 0;}; +Date.prototype.getSeconds = function() {return 0;}; +Date.prototype.getMilliseconds = function() {return 0;}; +Date.prototype.getTimezoneOffset = function() {return 0;}; + +Date.prototype.toDateString = function() {return "";}; +Date.prototype.toGMTString = function() {return "";}; +Date.prototype.toISOString = function() {return "";}; +Date.prototype.toJSON = function() {return "";}; +Date.prototype.toLocaleDateString = function() {return "";}; +Date.prototype.toLocaleFormat = function() {return "";}; +Date.prototype.toLocaleString = function() {return "";}; +Date.prototype.toLocaleTimeString = function() {return "";}; +Date.prototype.toString = function() {return "";}; +Date.prototype.toTimeString = function() {return "";}; +Date.prototype.toUTCString = function() {return "";}; + +Date.prototype.setDate = function() {return 0;}; +Date.prototype.setFullYear = function() {return 0;}; +Date.prototype.setHours = function() {return 0;}; +Date.prototype.setMinutes = function() {return 0;}; +Date.prototype.setMonth = function() {return 0;}; +Date.prototype.setYear = function() {return 0;}; +Date.prototype.setSeconds = function() {return 0;}; +Date.prototype.setMilliseconds = function() {return 0;}; + +Date = function (Date) { + var names = Object.getOwnPropertyNames(Date); + // Loop through them + for (var i = 0; i < names.length; i++) { + // Skip props already in the MyDate object + if (names[i] in MyDate) continue; + // Get property description from o + var desc = Object.getOwnPropertyDescriptor(Date, names[i]); + // Use it to create property on MyDate + Object.defineProperty(MyDate, names[i], desc); + } + + return MyDate; + + function MyDate() { + if (arguments.length >= 0) { + arguments = [0]; + } + return instantiate(Date, arguments); + } +}(Date); +)"; + static std::string jsLimitMathSet = R"( var mathKeep = new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc", "log", "log10", "log2", "pow", "sqrt", "E", "LN10", "LN2", "LOG10E", "LOG2E", "PI", "SQRT1_2", "SQRT2" ]); @@ -71,7 +142,7 @@ V8Filter::~V8Filter() } int V8Filter::Initialize(V8Engine *engine, std::string script, std::string functionName, - const std::vector &callbackNames, bool isFilterLimitedMathSet, + const std::vector &callbackNames, bool isFilterLimitedMathSet, bool isFixedJSDateFunctions, std::string &strResult) { logger->debug("V8Filter::Initialize - enter"); @@ -103,6 +174,10 @@ int V8Filter::Initialize(V8Engine *engine, std::string script, std::string funct m_context.Reset(isolate, context); std::string jsPreamble = jsFixture; + if (isFixedJSDateFunctions) + { + jsPreamble=jsFixtureDateFunctions; + } if (isFilterLimitedMathSet) { jsPreamble += jsLimitMathSet; diff --git a/src/v8_win/v8filter.h b/src/v8_win/v8filter.h index a63b3949..8138bb44 100644 --- a/src/v8_win/v8filter.h +++ b/src/v8_win/v8filter.h @@ -36,7 +36,7 @@ class V8Filter * MC_ERR_NOERROR otherwise. */ int Initialize(V8Engine *engine, std::string script, std::string functionName, - const std::vector &callbackNames, bool isFilterLimitedMathSet, std::string &strResult); + const std::vector &callbackNames, bool isFilterLimitedMathSet, bool isFixedJSDateFunctions, std::string &strResult); /** * Run the filter function in the JS script. diff --git a/src/version/version.cpp b/src/version/version.cpp index dd1a8145..0363ebff 100644 --- a/src/version/version.cpp +++ b/src/version/version.cpp @@ -13,8 +13,8 @@ int mc_State::VersionInfo(int version) return custom_version; } - int this_build=20000202; - int this_protocol=20007; + int this_build=20000203; + int this_protocol=20008; if(version < 0) { diff --git a/src/wallet/chunkdb.cpp b/src/wallet/chunkdb.cpp index 4a264bb8..6cb6110b 100644 --- a/src/wallet/chunkdb.cpp +++ b/src/wallet/chunkdb.cpp @@ -822,6 +822,7 @@ int mc_ChunkDB::Initialize(const char *name,uint32_t mode) { int err,value_len,new_db; char msg[256]; + char dir_name[MC_DCT_DB_MAX_PATH]; mc_SubscriptionDBRow subscription; @@ -836,7 +837,9 @@ int mc_ChunkDB::Initialize(const char *name,uint32_t mode) mc_GetFullFileName(name,"chunks","",MC_FOM_RELATIVE_TO_DATADIR | MC_FOM_CREATE_DIR,m_DirName); mc_CreateDir(m_DirName); mc_GetFullFileName(name,"chunks/chunks",".db",MC_FOM_RELATIVE_TO_DATADIR | MC_FOM_CREATE_DIR,m_DBName); - mc_GetFullFileName(name,"chunks/chunks",".log",MC_FOM_RELATIVE_TO_DATADIR,m_LogFileName); + mc_GetFullFileName(name,"chunks","",MC_FOM_RELATIVE_TO_LOGDIR | MC_FOM_CREATE_DIR,dir_name); + mc_CreateDir(dir_name); + mc_GetFullFileName(name,"chunks/chunks",".log",MC_FOM_RELATIVE_TO_LOGDIR | MC_FOM_CREATE_DIR,m_LogFileName); m_DB->SetOption("KeySize",0,m_KeySize); m_DB->SetOption("ValueSize",0,m_ValueSize); diff --git a/src/wallet/dbflat.cpp b/src/wallet/dbflat.cpp index 29382c6d..2c41c2ff 100644 --- a/src/wallet/dbflat.cpp +++ b/src/wallet/dbflat.cpp @@ -17,7 +17,7 @@ bool fDBFlatDebug=false; bool fDBFlatDebugKey=false; bool mc_CopyFile(boost::filesystem::path& pathDBOld,boost::filesystem::path& pathDBNew); -void PrintDBFlatPos(char *msg,const mc_DBFlatPos *pos) +void PrintDBFlatPos(const char *msg,const mc_DBFlatPos *pos) { if(fDBFlatDebug) { @@ -25,7 +25,7 @@ void PrintDBFlatPos(char *msg,const mc_DBFlatPos *pos) } } -void PrintDataStreamKey(char *msg,const CDataStream& ss) +void PrintDataStreamKey(const char *msg,const CDataStream& ss) { if(fDBFlatDebugKey) { @@ -35,7 +35,7 @@ void PrintDataStreamKey(char *msg,const CDataStream& ss) printf("%s: %s",msg,strType.c_str()); if(ss_copy.size()) { - printf(" + %u bytes: ",ss_copy.size()); + printf(" + %lu bytes: ",ss_copy.size()); if(ss_copy.size() == 4) { uint32_t v; @@ -936,7 +936,6 @@ int CDBFlat::ReadAtCursor(void* pcursor, CDataStream& ssKey, CDataStream& ssValu mc_DBFlatPos *lpPos; uint32_t key_size_bytes; uint32_t val_size_bytes; - uint32_t off; if(pcursor) { while(true) @@ -946,7 +945,6 @@ int CDBFlat::ReadAtCursor(void* pcursor, CDataStream& ssKey, CDataStream& ssValu { PrintDBFlatPos("Read At Cursor",lpPos); } - off=lpPos->m_Offset; if(lpPos->m_Offset+MC_DBF_FLAGS_FIELDSIZE >= m_FileSize) { if(lpPos->m_Offset == m_FileSize) diff --git a/src/wallet/dbwrap_ent.cpp b/src/wallet/dbwrap_ent.cpp new file mode 100644 index 00000000..197ebe20 --- /dev/null +++ b/src/wallet/dbwrap_ent.cpp @@ -0,0 +1,196 @@ +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Original code was distributed under the MIT software license. +// Copyright (c) 2014-2019 Coin Sciences Ltd +// MultiChain code distributed under the GPLv3 license, see COPYING file. + +#include "wallet/dbwrap.h" + +#include +#include +#include + +#include + +using namespace std; +using namespace boost; + +unsigned int nWalletDBUpdated; + +CDBWrapEnv bitdbwrap; + +void WalletDBLogVersionString() +{ + LogPrintf("Using walletdbversion=3\n"); +} + +void CDBWrapEnv::EnvShutdown() +{ + +} + +CDBWrapEnv::CDBWrapEnv() +{ + m_lpDBEnv=NULL; + m_lpMapFileUseCount=NULL; +} + +CDBWrapEnv::~CDBWrapEnv() +{ + EnvShutdown(); +} + +void CDBWrapEnv::Close() +{ + EnvShutdown(); +} + +bool CDBWrapEnv::Open(const boost::filesystem::path& pathIn) +{ + m_Env.Open(pathIn); + return true; +} + +CDBConstEnv::VerifyResult CDBWrapEnv::Verify(std::string strFile) +{ + return m_Env.Verify(strFile); +} + +void CDBWrapEnv::SetSeekDBName(std::string strFile) +{ + if(m_lpDBEnv == NULL) + { + m_Env.m_FileName=strFile; + } +} + +bool CDBWrapEnv::Salvage(std::string strFile, bool fAggressive, std::vector& vResult) +{ + return m_Env.Salvage(strFile,fAggressive,vResult); +} + + +void CDBWrapEnv::CheckpointLSN(const std::string& strFile) +{ + +} + +int CDBWrapEnv::RenameDb(const std::string& strOldFileName,const std::string& strNewFileName) +{ + return m_Env.RenameDb(strOldFileName,strNewFileName); +} + +bool CDBWrapEnv::Recover(std::string strFile, std::vector& SalvagedData) +{ + return m_Env.Recover(strFile,SalvagedData); +} + +CDBWrap::CDBWrap(const std::string& strFilename, const char* pszMode) +{ + m_lpDb=NULL; + m_lpDbFlat=new CDBFlat(&bitdbwrap.m_Env,strFilename,pszMode); +} + +CDBWrap::~CDBWrap() +{ + if(m_lpDbFlat) + { + delete m_lpDbFlat; + } +} + + +void CDBWrap::Flush() +{ + m_lpDbFlat->Flush(); +} + +void CDBWrap::Close() +{ + m_lpDbFlat->Close(); +} + +void CDBWrapEnv::CloseDb(const string& strFile) +{ + +} + +bool CDBWrapEnv::RemoveDb(const string& strFile) +{ + return m_Env.RemoveDb(strFile); +} + + +void CDBWrapEnv::Flush(bool fShutdown) +{ + +} + +bool CDBWrap::Read(CDataStream& key, CDataStream& value) +{ + return m_lpDbFlat->Read(key,value); +} + +bool CDBWrap::Write(CDataStream& key, CDataStream& value, bool fOverwrite) +{ + return m_lpDbFlat->Write(key,value,fOverwrite); +} + +bool CDBWrap::Erase(CDataStream& key) +{ + return m_lpDbFlat->Erase(key); +} + +bool CDBWrap::Exists(CDataStream& key) +{ + return m_lpDbFlat->Exists(key); +} + +void* CDBWrap::GetCursor() +{ + return m_lpDbFlat->GetCursor(); +} + +void CDBWrap::CloseCursor(void* cursor) +{ + return m_lpDbFlat->CloseCursor(cursor); +} + +// int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT) +int CDBWrap::ReadAtCursor(void* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags) +{ + return m_lpDbFlat->ReadAtCursor(pcursor,ssKey,ssValue,fFlags); +} + + +bool CDBWrap::TxnBegin() +{ + return m_lpDbFlat->TxnBegin(); +} + +bool CDBWrap::TxnCommit() +{ + return m_lpDbFlat->TxnCommit(); +} + +bool CDBWrap::TxnAbort() +{ + return m_lpDbFlat->TxnAbort(); +} + +bool CDBWrap::ReadVersion(int& nVersion) +{ + return m_lpDbFlat->ReadVersion(nVersion); +} + +bool CDBWrap::WriteVersion(int nVersion) +{ + return m_lpDbFlat->WriteVersion(nVersion); +} + + +bool RewriteWalletDB(const std::string& strFile, const char* pszSkip) +{ + return CDBFlat::Rewrite(&bitdbwrap.m_Env,strFile,pszSkip); +} + + diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index de8782b2..fc7b2359 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -19,6 +19,7 @@ extern mc_WalletTxs* pwalletTxsMain; #include "utils/timedata.h" #include "utils/util.h" #include "utils/utilmoneystr.h" +#include "community/community.h" #include @@ -30,6 +31,10 @@ using namespace std; /** * Settings */ + +//! -maxtxfee default +static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN; + CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; unsigned int nTxConfirmTarget = 1; @@ -1356,9 +1361,10 @@ mc_TxImport *StartImport(CWallet *lpWallet,bool fOnlyUnsynced, bool fOnlySubscri lpent=(mc_TxEntityStat*)m_ChainEntities->GetRow(i); if(lpent->m_Entity.IsSubscription()) { - if(lpent->m_Entity.m_EntityType & MC_TET_CHAINPOS) +// if(lpent->m_Entity.m_EntityType & MC_TET_CHAINPOS) { - if(lpent->m_Flags & MC_EFL_NOT_IN_SYNC) + if( ((lpent->m_Flags & MC_EFL_NOT_IN_SYNC) != 0 ) || + (pEF->STR_IsOutOfSync(&(lpent->m_Entity)) != 0) ) { vStreamsToImport.push_back(lpent->m_Entity); } @@ -1442,8 +1448,10 @@ mc_TxImport *StartImport(CWallet *lpWallet,bool fOnlyUnsynced, bool fOnlySubscri memcpy(entity.m_EntityID,vStreamsToImport[i].m_EntityID,MC_TDB_ENTITY_ID_SIZE); entity.m_EntityType=vStreamsToImport[i].m_EntityType; lpEntities->Add(&entity,NULL); +/* entity.m_EntityType=(vStreamsToImport[i].m_EntityType - MC_TET_CHAINPOS) | MC_TET_TIMERECEIVED; lpEntities->Add(&entity,NULL); + */ } } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index ce21d696..b35bed70 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -45,12 +45,6 @@ extern bool fPayAtLeastCustomFee; //! -paytxfee default static const CAmount DEFAULT_TRANSACTION_FEE = 0; -//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB -static const CAmount nHighTransactionFeeWarning = 0.01 * COIN; -//! -maxtxfee default -static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN; -//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) -static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning; //! Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; diff --git a/src/wallet/wallettxdb.cpp b/src/wallet/wallettxdb.cpp index b76473c3..c4c35d5a 100644 --- a/src/wallet/wallettxdb.cpp +++ b/src/wallet/wallettxdb.cpp @@ -3,6 +3,7 @@ #include "multichain/multichain.h" #include "wallet/wallettxdb.h" +#include "community/community.h" #define MC_TDB_MAX_TXS_FILE_SIZE 0x8000000 // Maximal data file size, 128MB @@ -296,6 +297,7 @@ int mc_TxDB::Initialize(const char *name,uint32_t mode) int import_count; int last_import; char msg[256]; + char dir_name[MC_DCT_DB_MAX_PATH]; mc_TxEntityStat stat; mc_TxImportRow edbImport; @@ -312,7 +314,9 @@ int mc_TxDB::Initialize(const char *name,uint32_t mode) m_Database=new mc_TxEntityDB; mc_GetFullFileName(name,"wallet/txs","",MC_FOM_RELATIVE_TO_DATADIR | MC_FOM_CREATE_DIR,m_LobFileNamePrefix); - mc_GetFullFileName(name,"wallet/txs",".log",MC_FOM_RELATIVE_TO_DATADIR,m_LogFileName); + mc_GetFullFileName(name,"wallet","",MC_FOM_RELATIVE_TO_LOGDIR | MC_FOM_CREATE_DIR,dir_name); + mc_CreateDir(dir_name); + mc_GetFullFileName(name,"wallet/txs",".log",MC_FOM_RELATIVE_TO_LOGDIR | MC_FOM_CREATE_DIR,m_LogFileName); m_Database->SetName(name); @@ -923,11 +927,6 @@ int mc_TxDB::DecrementSubKey( err=MC_ERR_NOERROR; - if(IsCSkipped(entity->m_EntityType)) - { - return err; - } - imp=m_Imports; mempool=m_MemPools[0]; if(import) // Find import @@ -1014,11 +1013,6 @@ int mc_TxDB::IncrementSubKey( err=MC_ERR_NOERROR; - if(IsCSkipped(entity->m_EntityType)) - { - return err; - } - imp=m_Imports; mempool=m_MemPools[0]; if(import) // Find import @@ -1044,7 +1038,7 @@ int mc_TxDB::IncrementSubKey( memcpy(&erow.m_Entity,entity,sizeof(mc_TxEntity)); erow.m_Generation=stat->m_Generation; - + last_pos=0; mprow=mempool->Seek(&erow); if(mprow >= 0) @@ -1074,35 +1068,41 @@ int mc_TxDB::IncrementSubKey( memcpy((char*)&erow+m_Database->m_ValueOffset,ptr,m_Database->m_ValueSize); last_pos=erow.m_LastSubKeyPos; } + if( (IsCSkipped(entity->m_EntityType) == 0) && (pEF->STR_IsIndexSkipped(import,parent_entity,entity) == 0) ) + { + erow.Zero(); + memcpy(&erow.m_Entity,entity,sizeof(mc_TxEntity)); + erow.m_Generation=stat->m_Generation; + erow.m_LastSubKeyPos=last_pos+1; + mempool->Add(&erow,(unsigned char*)&erow+MC_TDB_ENTITY_KEY_SIZE+MC_TDB_TXID_SIZE); + } + } + + if( (IsCSkipped(entity->m_EntityType) == 0) && (pEF->STR_IsIndexSkipped(import,parent_entity,entity) == 0) ) + { erow.Zero(); memcpy(&erow.m_Entity,entity,sizeof(mc_TxEntity)); erow.m_Generation=stat->m_Generation; + memcpy(erow.m_TxId,tx_hash,MC_TDB_TXID_SIZE); erow.m_LastSubKeyPos=last_pos+1; - mempool->Add(&erow,(unsigned char*)&erow+MC_TDB_ENTITY_KEY_SIZE+MC_TDB_TXID_SIZE); - } - - erow.Zero(); - memcpy(&erow.m_Entity,entity,sizeof(mc_TxEntity)); - erow.m_Generation=stat->m_Generation; - memcpy(erow.m_TxId,tx_hash,MC_TDB_TXID_SIZE); - erow.m_LastSubKeyPos=last_pos+1; - erow.m_TempPos=last_pos+1; - erow.m_Block=block; - erow.m_Flags=flags; - if(extension) - { - if(extension->m_Count) + erow.m_TempPos=last_pos+1; + erow.m_Block=block; + erow.m_Flags=flags; + if(extension) { - memcpy(erow.m_TxId+MC_TEE_OFFSET_IN_TXID,extension,MC_TEE_SIZE_IN_EXTENSION); - erow.m_Flags |= MC_TFL_IS_EXTENSION; + if(extension->m_Count) + { + memcpy(erow.m_TxId+MC_TEE_OFFSET_IN_TXID,extension,MC_TEE_SIZE_IN_EXTENSION); + erow.m_Flags |= MC_TFL_IS_EXTENSION; + } } - } - mempool->Add(&erow,(unsigned char*)&erow+MC_TDB_ENTITY_KEY_SIZE+MC_TDB_TXID_SIZE); + mempool->Add(&erow,(unsigned char*)&erow+MC_TDB_ENTITY_KEY_SIZE+MC_TDB_TXID_SIZE); + } if(last_pos == 0) { - if(IsCSkipped(stat->m_Entity.m_EntityType) == 0) + if( (IsCSkipped(stat->m_Entity.m_EntityType) == 0) && (pEF->STR_IsIndexSkipped(import,NULL,parent_entity) == 0) ) { erow.Zero(); memcpy(&erow.m_Entity,&stat->m_Entity,sizeof(mc_TxEntity)); @@ -1340,6 +1340,11 @@ int mc_TxDB::AddTx(mc_TxImport *import, { isrelevant=0; } + if(pEF->STR_IsIndexSkipped(import,NULL,(mc_TxEntity*)entities->GetRow(i))) + { + isrelevant=0; + } + if(isrelevant) { @@ -2134,6 +2139,11 @@ int mc_TxDB::GetList( return MC_ERR_NOT_SUPPORTED; } + if(pEF->STR_IsIndexSkipped(import,NULL,entity)) + { + return MC_ERR_NOT_ALLOWED; + } + int row; mc_TxEntityStat *stat; @@ -2260,6 +2270,11 @@ int mc_TxDB::GetList( return MC_ERR_NOT_SUPPORTED; } + if(pEF->STR_IsIndexSkipped(import,NULL,entity)) + { + return MC_ERR_NOT_ALLOWED; + } + mempool=m_MemPools[import-m_Imports]; first=from; @@ -2490,6 +2505,49 @@ int mc_TxDB::GetListSize(mc_TxEntity *entity,int *confirmed) return (int)(stat->m_LastPos); } +int mc_TxDB::TransferSubKey(mc_TxEntityStat *lpChainEntStat,const mc_TxEntityRow& erow,int slot) +{ + unsigned char* subkey_ptr; + mc_TxEntityRow subkey_erow; + unsigned char stream_subkey_hash160[20]; + int subkey_list_size,transferred_subkeys; + int err=MC_ERR_NOERROR; + int i,value_len; + + transferred_subkeys=0; + + switch(lpChainEntStat->m_Entity.m_EntityType & MC_TET_TYPE_MASK) + { + case MC_TET_STREAM_KEY: + case MC_TET_STREAM_PUBLISHER: + mc_GetCompoundHash160(&stream_subkey_hash160,&(erow.m_Entity.m_EntityID),erow.m_TxId); + subkey_erow.Zero(); + memcpy(subkey_erow.m_Entity.m_EntityID,&stream_subkey_hash160,MC_TDB_ENTITY_ID_SIZE); + subkey_erow.m_Entity.m_EntityType=lpChainEntStat->m_Entity.m_EntityType | MC_TET_SUBKEY; + subkey_erow.m_Generation=lpChainEntStat->m_Generation; + GetListSize(&(subkey_erow.m_Entity),subkey_erow.m_Generation,&subkey_list_size); + for(i=0;im_Generation; + subkey_erow.SwapPosBytes(); + subkey_ptr=(unsigned char*)m_Database->m_DB->Read((char*)&subkey_erow+m_Database->m_KeyOffset,m_Database->m_KeySize,&value_len,0,&err); + subkey_erow.m_Generation=(m_Imports+slot)->m_ImportID; // Change generation when writing to DB + err=m_Database->m_DB->Write((char*)&subkey_erow+m_Database->m_KeyOffset,m_Database->m_KeySize,(char*)subkey_ptr,m_Database->m_ValueSize,MC_OPT_DB_DATABASE_TRANSACTIONAL); + subkey_erow.SwapPosBytes(); + transferred_subkeys++; + if(transferred_subkeys >= 1000) + { + m_Database->m_DB->Commit(MC_OPT_DB_DATABASE_TRANSACTIONAL); + transferred_subkeys=0; + } + } + break; + } + + return MC_ERR_NOERROR; +} + mc_TxImport *mc_TxDB::StartImport(mc_Buffer *lpEntities,int block,int *err) { char msg[256]; @@ -2503,8 +2561,6 @@ mc_TxImport *mc_TxDB::StartImport(mc_Buffer *lpEntities,int block,int *err) mc_TxEntityRow erow; mc_TxEntityRow *lperow; unsigned char* ptr; - - Dump("Before StartImport"); generation=m_DBStat.m_LastGeneration+1; slot=0; @@ -2569,11 +2625,20 @@ mc_TxImport *mc_TxDB::StartImport(mc_Buffer *lpEntities,int block,int *err) erow.m_Generation=(m_Imports+slot)->m_ImportID; // Change generation when writing to DB *err=m_Database->m_DB->Write((char*)&erow+m_Database->m_KeyOffset,m_Database->m_KeySize,(char*)ptr,m_Database->m_ValueSize,MC_OPT_DB_DATABASE_TRANSACTIONAL); erow.SwapPosBytes(); + + count++; if(*err) { goto exitlbl; } + + *err=TransferSubKey(lpChainEntStat,erow,slot); + if(*err) + { + goto exitlbl; + } + if(((pos+1) % 1000) == 0) { m_Database->m_DB->Commit(MC_OPT_DB_DATABASE_TRANSACTIONAL); @@ -2594,6 +2659,7 @@ mc_TxImport *mc_TxDB::StartImport(mc_Buffer *lpEntities,int block,int *err) *err=m_Database->m_DB->Write((char*)&erow+m_Database->m_KeyOffset,m_Database->m_KeySize,(char*)&erow+m_Database->m_ValueOffset,m_Database->m_ValueSize,MC_OPT_DB_DATABASE_TRANSACTIONAL); erow.SwapPosBytes(); count++; + *err=TransferSubKey(lpChainEntStat,erow,slot); } } } @@ -2963,7 +3029,8 @@ int mc_TxDB::CompleteImport(mc_TxImport *import,uint32_t flags) edbImport.m_Generation=lpdel->m_Generation; edbImport.m_Block=import->m_Block; edbImport.m_Pos=lpdel->m_PosInImport; - edbImport.m_LastPos=lpdel->m_LastPos; + edbImport.m_LastPos=lpdel->m_LastClearedPos; +// edbImport.m_LastPos=lpdel->m_LastPos; edbImport.m_LastImportedBlock=lpent->m_LastImportedBlock;//import->m_Block; edbImport.m_TimeAdded=lpdel->m_TimeAdded; edbImport.m_Flags=lpdel->m_Flags; @@ -2988,6 +3055,8 @@ int mc_TxDB::CompleteImport(mc_TxImport *import,uint32_t flags) { goto exitlbl; } + + pEF->STR_SetSyncFlag(&(lpent->m_Entity),false); } edbImport.Zero(); // Import block update @@ -3030,6 +3099,11 @@ int mc_TxDB::CompleteImport(mc_TxImport *import,uint32_t flags) m_Imports->m_Block=import->m_Block; // Cleanup below this point, cannot fail + for(j=0;jm_Entities->GetCount();j++) + { + lpent=(mc_TxEntityStat*)import->m_Entities->GetRow(j); + pEF->STR_SetSyncFlag(&(lpent->m_Entity),true); + } j=0; for(i=0;iGetCount();i++) { @@ -3220,14 +3294,19 @@ int mc_TxDB::DropImport(mc_TxImport *import) { char msg[256]; int err; - int j,commit_required; + int j,commit_required,value_len,i; uint32_t pos; mc_TxImportRow edbImport; mc_TxEntityStat *lpent; mc_TxEntityRow erow; + mc_TxEntityRow subkey_erow; + unsigned char stream_subkey_hash160[20]; + unsigned char *ptr; + int subkey_list_size,deleted_items; Dump("Before DropImport"); + deleted_items=0; err=MC_ERR_NOERROR; for(j=0;jm_Entities->GetCount();j++) @@ -3276,6 +3355,40 @@ int mc_TxDB::DropImport(mc_TxImport *import) erow.m_Generation=lpent->m_Generation; erow.m_Pos=pos; erow.SwapPosBytes(); + switch(lpent->m_Entity.m_EntityType & MC_TET_TYPE_MASK) + { + case MC_TET_STREAM_KEY: + case MC_TET_STREAM_PUBLISHER: + ptr=(unsigned char*)m_Database->m_DB->Read((char*)&erow+m_Database->m_KeyOffset,m_Database->m_KeySize,&value_len,0,&err); + if(err == MC_ERR_NOERROR) + { + if(ptr) + { + memcpy((char*)&erow+m_Database->m_ValueOffset,ptr,m_Database->m_ValueSize); + } + mc_GetCompoundHash160(&stream_subkey_hash160,&(erow.m_Entity.m_EntityID),erow.m_TxId); + subkey_erow.Zero(); + memcpy(subkey_erow.m_Entity.m_EntityID,&stream_subkey_hash160,MC_TDB_ENTITY_ID_SIZE); + subkey_erow.m_Entity.m_EntityType=lpent->m_Entity.m_EntityType | MC_TET_SUBKEY; + subkey_erow.m_Generation=erow.m_Generation; + GetListSize(&(subkey_erow.m_Entity),subkey_erow.m_Generation,&subkey_list_size); + for(i=0;im_DB->Delete((char*)&subkey_erow+m_Database->m_KeyOffset,m_Database->m_KeySize,MC_OPT_DB_DATABASE_TRANSACTIONAL); + subkey_erow.SwapPosBytes(); + deleted_items++; + if(deleted_items >= 1000) + { + m_Database->m_DB->Commit(MC_OPT_DB_DATABASE_TRANSACTIONAL); + deleted_items=0; + } + } + } + break; + } m_Database->m_DB->Delete((char*)&erow+m_Database->m_KeyOffset,m_Database->m_KeySize,MC_OPT_DB_DATABASE_TRANSACTIONAL); erow.SwapPosBytes(); commit_required=1; diff --git a/src/wallet/wallettxdb.h b/src/wallet/wallettxdb.h index 68e0c7a0..4754f9a5 100644 --- a/src/wallet/wallettxdb.h +++ b/src/wallet/wallettxdb.h @@ -37,12 +37,14 @@ #define MC_TET_CHAINPOS 0x00000100 #define MC_TET_TIMERECEIVED 0x00000200 #define MC_TET_ORDERMASK 0x0000FF00 +#define MC_TET_RESERVEDMASK 0x00FF0000 #define MC_TET_DB_STAT 0x01000000 #define MC_TET_IMPORT 0x02000000 #define MC_TET_DELETED 0x04000000 #define MC_TET_GETDB_ADD_TX 0x10000000 #define MC_TET_SPECIALMASK 0xFF000000 +#define MC_EFL_RESERVEDMASK 0x00FF0000 #define MC_EFL_NOT_IN_SYNC 0x01000000 #define MC_EFL_NOT_IN_SYNC_AFTER_IMPORT 0x02000000 #define MC_EFL_UNSUBSCRIBED 0x10000000 @@ -382,7 +384,9 @@ typedef struct mc_TxDB int RollBack(mc_TxImport *import,int block); // Rollback to specific block int Unsubscribe(mc_Buffer *lpEntities); // List of the entities to unsubscribe from - + + int TransferSubKey(mc_TxEntityStat *lpChainEntStat,const mc_TxEntityRow& erow,int slot); + mc_TxImport *StartImport( // Starts new import mc_Buffer *lpEntities, // List of entities to import int block, // Star from this block