以太坊交易Nonce设置

以太坊交易Nonce设置1 什么是 nonce 以太坊中的 nonce 有两个意义 1 工作量证明 为了证明工作量的无意义的值 这是采矿的本质 这个值将决定采矿的难度 2 账户的随机数 在一个账户中的防止多重交易的用途 例如一个交易从 A 到 B20 个币 可能从 A 到 B 发送多次 为了防止交易的重播攻击 每笔交易必须有一个 nonce 随机数 针对每一个账户 nonce 都是从 0 开始 当 nonce 为 0 的交易处理完之后 才会处理 nonce 为 1 的

1 什么是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 }

追踪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 state replace, err := pool.add(tx, local) if err != nil { return err } // If we added a new transaction, run promotion checks and return if !replace { from, _ := types.Sender(pool.signer, tx) // already validated pool.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才会生效。




版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/213177.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午6:23
下一篇 2026年3月18日 下午6:24


相关推荐

  • WES7下载_影音先锋下载

    WES7下载_影音先锋下载WES7(WindowsEmbeddedStandard7)是微软在2010年5月13日发布的基于X86平台,Windows7组件化的嵌入式操作系统。WES7除了具有Windows7最新的功能外,还具

    2022年8月1日
    9
  • Eclipse SVN历史乱码问题

    Eclipse SVN历史乱码问题eclipse 默认编码格式为 GBK nbsp 将其更改为 utf 8 即可

    2025年8月21日
    5
  • C++ nullptr

    c++nullptr

    2022年4月6日
    44
  • clion 激活码 下载(最新序列号破解)

    clion 激活码 下载(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
    49
  • 如果我说熟悉SpringBoot 面试官会怎么问?

    如果我说熟悉SpringBoot 面试官会怎么问?SpringBoot因简化了Spring框架使用难度,极大地提高了Java企业级应用开发的效率,成为企业考核人才的重要标准之一。但随着现今互联网行业快速发展、企业业务不断深入,相应地对SpringBoot技术要求也愈来愈高。春节时期有一位打算金三银四面试的读者私信问我:如果我说熟悉SpringBoot面试官会怎么问?​可能不少朋友跟他一样,不清楚当下企业真实生产环境下对SpringBoot有哪些具体要求,需要掌握到什么程度。为此,结合这些年的面试经历及各大厂的职位要求,给

    2022年6月5日
    29
  • STM32F103C8T6单片机简介

    STM32F103C8T6单片机简介TheSTM32F103xxmedium-densityperformancelinefamilyincorporatesthehigh-performanceARMCortex-M332-bitRISCcoreoperatingata72MHzfrequency,high-speedembeddedmemories(Flashmemoryupto128KbytesandSRAMupto20Kbytes),andanextensive

    2022年4月25日
    123

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号