使用eos-go交易过期问题修复

转载请注明:https://www.cnblogs.com/tkblack/p/12659826.html

前段时间,使用eos-go发交易进行测试,程序在我本机运行时是OK的,但是放到服务器运行就报错,提示错误: Internal Service Error: Expired Transaction。

看到这个报错提示,很明显的知道,交易过期了,也就是我们设置的交易过期时间小于当前时间。我看了下代码,实现如下(注意红色部分):

func (tx *Transaction) SetExpiration(in time.Duration) {
    tx.Expiration = JSONTime{time.Now().UTC().Add(in)}
}

具体设置过期时间如下红色部分:

func (tx *Transaction) Fill(headBlockID Checksum256, delaySecs, maxNetUsageWords uint32, maxCPUUsageMS uint8) {
    tx.setRefBlock(headBlockID)

    if tx.ContextFreeActions == nil {
        tx.ContextFreeActions = make([]*Action, 0, 0)
    }
    if tx.Extensions == nil {
        tx.Extensions = make([]*Extension, 0, 0)
    }

    tx.MaxNetUsageWords = Varuint32(maxNetUsageWords)
    tx.MaxCPUUsageMS = maxCPUUsageMS
    tx.DelaySec = Varuint32(delaySecs)

    tx.SetExpiration(30 * time.Second)
}

显然,过期时间在本地时间的基础上增加30秒,理论30秒足够了,但是程序中使用的是本地时间,因此,如果本地时间滞后超过30秒,就会出现过期错误。

解决这个问题也挺简单的,如果不想改代码,那直接调整本地时间就好了;当然也可以将过期时间设置长一点,比如设置为加300秒。

当然,这里还有一个方法,设置过期时间为链上返回的时间加30秒,也就是不用time.Now(),这样就不会受本地时间的影响而导致出现交易过期的错误。修改代码也比较简单:

(仅需修改transaction.go文件中的代码,绿色表示原来的代码,红色表示添加或修改的代码)

// transaction.go
//......(省略)
// NewTransaction creates a transaction. Unless you plan on adding HeadBlockID later, to be complete, opts should contain it. Sign func NewTransaction(actions []*Action, opts *TxOptions) *Transaction { if opts == nil { opts = &TxOptions{} } tx := &Transaction{Actions: actions}
/* modify by tkblack begin */ //tx.Fill(opts.HeadBlockID, opts.DelaySecs, opts.MaxNetUsageWords, opts.MaxCPUUsageMS) tx.Fill(opts.HeadBlockID, opts.DelaySecs, opts.MaxNetUsageWords, opts.MaxCPUUsageMS, opts.Expiration) /* modify by tkblack end */
return tx }
//......(省略)
func (tx *Transaction) Fill(headBlockID Checksum256, delaySecs, maxNetUsageWords uint32, maxCPUUsageMS uint8, expiration JSONTime) { 
  tx.setRefBlock(headBlockID)  
  
if tx.ContextFreeActions == nil {
    tx.ContextFreeActions
= make([]*Action, 0, 0)
  }
  
if tx.Extensions == nil {
    tx.Extensions
= make([]*Extension, 0, 0)
  }
  
tx.MaxNetUsageWords = Varuint32(maxNetUsageWords)
  tx.MaxCPUUsageMS
= maxCPUUsageMS
  tx.DelaySec
= Varuint32(delaySecs)

  
/* modify by tkblack begin */
  //tx.SetExpiration(30 * time.Second)
  
//expiration.Time = expiration.Time.Add(30 * time.Second)
  tx.Expiration
= expiration
  
/* modify by tkblack end */
}
//......
(省略)

 type TxOptions struct {
     ChainID     Checksum256 // If specified, we won't hit the API to fetch it
     HeadBlockID Checksum256 // If provided, don't hit API to fetch it.  This allows offline transaction signing.
     //MaxNetUsageWords uint32
     DelaySecs     uint32
     MaxCPUUsageMS uint8 // If you want to override the CPU usage (in counts of 1024)
     //ExtraKCPUUsage uint32 // If you want to *add* some CPU usage to the estimated amount (in counts of 1024)
     Compress CompressionType

     /* modify by tkblack begin */
     //  
     Expiration JSONTime
     /* modify by tkblack end */
 }
//......(省略)
// FillFromChain will load ChainID (for signing transactions) and
// HeadBlockID (to fill transaction with TaPoS data).
func (opts *TxOptions) FillFromChain(api *API) error {
    if opts == nil {
        return errors.New("TxOptions should not be nil, send an object")
    }

    if opts.HeadBlockID == nil || opts.ChainID == nil {
        info, err := api.cachedGetInfo()
        if err != nil {
            return err
        }

        if opts.HeadBlockID == nil {
            opts.HeadBlockID = info.HeadBlockID
        }
        if opts.ChainID == nil {
            opts.ChainID = info.ChainID
        }
/* modify by tkblack begin */ // opts.Expiration.Time = info.HeadBlockTime.Add(30 * time.Second) /* modify by tkblack end */ } return nil }

以上原理即通过get_info命令获取到最新区块的时间戳,然后加30秒作为过期时间,因此过期时间始终比链上时间相多30秒,至于本地时间是否准确不会影响程序运行。

posted @ 2020-04-08 14:37  tkblack  阅读(431)  评论(0编辑  收藏  举报