// 启动
ui CMyApp::OnInit()
ui CMyApp::OnInit2()
db CAddrDB::LoadAddresses() // 加载地址
db 加载用户自定义的地址 CAddress from addr.txt
db 再从 Berkeley DB addr.dat 中加载 CAddress
net AddAddress() // 添加地址
net 拒绝不能路由的地址(内网地址被判定为不能路由) // CAddress::IsRoutable
net 拒绝当前节点的地址 // 节点的地址 保存在 全局变量 addrLocalHost
net 保存到 全局变量 mapAddresses 中, key 是 IP + Port
main LoadBlockIndex // 加载区块
db CTxDB::LoadBlockIndex(); // key是"blockindex"+块hash
db 从 BerkeleyDB 中加载 到 全局变量 mapBlockIndex 中
main 如果 mapBlockIndex 为 empty, 说明 刚刚启动主链(狭义的,局部的,极有可能会被推翻的), 发起一个交易(无效的),并打包这个创世区块
db LoadWallet // 加载钱包
db CWalletDB::LoadWallet // 以键值对方式存储,
name为地址本, 存入 mapAddressBook
tx:钱包交易CWalletTx, 存入 mapWallet
key:公钥私钥对, 存入 mapKeys, mapPubKeys
defaultkey:当前用户公私钥对信息 存入 keyUser
setting: 是否挖矿, 交易费用, 外部IP+端口
main ReacceptWalletTransactions // 将不在块中的钱包交易放入到对应的内存交易对象 mapTransactions中
CTxDB::ContainsTx // key是"blockindex"+钱包交易hash
main CWalletTx::AcceptWalletTransaction
CMerkleTx::AcceptTransaction
CTransaction::AcceptTransaction
存入 mapTransactions(用于保存未打包的交易)
ui CMainFrame::show()
ui CMainFrame::CMainFrame()
net StartNode()
创建 tcp 监听socket
启动 ThreadIRCSeed // 聊天线程
启动 ThreadSocketHandler // socket监听线程
启动 ThreadOpenConnections // 连接其他node的线程
启动 ThreadMessageHandler // 消息处理线程
net ThreadBitcoinMiner // 启动挖矿线程
// 用于: 1:监听新进连接, 2: 处理vNode的 接收 和发送 缓冲区
ThreadSocketHandler
LOOP{
断开不使用的节点
accept 新连接(非阻塞), 存入 vNode
循环处理所有节点的 recv buffer 和 send buffer
}
// 用于不停的创建与其他节点的连接
ThreadOpenConnections
LOOP{
从 mapAddresses 加载所有地址, 排序分组
随机创建连接 存入 vNode
}
// 用于处理每一个节点上的消息, 与 ThreadSocketHandler 的分工是, 它处理消息逻辑, 会读取和写入 节点上的 recv buffer 和 send buffer, 而 由 ThreadSocketHandler 去完成 具体的 send 和 recv 函数调用
ThreadMessageHandler
LOOP vNode{
ProcessMessage 处理消息
version: 消息的版本
addr: 地址消息, 添加的本地地址簿中
inv: 库存(交易, 区块, review, product)消息: CInv 中只有类型和内容hash, 该消息用于告知别人我有啥, 收到消息的node查看自己是否有, 如果没有就将请求放入 对方节点 的 mapAskFor 中, 在后续的 SendMessage 中处理
getdata: // 有人找我要Block数据, 直接掉对方 CNode::PushMessage("block") 等待发送
getblocks:
tx: // 接受到了交易信息
review:
block:
getaddr:
checkorder:
submitorder:
reply:
SendMessages 发送消息
addr: 地址信息发送, 告诉别人我知道谁谁谁
inventory:
getdata: 遍历 节点 的 mapAskFor 发送 getdata 消息
}
// 挖矿
ThreadBitcoinMiner
LOOP{
根据最高的Block(即上一个Block)计算出本次挖矿的难度值
新建一个BaseCoin交易
新建一个Block, append 刚刚的BaseCoin交易
收集最新的交易放入区块中
LOOP 本地交易池 mapTransactions
{
根据交易系列化大小计算fee
本次打包拒绝fee太低的交易
}
计算满足难度的hash值
处理Block ::ProcessBlock
}
// 自己挖到, 或接手到
// 处理Block
::ProcessBlock
判断重复
校验合法 CBlock::CheckBlock
判断高度, 发起缺失的block的请求 CNode::PushMessage("getblocks")
接受存储改Block CBlock::AcceptBlock
RelayInventory // 转播库存, 告知被人我有了这个 Block (消息中只有Block的hash)
放入 每一个 vNode 的 vInventoryToSend, 等待 ThreadMessageHandler处理
递归处理依赖于此块的任何孤立块
// 转账, 注: 要求对方在线
CSendingDialog::StartTransfer()
判断余额
链接对方
向对方发送 checkorder 以询问对方是否接受交易并允许查看order内容
等待回复
CreateTransaction // 创建钱包交易
寻找自己的vOut
签名
CommitTransactionSpent // 提交交易
加入到钱包
标记 vOut 已经花掉了
CNode::PushRequest("submitorder") 确认一个order已经被提交
验证并接受交易, 存入 mapTransactions 中
ThreadRequestProductDetails
// 退出
ui CMyApp::OnExit()
ui ::Shutdown()
net ::StopNode()
等待所有线程退出
// 打印 Block tree
db CTxDB::LoadBlockIndex();
从 db 中加载出 CBlockIndex, 组织成 <块哈希, CBlockIndex*> 存入全景变量 mapBlockIndex 中
main PrintBlockTree();
// CBlockIndex 的 作用是 从本地的 blkxxxx.dat 文件中 索引出 CBlock 数据
CBlock::ReadFromDisk
// CBlockIndex 是 存在 Berkeley DB 中的, 其数据文件 blkindex.dat