以太坊交易Nonce设置
1 什么是nonce?
以太坊中的nonce有两个意义:
1.工作量证明:为了证明工作量的无意义的值,这是采矿的本质,这个值将决定采矿的难度,
2.账户的随机数:在一个账户中的防止多重交易的用途。例如一个交易从A到B 20个币,可能从A到B发送多次。
为了防止交易的重播攻击,每笔交易必须有一个nonce随机数,针对每一个账户nonce都是从0开始,当nonce为0的交易处理完之后,才会处理nonce为1的交易,并依次加1的交易才会被处理。以下是nonce使用的几条规则:
- 当nonce太小,交易会被直接拒绝。
- 当nonce太大,交易会一直处于队列之中,这也就是导致我们上面描述的问题的原因;
- 当发送一个比较大的nonce值,然后补齐开始nonce到那个值之间的nonce,那么交易依旧可以被执行。
- 当交易处于queue中时停止geth客户端,那么交易queue中的交易会被清除掉。
2 以太坊源码中关于Nonce的解读
以太坊在geth的console端使用eth.sendTransaction({from:addr1,to:addr2,value:money})的形式来转账ether的时候,会通过RPC调用到/ethapi/api.go中的函数SendTransaction():
// SendTransaction will create a transaction from the given arguments and
// tries to sign it with the key associated with args.To. If the given passwd isn't
// able to decrypt the key it fails.
func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) {if args.Nonce == nil {// Hold the addresse's mutex around signing to prevent concurrent assignment of// the same nonce to multiple accounts.s.nonceLock.LockAddr(args.From)defer s.nonceLock.UnlockAddr(args.From)}signed, err := s.signTransaction(ctx, args, passwd)if err != nil {return common.Hash{}, err}return submitTransaction(ctx, s.b, signed)
}
sendTransaction()继续调用submitTransaction()函数来执行交易:
// submitTransaction is a helper function that submits tx to txPool and logs a message.
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {if err := b.SendTx(ctx, tx); err != nil {return common.Hash{}, err}if tx.To() == nil {signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())from, err := types.Sender(signer, tx)if err != nil {return common.Hash{}, err}addr := crypto.CreateAddress(from, tx.Nonce())log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())} else {log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())}return tx.Hash(), nil
}
submitTransaction()在sendTx()函数中发送交易。然后在判断交易地址是否为空,为空的则是创建合约的交易。
追踪sendTx()函数到/core/tx_pool.go中的addTx()函数,原来是通过addTx()将交易添加到交易池。
func (pool *TxPool) addTx(tx *types.Transaction, local bool) error {pool.mu.Lock()defer pool.mu.Unlock()// Try to inject the transaction and update any statereplace, err := pool.add(tx, local)if err != nil {return err}// If we added a new transaction, run promotion checks and returnif !replace {from, _ := types.Sender(pool.signer, tx) // already validatedpool.promoteExecutables([]common.Address{from})}return nil
}
addTx()首先调用add()将交易添加到交易池pool,如果成功,则调用promoteExecutables()函数去执行交易。promoteExecutables()函数关键代码是:
// Gather all executable transactions and promote them
for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) {hash := tx.Hash()log.Trace("Promoting queued transaction", "hash", hash)pool.promoteTx(addr, hash, tx)log.Info("lzj log:","hash",hash,"Nonce",pool.pendingState.GetNonce(addr))
}
这段代码收集所有可执行交易并且执行它们。pool.pendingState.GetNonce(addr)得到和地址addr相关的nonce范围N,N等于len(addr.nonces)) + addr.nstart,其实等于该地址已经发送成功的交易个数。list.Ready()函数将返回一个交易集合,这个集合中的所有交易都要求满足nonce不大于N。只有Nonce满足要求的交易才会被处理,就是通过pool.promoteTx(addr, hash, tx)执行交易。
3 Web3j等RPC方式设置Nonce的正确方式
一般的通过Web3j发起以太坊交易的方法是:
Transaction.createEtherTransaction(from,nonce,gasPrice,gasLimit,to,value);
其中的nonce得到方式是:
EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(from, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
通过取得当前该账户发起过的交易次数,并设其为当前交易的Nonce值。
如果要在for循环里同时发起多笔交易,因为当前交易尚没有被处理成功,所以通过上述方法得到的Nonce将会与上一次交易的Nonce相同,如果这笔交易的Gas比上次交易大,则会替换上次交易,否则将会报如下错误:
transaction failed,info:replacement transaction underpriced
解决这个问题的方法是自己维护Nonce,同一个账户连续发送俩笔交易时,通过递增Nonce来防止Nonce重复。
此种方案也有限制条件。第一,由于nonce统一进行维护,那么这个地址必须是内部地址,而且发起交易必须通过统一维护的nonce作为出口,否则在其他地方发起交易,原有维护的nonce将会出现混乱。第二,一旦已经发出的交易发生异常,异常交易的nonce未被使用,那么异常交易的nonce需要重新被使用之后它后面的nonce才会生效。
以太坊交易Nonce设置相关推荐
- 以太坊交易中的nonce和confirmation
1. 以太坊交易中的nonce及其价值 1.1 以太坊交易中的nonce值 在以太坊中,每笔交易都有一个nonce值,该nonce值代表的是从该交易发起地址发出的交易数.(当存在使用同一地址从多个客户 ...
- 一文讲清楚以太坊的nonce
续上篇:一文讲清楚以太坊的gas,gasPrice,gasLimit 我们今天来讲讲以太坊的nonce.做过钱包开发的同学都应该知道,nonce是一个非常关键的参数.对于一般用户来说,各种钱包已经帮我 ...
- 以太坊交易信息及event、input、logs、topics等概念机制
文章目录 一.交易信息获取 1.1 合约事件例子定义 1.2 以太坊交易获取 二.input解析 2.1 input内容解析 2.2 input处理逻辑 三.logs解析 3.1 logs解析代码 四 ...
- 观点:以太坊交易费市场泡沫预警,交易费日渐成为用户难以承受之重
在经历了一次大熊市之后,以太坊已经再次流行起来.受包括 ETH 价格反弹以及所谓"去中心化金融"(DeFi)的采用等因素的综合影响,以太坊区块链的活跃用户和日交易量都出现了强力增长 ...
- 区块链 以太坊 交易结构、执行、存储 解析 交易中为什么没有包含发送者地址这条数据
一. 交易的结构 1. Transaction结构 交易结构定义在 core/types/transaction.go 中: type Transaction struct {//交易数据data t ...
- java如何监听以太坊交易
2019独角兽企业重金招聘Python工程师标准>>> 你可以在web3j库的帮助下使用java轻松监听以太坊交易,但此库无法监听Erc20 Token交易. 要监听Erc20Tok ...
- Infura Http 客户端 以太坊 交易
web3j Infura 模块提供了一个Infura Http 客户端(InfuraHttpService),它为Infura特定的Infura-Ethereum-Preferred-Client提供 ...
- 以太坊地址和公钥_以太坊交易签名解析源码解读
上篇文章<以太坊交易签名过程源码解析[1]>从源码角度分析了一个合约调用的的签名过程,签名后的交易发送到以太坊节点后,节点需要从签名交易中还原出公钥(从公钥中单向计算出账号地址),进而将交 ...
- Web3j通过合约地址监听transfer事件获取以太坊交易数据
Web3j通过合约地址监听transfer事件获取以太坊交易数据 We3j web3j是一个轻量级的Java库,用于在Ethereum网络上集成客户端(节点). 核心特性 通过Java类型的JSON- ...
最新文章
- 说说设计模式~组合模式(Composite)
- hostent结构体图解
- 集成电路883和883b有什么区别
- 阿里对大年龄清退的定义
- LVM逻辑卷详解及创建
- Orace用户创建及权限分配
- Tableview最后一行无法显示或者显示不全的问题IOS
- django中使用第三方包实现定时任务
- JavaScript学习笔记(四)
- Slideshow Maker for mac(幻灯片制作软件)
- Activity传递数据
- node 更新_更新应用时,如何实现 K8s 零中断滚动更新?
- 编译原理(紫龙书)第2版习题答案
- 《现代汉语》北大公开课
- python打印列表的下标和值的例子:
- mysql中用于删除数据的是什么意思_数据库删除语句delete有什么用?
- 外汇mt4 软件在哪里下载比较正规?
- kali2021安装百度网盘
- 2022-2028全球快餐肉汤食品行业调研及趋势分析报告
- UE4 Windows环境下游戏打包基础教程(ios, windows, android)(UFE方式以及命令行方式)