AppInitMain() 부터 시작. - init.cpp 참고
bool AppInitMain()
{
// 이전 포스팅에서 "-regtest", "-testnet" 의 설정 여부에 따른 globalChainParams 에서 현재 Chain 에 대한
// 정보를 획득! (chainparams.cpp 참고 - 이 곳에 각 Chain 의 정보들이 기술되어 있으니 한번씩 읽어 볼 것.)
const CChainParams& chainparams = Params();
// ********************************************************* Step 4a: application initialization
#ifndef WIN32
// GetPidFile(): "-pid" 설정값이 존재한다면 그 값을 사용하여 pid file 의 절대 경로를 생성.
// 그렇지 않다면, default 로 bitcoind.pid 를 이용하여 pid file 의 절대 경로를 생성.
// = data directory + "/" + net + "/" + filename
// getpid(): 현재 프로세스의 id 를 구해옴.
//
// 파일을 생성 후 해당 파일에 현재 process id 를 저장.
CreatePidFile(GetPidFile(), getpid());
#endif
// 전역 logger 설정에 로깅을 파일로도 하라는 설정이 turn on 되어 있다면..
// https://steemit.com/understanding/@jayson.jeong/bitcoind-source-1 참고.
if (g_logger->m_print_to_file) {
// "-shrinkdebugfile=1" 설정되어 있거나 설정되어 있지 않더라도 logging category 가 NONE 이라면,
if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) {
// Do this first since it both loads a bunch of debug.log into memory,
// and because this needs to happen before any other debug.log printing
// 현재 소스상 파일의 크기가 약 11MB 보다 클 경우, 가장 최근 10MB 정도 로그를 포함한 파일의 크기로 trimming.
g_logger->ShrinkDebugFile();
}
// 해당 파일을 일단 append mode 로 오픈하고, 작업 중 발생했던 로그들을 모아뒀던 버퍼에서 로그들을 꺼내서
// 이 파일에 쓴다.
if (!g_logger->OpenDebugLog()) {
return InitError(strprintf("Could not open debug log file %s",
g_logger->m_file_path.string()));
}
}
// 전역 logger 의 설정 중 m_log_timestamps 이 turn on 되어 있지 않다면..
if (!g_logger->m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
// 현재 설정에서 정보성 내용들을 출력!
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", GetDataDir().string());
LogPrintf("Using config file %s\n", GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
// Warn about relative -datadir path.
// "-datadir" 설정 값이 절대 경로가 아니라면... 아래의 경고 메세지 출력...
if (gArgs.IsArgSet("-datadir") && !fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) {
LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
"current working directory '%s'. This is fragile, because if bitcoin is started in the future "
"from a different location, it will be unable to locate the current data files. There could "
"also be data loss if bitcoin is started while in a temporary directory.\n",
gArgs.GetArg("-datadir", ""), fs::current_path().string());
}
// SignatureCache(모든 트랜잭션에 ECDSA 를 두번 체크하는 것을 막기 위한 캐시) 초기화. - script/sigcache.cpp 참고
// - mempool 에 저장될 때 한번, block chain 에 저장될 때 또 한번. 총 2번.
// SignatureCache 는 내부적으로 CuckooCache 를 사용하는데 관련 소스는 cuckoocache.cpp, cuckoocache.h 참고
InitSignatureCache();
// 이 부분도 위와 동일한 이유로 사용되는 캐쉬
// 내부적으로 CuckooCache 를 사용하는 것도 동일.
InitScriptExecutionCache();
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
for (int i=0; i<nScriptCheckThreads-1; i++)
// boost::thread_group
// *worker* 쓰레드 하나 생성. 이름은 "bitcoin-scriptch"
// 이 *worker* 쓰레드는 CScriptCheck (하나의 script verification 을 나타내는 closure) 작업들이 쌓인
// 큐(CCheckQueue)에서 작업들이 들어오길 기다리고 있다가 작업이 들어오면 큐에서 꺼내서 CScriptCheck 의
// operator()() 메소드(validation.cpp 참고) 를 수행. - 결국 해당 트랜잭션의 scriptSig 와 scriptPubKey 검증.
// 검증 로직은 script/interpreter.cpp 의 VerifyScript() 참고.
// - CScriptCheck 는 validation.cpp 와 validation.h 참고
// - CCheckQueue 는 checkqueue.cpp 와 checkqueue.h 참고
threadGroup.create_thread(&ThreadScriptCheck);
}
// Start the lightweight task scheduler thread
// serviceLoop 는 &scheduler 인스턴스를 &CScheduler::serviceQueue 함수에 this pointer로 바인딩한 함수.
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
// TraceThread 라는 함수에 인자로 "scheduler"와, serviceLoop 를 바인딩 시킨 후 쓰레드를 생성해서 수행.
// "bitcoin-scheduler" 라는 이름으로 쓰레드의 이름을 변경하고 serviceLoop() 를 실행.
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
// serviceLoop() 의 대략적인 내용은 다음과 같다.
// 작업 큐의 타입은 std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue; 로서
// - boost::chrono::system_clock::time_point 순으로 정렬되어 있고 multi value (Function) 을 저장할 수 있다.
// 역시 작업 큐에 작업이 있을 때까지 또는 첫번째 작업의 실행시점이 될 때까지 기다렸다가 실행할 작업이 생기면
// 꺼내서 Function 에 해당 하는 녀석을 실행.
// static CMainSignals g_signals;
// g_signals 의 내부에는 MainSignalsInstance 에 접근할 수 있는 포인터가 존재
// MainSignalsInstance 는 UpdatedBlockTip/TransactionAddedToMempool/BlockConnected/BlockDisconnected
// /TransactionRemovedFromMempool/ChainStateFlushed/Inventory/Broadcast/BlockChecked/NewPoWValidBlock
// 등의 이벤트가 발생할 때 실행할 callback 함수들을 등록할 수 있다.
// g_signals 는 이 MainSignalsInstance 에 접근할 수 있는 통로(인터페이스)의 역할을 한다.
// (소스 코드는 validationinterface.cpp 참고.)
// 전역 변수 g_signals 에 접근할 수 있는 함수 GetMainSignals()
// 새로운 MainSignalsInstance 를 생성하면서 관련 callback 함수들을 실행할 schduler 인스턴스도 함께 전달.
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
// CTxMemPool (txmempool.h 참고) 에서 감지할 수 있는 NotifyEntryRemoved 이벤트에
// 대한 callback 함수(&CMainSignals::MempoolEntryRemoved) 를 등록한다.
// (역시 소스 코드는 validationinterface.cpp 참고)
GetMainSignals().RegisterWithMempoolSignals(mempool);
/* Register RPC commands regardless of -server setting so they will be
* available in the GUI RPC console even if external calls are disabled.
*/
// CRPCTable tableRPC 인스턴스에 모든 core rpc command 와 handler 들을 등록.
//
// CRPCTable(소스 코드는 rpc/server.h 와 rpc/server.cpp 참고) 는 내부적으로
// std::map<std::string, const CRPCCommand *> mapCommands; 타입의 매핑 테이블을 가지고 있음.
// CRPCCommand(소스 코드는 rcp/server.h 참고) 는 내부적으로
// typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest); 타입의 함수 포인터를 저장함으로써
// 대응되는 커맨드에 대한 실행 함수 매핑을 유지하는 형태.
//
// 차례대로 아래의 함수들이 호출되며 소스 코드 내에서 각각의 함수 상위에 관련 테이블 코드가 존재.
// 각각의 커맨드에 대해서 어떤 함수들이 호출될 지 쉽게 볼 수 있음.
// RegisterBlockchainRPCCommands() - 소스 코드는 rpc/blockchain.cpp 참고
// RegisterNetRPCCommands() - 소스 코드는 rpc/net.cpp 참고
// RegisterMiscRPCCommands() - 소스 코드는 rpc/misc.cpp 참고
// RegisterMiningRPCCommands() - 소스 코드는 rpc/mining.cpp 참고
// RegisterMiningRPCCommands() - 소스 코드는 rpc/rawtransaction.cpp 참고.
// 각 rpc command 의 세부 동작은 추후 포스팅에서 진행해보도록 하자.
RegisterAllCoreRPCCommands(tableRPC);
// "-disablewallet" 설정이 존재한다면 단순 리턴.
// 그렇지 않다면, 여기서는 RegisterWalletRPCCommands() 가 호출됨. - 소스 코드는 wallet/rpcwallet.cpp 참고.
g_wallet_init_interface.RegisterRPC(tableRPC);
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
* that the server is there and will be ready later). Warmup mode will
* be disabled when initialisation is finished.
*/
// "-server" 설정이 존재한다면...
if (gArgs.GetBoolArg("-server", false))
{
// 이전 포스팅에 언급되었던 CClientUIInterface uiInterface 의 InitMessage callback 에
// SetRPCWarmupStatus 함수도 등록한다 (rcp/server.cpp 참고)
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
// static struct CRPCSignals g_rpcSignals (rpc/server.cpp 참고) 에
// OnStarted 이벤트 발생시 호출될 callback &OnRPCStarted(init.cpp 참고) 등록
// - uiInterface.NotifyBlockTip 이벤트에 &RPCNotifyBlockChange 등록
// OnStopped 이벤트 발생시 호출될 callback &OnRPCStopped(init.cpp 참고) 등록
// - uiInterface.NotifyBlockTip 이벤트에 등록된 &RPCNotifyBlockChange reset 및 RPCNotifyBlockChange(false, nullptr) 호출.
// InitHttpServer() 호출
// - http 요청에 대한 access control list 초기화
// - "-rpcssl" 이 설정되어 있는 경우, error. (Not Supported!)
// - 관련하여 libevent 관련 초기화 후, address binding 후 요청을 받아들일 수 있는 준비까지 완료.
// - rpc 요청에 대한 work queue 관련 구조체 초기화 (WorkQueue<HttpClosure> - httpserver.cpp 및 httpserver.h 참고)
// StartRPC() 호출
// - g_rpcSignals.Started() 호출. -> OnStarted 이벤트시에 호출될 callback 들 모두 호출.
// StartHTTPRPC() 호출.
// - "-rpcpassword" 가 설정되어 있지 않을 경우, random cookie authentication 을 사용하거나 설정되어 있을 경우
// "-rpcuser" : "-rpcpassword" 형태의 authentication 문자열 생성.
// - "/" 에 HTTPReq_JSONRPC handler 등록(httprpc.cpp 참고) - 정확하게 일치해야 호출.
// - "/wallet/" 에 역시 HTTPReq_JSONRPC handler 등록 - prefix 만 일치해도 호출.
// "-rest" 설정이 되어 있다면, StartRest() 호출 - rest.cpp 참고. /rest/xxx 에 대한 핸들러들 등록.
// StartHttpServer() 호출.
// - "bitcoin-http" 라는 event dispatcher thread 생성. 상위에서 생성한 work queue 에 작업 등록.
// - "-rpcthreads" 수 만큼 "bitcoin-httpworker" 라는 worker thread 생성. work queue 에 등록된 작업을 꺼내서 처리.
if (!AppInitServers())
return InitError(_("Unable to start HTTP server. See debug log for details."));
}
int64_t nStart;
// ********************************************************* Step 5: verify wallet database integrity
// --enable-wallet 으로 컴파일된 경우, wallet database 의 integrity 를 점검한다.
// g_wallet_init_interface 는 https://steemit.com/understanding/@jayson.jeong/bitcoind-source-2 에서
// 초기화 관련 언급을 하였음. 관련된 소스는 wallet/init.cpp 를 참고
// 참고로 wallet database 는 leveldb 가 아니라 berkeleydb 를 사용하는 듯. (wallet/db.cpp 참고)
if (!g_wallet_init_interface.Verify()) return false;
아직 관련 소스가 모두 끝난 상황은 아니지만 너무 많으니 여기까지만... 다음 포스팅에서 계속...
Congratulations @jayson.jeong! You received a personal award!
Click here to view your Board
Do not miss the last post from @steemitboard:
Vote for @Steemitboard as a witness and get one more award and increased upvotes!
Congratulations @jayson.jeong! You received a personal award!
You can view your badges on your Steem Board and compare to others on the Steem Ranking
Vote for @Steemitboard as a witness to get one more award and increased upvotes!