主页 > 以太坊钱包imtoken官网 > 以太坊是矿池源码选择以太坊矿池
以太坊是矿池源码选择以太坊矿池
目前的以太坊公链平均每秒可以处理30到40笔交易,所以以太坊一旦出现流行的DAPP,很容易出现交易拥堵。
交易处理速度之低,永远无法与现有的中心化服务相提并论。 当网络中有大量交易排队时,矿工如何选择和管理这些交易? 答案就在本文介绍的以太坊交易池中。
交易流程
当你通过以太坊钱包向张三发送转账交易时。 这笔交易是如何进入网络并最终被矿工包含在一个区块中的?
下图展示了一笔交易从诞生到进入区块的关键过程。
首先,用户可以通过以太坊钱包或其他对以太坊节点 API 的调用(on 等)向正在运行的以太坊 geth 节点发送交易。
此时,由于交易是通过节点的API接收的,因此该交易被视为本地交易(图中红球所示),并进行一系列的校验处理。 交易成功进入交易池,然后发送到连接的邻居节点。
当相邻节点(如矿工节点)从相邻节点收到这笔交易时,才进入交易池。 交易将被标记为远程(在图中用绿色球表示)。 在进入矿工节点的交易池,等待矿工打包入块之前,以太坊是矿池的源代码,需要进行检查和处理。
相邻节点是否是矿工并不重要。 因为默认情况下,任何节点都会及时将收到的合法交易发送给相邻节点。 得益于P2P网络,一笔交易平均在6秒内传遍整个以太坊公链网络的每一个节点。
区分进入以太坊交易池的本地交易和远程交易的目的是让节点区别对待本地交易和远程交易。 简单地说,本地事务比远程事务具有更高的优先级。
以太坊交易池设计
上面没有提到交易池处理细节。 这里Ethereum是矿池的源代码,下面会详细讲解以太坊交易池处理交易的完整过程。 在讲解之前,你还需要了解一下以太坊交易池的设计模型。 自 2014 年以来,以太坊的交易池一直在不断优化,没有中断。 从这里也可以看出,交易池不仅重要,而且对性能的要求也很高。
下图展示了以太坊交易池的主要设计模块,分别是交易池配置、实时区块链状态、交易管理容器、本地交易存储、新增交易事件。
各个模块相互影响,其中最重要的是事务管理。 这也是我们需要关注的部分。
交易池配置
交易池的配置不多,但是每一个配置都直接影响交易池的交易处理行为。 配置信息由以下信息定义:
// core/tx_pool.go:125
type TxPoolConfig struct {
Locals []common.Address
NoLocals bool
Journal string
Rejournal time.Duration
PriceLimit uint64
PriceBump uint64
AccountSlots uint64
GlobalSlots uint64
AccountQueue uint64
GlobalQueue uint64
Lifetime time.Duration
}
在上面的配置中,有两个重要的概念可执行事务和不可执行事务。 可执行交易是指从交易池中选出的一部分可以执行并打包成区块的交易。 另一方面,不可执行交易则相反。 任何刚进入交易池的交易都处于不可执行状态以太坊矿池d池,并会在某个时刻升级为可执行状态。
节点如何自定义上述交易配置? 以太坊geth节点允许在启动节点时通过参数修改配置。 可修改的交易池配置参数如下(geth -h查看):
TRANSACTION POOL OPTIONS:
--txpool.locals value Comma separated accounts to treat as locals (no flush, priority inclusion)
--txpool.nolocals Disables price exemptions for locally submitted transactions
--txpool.journal value Disk journal for local transaction to survive node restarts (default: "transactions.rlp")
--txpool.rejournal value Time interval to regenerate the local transaction journal (default: 1h0m0s)
--txpool.pricelimit value Minimum gas price limit to enforce for acceptance into the pool (default: 1)
--txpool.pricebump value Price bump percentage to replace an already existing transaction (default: 10)
--txpool.accountslots value Minimum number of executable transaction slots guaranteed per account (default: 16)
--txpool.globalslots value Maximum number of executable transaction slots for all accounts (default: 4096)
--txpool.accountqueue value Maximum number of non-executable transaction slots permitted per account (default: 64)
--txpool.globalqueue value Maximum number of non-executable transaction slots for all accounts (default: 1024)
--txpool.lifetime value Maximum amount of time non-executable transaction are queued (default: 3h0m0s)
链状态
所有进入交易池的交易都需要经过验证。 最基本的是验证账户余额是否足以支付交易执行费用。 或者交易随机数是否合法。 交易池中维护的最新区块StateDB。 当交易池收到新的区块信号时,会立即重置。
交易池启动后,会订阅链的区块头事件:
//core/tx_pool.go:274
pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh)
并开始监听新事件:
//core/tx_pool.go:305
for {
select {
// Handle ChainHeadEvent
case ev := <-pool.chainHeadCh:
if ev.Block != nil {
pool.mu.Lock()
if pool.chainconfig.IsHomestead(ev.Block.Number()) {
pool.homestead = true
}
pool.reset(head.Header(), ev.Block.Header())
head = ev.Block
pool.mu.Unlock()
}
//...
}
}
收到事件后,会执行func(pool *TxPool) reset(oldHead, newHead *types.Header)方法更新状态,处理交易。核心是删除交易中不符合要求的交易汇集和更新交易
地方事务
在交易池中将交易标记为本地交易有多种用途:
将发送的交易存储在本地磁盘上。 这样本地交易不会丢失,并且可以在节点重启时重新加载到交易池中实时广播。 它可以作为外部程序与以太坊通信的通道。 外部程序只需要监听文件内容的变化就可以获取交易列表。 本地事务可以优先于远程事务。 限制交易量等操作不会影响本地下的账户和交易。
对应本地交易存储,在启动交易池时根据配置开启本地交易存储能力:
//core/tx_pool.go:264
if !config.NoLocals && config.Journal != "" {
pool.journal = newTxJournal(config.Journal)
if err := pool.journal.load(pool.AddLocals); err != nil {
log.Warn("Failed to load transaction journal", "err", err)
}
//...
}
并将现有交易从磁盘加载到交易池中。 当一个新的本地交易进入交易池时,实时写入日志文件。
// core/tx_pool.go:757
func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) {
if pool.journal == nil || !pool.locals.contains(from) {
return
}
if err := pool.journal.insert(tx); err != nil {
log.Warn("Failed to journal local transaction", "err", err)
}
}
如上所示,只会记录属于本地账户的交易。 如果是这种情况,您是否注意到日志文件会随着本地事务无限增长? 答案是否定的,尽管不能实时从日志中删除事务。 但是,支持定期更新日志文件。
日志不保存所有的本地交易和历史,它只保存当前交易池中存在的本地交易。 因此,交易池会周期性地轮换日志文件,将交易池中的本地交易写入日志文件,并丢弃旧数据。
journal := time.NewTicker(pool.config.Rejournal)
//...
//core/tx_pool.go:353
case <-journal.C:
if pool.journal != nil {
pool.mu.Lock()
if err := pool.journal.rotate(pool.local()); err != nil {
log.Warn("Failed to rotate local tx journal", "err", err)
}
pool.mu.Unlock()
}
}
新的交易信号
如文章开头所述,进入交易池的交易将被广播到网络中。 这依赖于交易池来支持外部订阅新的交易事件信号。 任何订阅该事件的子模块都可以实时收到事件通知,并在交易池中出现新的可执行交易时获取新的交易信息。
需要注意的是以太坊矿池d池,并不是所有进入交易池的交易都会被通知到外部,只有当交易从不可执行状态变为可执行状态时才会发送信号。
//core/tx_pool.go:705
go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}})
//core/tx_pool.go:1022
go pool.txFeed.Send(NewTxsEvent{promoted})
在交易池中,有两个地方执行信号。 一种是用事务替换现有的可执行事务。 第二个是在新一批交易从不可执行状态升级到可执行状态之后。