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/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 fee66849..16c6bf2c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,7 +51,6 @@ EXTRA_LIBRARIES = \ libbitcoin_util.a \ libbitcoin_common.a \ univalue/libbitcoin_univalue.a \ - libbitcoin_enterprise.a \ libbitcoin_server.a \ libbitcoin_cli.a if ENABLE_WALLET @@ -180,8 +179,10 @@ obj/build.h: FORCE libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h if ENABLE_ENTERPRISE --include enterprise/Makefile.am +EXTRA_LIBRARIES += libbitcoin_enterprise.a +include entMakefile.am else +EXTRA_LIBRARIES += libbitcoin_enterprise.a libbitcoin_enterprise_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_enterprise_a_SOURCES = \ community/community.cpp \ @@ -471,11 +472,11 @@ libbitcoin_v8_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(V8_INCLUDE) # multichaind binary # multichaind_LDADD = \ - $(LIBBITCOIN_ENTERPRISE) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_ENTERPRISE) \ $(LIBBITCOIN_MULTICHAIN) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ @@ -515,11 +516,11 @@ endif # multichaind-cold binary # multichaind_cold_LDADD = \ - $(LIBBITCOIN_ENTERPRISE) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_ENTERPRISE) \ $(LIBBITCOIN_MULTICHAIN) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ diff --git a/src/chainparams/state.h b/src/chainparams/state.h index a3bdb54a..73477bb4 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() diff --git a/src/core/init-cold.cpp b/src/core/init-cold.cpp index 8528d5ea..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"); diff --git a/src/core/init.cpp b/src/core/init.cpp index 47bb1ffe..16326b55 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -216,9 +216,9 @@ void Shutdown() if (pwalletMain) bitdbwrap.Flush(true); #endif -#ifndef WIN32 +//#ifndef WIN32 boost::filesystem::remove(GetPidFile()); -#endif +//#endif UnregisterAllValidationInterfaces(); #ifdef ENABLE_WALLET delete pwalletMain; @@ -463,6 +463,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"; @@ -938,9 +939,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"); 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/multichain/multichaind-cold.cpp b/src/multichain/multichaind-cold.cpp index 60337143..c1037f19 100644 --- a/src/multichain/multichaind-cold.cpp +++ b/src/multichain/multichaind-cold.cpp @@ -54,6 +54,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 +115,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 a1f02c28..5eaabf35 100644 --- a/src/multichain/multichaind.cpp +++ b/src/multichain/multichaind.cpp @@ -54,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 @@ -103,6 +117,11 @@ bool AppInit(int argc, char* argv[]) 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)) @@ -111,11 +130,11 @@ bool AppInit(int argc, char* argv[]) delete mc_gState; return false; } - + string edition=pEF->ENT_Edition(); if(edition.size()) { - edition=", "+edition+" Edition"; + edition=edition+" Edition, "; } @@ -127,7 +146,7 @@ bool AppInit(int argc, char* argv[]) mc_gState->m_Params->HasOption("-version") || (mc_gState->m_Params->NetworkName() == NULL)) { - fprintf(stdout,"\nMultiChain %s Daemon%s (protocol %s)\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str(),edition.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")) { @@ -150,7 +169,7 @@ bool AppInit(int argc, char* argv[]) if(!GetBoolArg("-shortoutput", false)) { - fprintf(stdout,"\nMultiChain %s Daemon%s (latest protocol %d)\n\n",mc_BuildDescription(mc_gState->GetNumericVersion()).c_str(),edition.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; @@ -217,6 +236,9 @@ bool AppInit(int argc, char* argv[]) mc_gState->m_Params->Parse(argc, argv, MC_ETP_DAEMON); mc_CheckDataDirInConfFile(); + + pEF=new mc_EnterpriseFeatures; + pEF->Initialize(mc_gState->m_Params->NetworkName(),0); } #endif diff --git a/src/permissions/permission.cpp b/src/permissions/permission.cpp index cd1c8696..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(); diff --git a/src/rpc/rpcclient.cpp b/src/rpc/rpcclient.cpp index 341774b8..5a9e9343 100644 --- a/src/rpc/rpcclient.cpp +++ b/src/rpc/rpcclient.cpp @@ -201,6 +201,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "gettxoutdata", 1 }, { "gettxoutdata", 2 }, { "gettxoutdata", 3 }, + { "txouttobinarycache", 2 }, + { "txouttobinarycache", 3 }, + { "txouttobinarycache", 4 }, { "liststreamkeys", 1 }, { "liststreamkeys", 2 }, { "liststreamkeys", 3 }, diff --git a/src/rpc/rpchelp.cpp b/src/rpc/rpchelp.cpp index d1e9ed3e..3638c961 100644 --- a/src/rpc/rpchelp.cpp +++ b/src/rpc/rpchelp.cpp @@ -4636,6 +4636,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/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 e62c176a..828dd49d 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -839,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 33afd2e4..c44504d2 100644 --- a/src/rpc/rpcserver.h +++ b/src/rpc/rpcserver.h @@ -279,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/rpcutils.cpp b/src/rpc/rpcutils.cpp index 97b163f4..4c826a41 100644 --- a/src/rpc/rpcutils.cpp +++ b/src/rpc/rpcutils.cpp @@ -1187,7 +1187,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 +1215,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 +1236,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; } } 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/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/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/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/wallettxdb.cpp b/src/wallet/wallettxdb.cpp index b76473c3..b93ae6b1 100644 --- a/src/wallet/wallettxdb.cpp +++ b/src/wallet/wallettxdb.cpp @@ -296,6 +296,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 +313,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);