交易是来自账户私钥签名后的指令,账户可以通过发起交易来更新TRON网络的状态,最简单的交易是将TRX从一个账户转移到另一个账户。

改变TRON网络状态的交易需要广播到整个网络,任何一个节点都可以广播交易请求。超级节点收到交易后执行交易,并将其打包进区块,然后将区块广播到网络的其他节点。

交易只有被超级节点打包进区块后,并且区块被确认了,交易才最终被确认。

一个交易的格式如下:

{
    "raw_data": 
    {
        "contract": [{<-->}],
        "ref_block_bytes": "c145",
        "ref_block_hash": "c56bd8a3b3341d9d",
        "expiration": 1646796363000,
        "data": "74657374",
        "timestamp": 1646796304152,
        "fee_limit":10000000000
    },
    "signature":["47b1f77b3e30cfbbfa41d795dd34475865240617dd1c5a7bad526f5fd89e52cd057c80b665cc2431efab53520e2b1b92a0425033baee915df858ca1c588b0a1800" ] 
}

交易主要包括以下字段:

  • raw_data.contract - 交易的主体内容,contract是一个列表,但目前只用到一个元素,不同类型的交易,contract内容不一样,如果是TRX转账类型交易,contract会包含转账金额,接收人等信息,TRON支持多种类型的contract,具体参考下面交易的类型章节。
  • raw_data.ref_block_bytes - 交易引用块的高度,使用了引用块高度的第6到8(不包含)字节,共2字节。引用块用于TRON TAPOS机制,可以防止分叉链交易重放, 引用块一般选择最新固化的区块。
  • raw_data.ref_block_hash - 交易引用块的hash,使用了引用块hash的第8到16(不包含)字节,共8字节,引用块用于TRON TAPOS机制,可以防止分叉链交易重放, 引用块一般选择最新固化的区块。
  • raw_data.expiration - 交易过期时间,超过这个时间,交易将不再被打包。如果用户调用java-tron节点的API创建交易体,节点会自动设置过期时间,一般是在创建交易时节点最高区块的时间戳基础上再增加60秒,可以在节点的配置文件中修改过期时间间隔,最大不能超过24小时。
  • raw_data.data - 交易备注。
  • raw_data.timestamp - 交易时间戳,设置交易创建时间。
  • raw_data.fee_limit - 执行智能合约交易所允许消耗的最大能量费用,只有智能合约部署和调用交易需要设置,其他交易无需设置。
  • signature - 发送方对交易的签名,交易有了签名就可以证明该交易来自发送方,并非恶意者所伪造。

交易的类型

TRON网络支持多种不同类型的交易,比如TRX转账交易、TRC10转账交易、创建智能合约交易、触发智能合约交易、质押TRX交易等等。

创建不同类型的交易,需要调用不同的API接口, 例如部署合约交易的类型是CreateSmartContract,需要调用wallet/deploycontractAPI来创建交易,质押TRX获取资源交易的类型是FreezeBalanceV2Contract,需要调用 wallet/freezebalancev2API来创建交易:

$ curl -X POST https://api.shasta.trongrid.io/wallet/freezebalancev2 -d '{"owner_address":"TCrkRWJuHP4VgQF3xwLNBAjVVXvxRRGpbA","frozen_balance": 2100000,"resource" : "BANDWIDTH","visible":true}' | jq
{
  "visible": true,
  "txID": "e54bab34838a59e85d5684e46a2e8e512cd11dfb07b35a9728adeaf3d2666fa6",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "frozen_balance": 2100000,
            "owner_address": "TCrkRWJuHP4VgQF3xwLNBAjVVXvxRRGpbA"
          },
          "type_url": "type.googleapis.com/protocol.FreezeBalanceV2Contract"
        },
        "type": "FreezeBalanceV2Contract"
      }
    ],
    "ref_block_bytes": "7139",
    "ref_block_hash": "d291dee525445093",
    "expiration": 1646902209000,
    "timestamp": 1646902151591
  },
  "raw_data_hex": "0a0271392208d291dee52544509340e8d39598f72f5a58080b12540a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e467265657a6542616c616e6365436f6e7472616374121e0a15411fafb1e96dfe4f609e2259bfaf8c77b60c535b9310a0968001180370a7939298f72f"
}

更多交易类型请参考:TRON网络交易类型,更多的HTTP API请参考:HTTP API

交易的生命周期

交易在其生命周期中会依次经历以下几个阶段:

  1. 交易被创建及签名
  2. 交易被广播到TRON网络,节点对其验证并执行通过后,将其放入交易缓存池中
  3. 产块节点从交易缓存池中取出交易,将其打包进新区块,然后将区块广播到TRON网络
  4. 交易将被“确认”。一个交易是否被确认取决于这个交易所在的区块是否被确认,TRON的区块确认机制是某个区块产出后,19个不同的产块节点基于这个区块产出了后续区块,那么这个区块视为被确认。

创建交易

对于创建交易,有很多的库和工具可以选择,下面以tronweb创建一个TRX转账的交易为例说明如何创建交易:

const unsignedTxn = await tronWeb.transactionBuilder.sendTrx("TVDGpn4hCSzJ5nkHPLetk8KQBtwaTppnkr", 100, "TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL");
 >{
    "visible": false,
    "txID": "9f62a65d0616c749643c4e2620b7877efd0f04dd5b2b4cd14004570d39858d7e",
    "raw_data": {
        "contract": [
            {
                "parameter": {
                    "value": {
                        "amount": 100,
                        "owner_address": "418840e6c55b9ada326d211d818c34a994aeced808",
                        "to_address": "41d3136787e667d1e055d2cd5db4b5f6c880563049"
                    },
                    "type_url": "type.googleapis.com/protocol.TransferContract"
                },
                "type": "TransferContract"
            }
        ],
        "ref_block_bytes": "0add",
        "ref_block_hash": "6c2763abadf9ed29",
        "expiration": 1581308685000,
        "timestamp": 1581308626092
    },
    "raw_data_hex": "0a020add22086c2763abadf9ed2940c8d5deea822e5a65080112610a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412300a15418840e6c55b9ada326d211d818c34a994aeced808121541d3136787e667d1e055d2cd5db4b5f6c880563049186470ac89dbea822e"
}

签名交易

发送交易前,必须由发送方使用私钥对其进行签名。

交易签名过程

  1. 计算交易的哈希
  2. 使用发送者账户的私钥对该交易哈希进行签名
  3. 将生成的签名结果添加到交易对象中

大多数的SDK都实现了上述的交易签名流程,并封装成接口供开发者调用,以tronweb为例,用户可以直接调用sign方法完成交易的签名。

tronweb签名示例
使用tronweb对上面创建的交易进行签名:

const signedTxn = await tronWeb.trx.sign(unsignedTxn, privateKey);
>{
    "visible": false,
    "txID":"9f62a65d0616c749643c4e2620b7877efd0f04dd5b2b4cd14004570d39858d7e",
    "raw_data":
    {
        "contract": [{<-->}],
        "ref_block_bytes": "0add",
        "ref_block_hash": "6c2763abadf9ed29",
        "expiration": 1581308685000,
        "timestamp": 1581308626092 
    },
    "raw_data_hex": "0a020add22086c2763abadf9ed2940c8d5deea822e5a65080112610a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412300a15418840e6c55b9ada326d211d818c34a994aeced808121541d3136787e667d1e055d2cd5db4b5f6c880563049186470ac89dbea822e",
    "signature": [ "47b1f77b3e30cfbbfa41d795dd34475865240617dd1c5a7bad526f5fd89e52cd057c80b665cc2431efab53520e2b1b92a0425033baee915df858ca1c588b0a1800" ] 
 }

广播交易

用户将交易发送到节点后,节点会尝试在其本地执行并验证该交易, 有效的交易将被继续广播到其他节点,无效的交易被该节点丢弃,这将有效防止垃圾交易在网络中无效广播,占用网络资源。

使用tronweb对已签名的交易进行广播:

const receipt = await tronWeb.trx.sendRawTransaction(signedTxn);
>{ 
    "result": true,
    "transaction":
    { 
        "visible": false,
        "txID": "9f62a65d0616c749643c4e2620b7877efd0f04dd5b2b4cd14004570d39858d7e",
        "raw_data":
        {
            "contract": [{<-->}],
            "ref_block_bytes": "0add",
            "ref_block_hash": "6c2763abadf9ed29",
            "expiration": 1581308685000,
            "timestamp": 1581308626092 
        },
        "raw_data_hex": "0a020add22086c2763abadf9ed2940c8d5deea822e5a65080112610a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412300a15418840e6c55b9ada326d211d818c34a994aeced808121541d3136787e667d1e055d2cd5db4b5f6c880563049186470ac89dbea822e",
        "signature": [ "47b1f77b3e30cfbbfa41d795dd34475865240617dd1c5a7bad526f5fd89e52cd057c80b665cc2431efab53520e2b1b92a0425033baee915df858ca1c588b0a1800" ] 
    } 
 }

交易确认

一个交易是否被确认取决于这个交易所在的区块是否被确认,TRON的区块确认机制是某个区块产出后, 19个不同的产块节点基于这个区块产出了后续区块,那么这个区块视为被确认。

java-tron节点提供了/walletsolidty/* 接口,方便用户查询被确认的交易,/walletsolidty/*/wallet/*的区别是/wallet/*查询到的交易是说明该交易已经上链但不一定被确认,/walletsolidty/*查询到的交易说明该交易已经上链同时也已经被固化,也就是交易被确认。

不同的交易的确认方法有所不同:

  • 系统合约交易
    创建智能合约类型和触发智能合约类型以外的所有类型的交易,都属于系统合约交易。系统合约交易确认方法:
    • 通过/walletsolidity/gettransactioninfobyid或者/walletsolidity/gettransactionbyidAPI能够查询到交易,即为确认
  • 智能合约交易
    创建智能合约和触发智能合约交易,因为交易需要在虚拟机中执行,某些交易执行过程中会抛出一些异常,这些交易能够上链,但不代表交易是执行成功的, 有两种确认智能合约交易是否执行成功的方法:
    • 通过/walletsolidity/gettransactioninfobyid API查询到的返回值中receipt.result等于success
    • 通过/walletsolidity/gettransactionbyidAPI查询到的返回值中transaction.ret.contractRetsuccess
  • 内部交易
    内部交易是合约中向其他普通地址或者合约地址转账的交易,首先通过/walletsolidity/gettransactioninfobyidAPI查询到内部交易记录,使用内部交易记录中的rejected字段来判断该内部交易是否被确认,但对于HTTP和GRPC接口有所不同:
    • HTTP接口:成功的内部交易,默认不返回 rejected 字段, 失败的内部交易,rejected等于true。
    • GRPC接口:成功的内部交易,rejected字段等于false,表示这笔内部交易没有被舍弃, 失败的内部交易,rejected等于true。

内部交易

我们平常说的交易一般指由外部账户触发的交易,比如智能合约调用交易,而在智能合约函数被执行的过程中,可能还会触发其它合约函数的调用、向外部账户转移TRX/TRC10代币、或者可能还会进行质押、投票、资源代理等操作,这种发生在智能合约调用期间的交易被称为内部交易。因此内部交易是由合约账户在TVM中触发的交易。

内部交易的产生

本节以在去中心化交易所中使用USDT交换TRX为例,来说明内部交易的产生。

下面为TRX-USDT交易对合约tokenToTrxSwapInput 方法,它可以根据用户输入的卖出的USDT数量,为用户换取TRX:

function tokenToTrxSwapInput(uint256 tokens_sold, uint256 min_trx, uint256 deadline) public returns (uint256) {
    return tokenToTrxInput(tokens_sold, min_trx, deadline, msg.sender, msg.sender);
  }
  
function tokenToTrxInput(uint256 tokens_sold, uint256 min_trx, uint256 deadline, address buyer, address payable recipient) private nonReentrant returns (uint256) {
    require(deadline >= block.timestamp && tokens_sold > 0 && min_trx > 0);
    uint256 token_reserve = token.balanceOf(address(this));
    uint256 trx_bought = getInputPrice(tokens_sold, token_reserve, address(this).balance);
    uint256 wei_bought = trx_bought;
    require(wei_bought >= min_trx);
    recipient.transfer(wei_bought);

    require(address(token).safeTransferFrom(buyer, address(this), tokens_sold));
    emit TrxPurchase(buyer, tokens_sold, wei_bought);
    emit Snapshot(buyer,address(this).balance,token.balanceOf(address(this)));

    return wei_bought;
  }

我们可以看到该合约方法中一共有四处代码涉及到触发其它合约或者为外部账户转账,分别为:

  • 第7行: token.balanceOf(address(this)),用于查询本合约的USDT余额
  • 第11行: recipient.transfer(wei_bought),用于给交换者账户转账TRX
  • 第13行: address(token).safeTransferFrom(buyer, address(this), tokens_sold)),用于从交换者账户中转移USDT到本合约中
  • 第15行: token.balanceOf(address(this)),用于查询本合约的USDT余额

以上四处代码分别对应了通过 TRONSCAN 或者通过 API 接口查询到的内部交易。

内部交易的用处

内部交易可以为用户提供一些重要信息,比如:

  • 失败交易定位 - 如果内部交易失败,则整个交易将失败。通过内部交易可以达到通知用户故障点的确切位置的目的,有助于快速定位并解决问题
  • 智能合约监控 - 您部署的智能合约可以与其他合约进行交互。通过内部交易可以了解合约何时与哪个合约进行了交互,以达到监控智能合约的目的
  • 智能合约分析 - 由于内部交易可能很复杂,通过查看智能合约执行的内部交易数量,您可以大概了解该合约的性能
  • 批量交易 - 如果您希望批量发送交易,如批量转账TRX,则可以使用内部交易,以实现便捷安全的将代币发送到目的地址

内部交易的存储

内部交易的用处很多,可以指导和告知用户交易的执行情况,但节点默认不保存内部交易信息,需要手动通过节点配置文件开启:

vm = {
    ...
  saveInternalTx = true
  saveFeaturedInternalTx = true
    ...
}
  • saveInternalTx:是否支持内部交易
  • saveFeaturedInternalTx:在saveInternalTx开启的情况下,是否保存Stake2.0相关内部交易

内部交易存储配置项开启后,重启节点,从重启时刻开始,节点将保存其内部交易,用户可以根据外层交易的交易ID来查看其内部交易,不支持直接通过内部交易的hash来查看内部交易详情。 通过gettransactioninfobyid API可以查询一笔交易中的内部交易。

内部交易的示例

节点保存的内部交易中包含如下信息:

  • hash:内部交易的哈希值
  • caller_address:调用者地址
  • transferTo_address:调用的合约地址或者接收TRX/TRC10代币的账户地址
  • callValueInfo.callValue:转账的TRX/TRC10代币的数量
  • callValueInfo.tokenId:转账的TRC10 name或者id;转账TRX时,该字段为空。
  • note:指令类型,比如call、create、 suicide、freezeBalanceV2ForEnergy、freezeBalanceV2ForBandwidth、unfreezeBalanceV2ForBandwidth等等
  • rejected:内部交易是否执行成功,true为执行失败
  • extra:目前主要用于保存投票的情况,以json格式记录投票的SR及其票数

下面我们根据各个示例来看内部交易包含的信息:

1. 智能合约调用其它智能合约方法

这里有一个示例,该交易是一个外部地址调用了"TQn9Y...."合约,"TQn9Y...."合约中又调用了"TR7NHq...."合约:

{
    "id": "50e6dd05c37b8666cf4a689fe6c0d52053b76b53d8649b256e6b9dca8c9df098",
    ......
    "internal_transactions": [
        {
            "hash": "380f4d87271b83afcf5e867271ee2d30b36c19d3eeb15a043477bce7fd5b2079",
            "caller_address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
            "transferTo_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
            "callValueInfo": [
                {}
            ],
            "note": "63616c6c"
        },
        .......
    ]
}

上述内部交易的包含的信息如下:

  • internal_transactions.caller_address是调用者地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address是合约中调用的另外一个合约的地址
  • internal_transactions.callValueInfo 本例中在调用其它合约时没有通过value传入TRX/TRC10 代币,因此该字段值为空。如果在合约调用其它合约函数时附带了value信息,则将通过该字段体现出来
  • internal_transactions.note是指令说明,为Hex格式,将其转换为字符串后即可得到明文的操作信息,本例为call

2. 智能合约向外部账户转账 TRX

这里有一个示例,该交易是一个外部地址调用了"TQn9Y...."合约,"TQn9Y...."合约中又向"TQnpn...."地址转入了TRX:

{
    "id": "50e6dd05c37b8666cf4a689fe6c0d52053b76b53d8649b256e6b9dca8c9df098",
     ......
    "internal_transactions": [
        ......
        {
            "hash": "f47fede2a45e722e6406421d0df16142e159ae7404525de5a595f4fc0c357e26",
            "caller_address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
            "transferTo_address": "TQnpnLZJYMzH5xku535rAiYTnqYXTDTEHQ",
            "callValueInfo": [
                {
                    "callValue": 4514968563
                }
            ],
            "note": "63616c6c"
        },
        ......
    ]
}
  • internal_transactions.caller_address是调用者地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address是转账TRX的目标地址
  • internal_transactions.callValueInfo[0].callValue 是转账TRX数额,单位为sun
  • internal_transactions.note是指令说明,为Hex格式,将其转换为字符串后即可得到明文的操作信息,本例为call

3. 智能合约向外部账户转账 TRC10 代币

TRC10转账与TRX转账基本相同,只在如下两个字段有所不同:

  • internal_transactions.callValueInfo[0].callValue 是转账的TRC10代币数额。
  • internal_transactions.callValueInfo[0].tokenId 是转账的TRC10 name或者id。由于第14号委员会提议允许通证同名,因此,在该提议生效前(5537806之前的区块),该字段表示转账TRC10的代币名称,在该提议生效后(5537806以及之后的区块),该字段表示转账TRC10的代币ID。

4. 智能合约质押TRX

这里有一个示例,该交易是一个外部地址调用了"TU8Mb...."合约,"TU8Mb...."合约中又进行了质押操作,质押1000TRX以获取能量:

{
    "id": "9d25a4fe417e0c7540cc5c5841e1d8c9215aec556d9b06e18910ed8b5088f0d8",
    ......
    "internal_transactions": [
        {
            "hash": "a3a4d666e7bf0729bbd8b5e5ad7afb7f8dd20191e7298ea9dbd17af345c96ed5",
            "caller_address": "TU8MbhYhurKv4T3xAHQKZCeP4DtFCmWLMt",
            "transferTo_address": "TU8MbhYhurKv4T3xAHQKZCeP4DtFCmWLMt",
            "callValueInfo": [
                {
                    "callValue": 1000000000
                }
            ],
            "note": "667265657a6542616c616e63655632466f72456e65726779"
        }
    ]
}
  • internal_transactions.caller_address是质押发起者地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address是质押资源接收地址,也就是质押发起者地址,即该合约地址
  • internal_transactions.callValueInfo[0].callValue 是质押的TRX金额(单位为sun)
  • internal_transactions.note是指令说明,为Hex格式,将其转换为字符串后即可得到明文的操作信息。本例中为freezeBalanceV2ForEnergy,表示合约质押TRX以获取能量。如果是合约质押获取带宽,则该字段值为freezeBalanceV2ForBandwidth

5. 智能合约解质押TRX

这里有一个示例,该交易是一个外部地址调用了"TU8Mb...."合约,"TU8Mb...."合约中又进行了解质押操作,解锁为获取带宽而质押的100TRX:

{
    "id": "dc110091fbd1568f8b264f287c7e0896d1afaf47b906a9e684fd17d57c7a1151",
    ......
    "internal_transactions": [
        {
            "hash": "16f73bdad5e9f984e082909b1028fff0b9865952131e681ca887446f8ec89918",
            "caller_address": "TU8MbhYhurKv4T3xAHQKZCeP4DtFCmWLMt",
            "transferTo_address": "TU8MbhYhurKv4T3xAHQKZCeP4DtFCmWLMt",
            "callValueInfo": [
                {
                    "callValue": 100000000
                }
            ],
            "note": "756e667265657a6542616c616e63655632466f7242616e647769647468"
        }
    ]
}
  • internal_transactions.caller_address 是解质押发起地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address 是解锁的质押本金接收地址,即外部地址直接调用的合约地址
  • internal_transactions.callValueInfo[0].callValue 是解质押的TRX金额(单位为sun)
  • internal_transactions.note 是指令说明,本例中为unfreezeBalanceV2ForBandwidth,表示合约解锁为获取带宽而质押的TRX。如果是合约解锁为获取能量而质押的TRX,则该字段值为unfreezeBalanceV2ForEnergy

6. 智能合约为其它账户代理资源

这里有一个示例,该交易是一个外部地址调用了"TU8Mb...."合约,"TU8Mb...."合约中又进行了资源代理操作,它将500000000sun的能量份额代理给了"TUznH...."地址:

{
    "id": "342daa21f8865786295c45bb80e2f257740091e4e1a3a546b90daa51bcbcbd18",
    ......
    "internal_transactions": [
        {
            "hash": "58382a79c3af68c472383580309a81a9322e7520a48b6463917ba9219ca32a7d",
            "caller_address": "TU8MbhYhurKv4T3xAHQKZCeP4DtFCmWLMt",
            "transferTo_address": "TUznHJfHe6gdYY7gvWmf6bNZHuPHDZtowf",
            "callValueInfo": [
                {
                    "callValue": 500000000
                }
            ],
            "note": "64656c65676174655265736f757263654f66456e65726779"
        }
    ]
}
  • internal_transactions.caller_address 是资源代理地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address 是资源接收地址
  • internal_transactions.callValueInfo[0].callValue 是代理质押的TRX数额(单位为sun)
  • internal_transactions.note 是指令说明,本例中为delegateResourceOfEnergy,表示代理能量资源操作。如果是合约代理带宽,则该字段值为delegateResourceOfBandwidth

7. 智能合约取消为其它账户的资源代理

这里有一个示例,该交易是一个外部地址调用了"TU8Mb...."合约,"TU8Mb...."合约中又进行了取消资源代理操作,它取消了为"TUznH...."地址代理的200000000sun能量份额:

{
    "id": "aa3961ffb0781d8b66d5e22368e92708135dac9c81eac1e2adcaa8546d729bc8",
    ......
    "internal_transactions": [
        {
            "hash": "1a8524704098770d9c6535e1112d1fb91855363c8366c93810f3cb56e8ee12bf",
            "caller_address": "TU8MbhYhurKv4T3xAHQKZCeP4DtFCmWLMt",
            "transferTo_address": "TUznHJfHe6gdYY7gvWmf6bNZHuPHDZtowf",
            "callValueInfo": [
                {
                    "callValue": 200000000
                }
            ],
            "note": "756e44656c65676174655265736f757263654f66456e65726779"
        }
    ]
}
  • internal_transactions.caller_address 是资源代理地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address 是资源接收地址,即取消为该地址的资源代理
  • internal_transactions.callValueInfo[0].callValue 是取消代理的TRX数额(单位为sun)
  • internal_transactions.note 是指令说明,本例中为unDelegateResourceOfEnergy,表示取消能量资源代理操作。如果是合约取消带宽资源代理,则该字段值为unDelegateResourceOfBandwidth

8. 智能合约为超级代表投票

这里有一个示例,该交易是一个外部地址调用了"TNaDY...."合约,"TNaDY...."合约中又进行了投票操作,为超级代表"TUoHa...."和"TUznH...."分别投票200和400:

{
    "id": "58506325f692eee0bd730d97a0086f8b0c50e8aa5392b9e4b0edd5fb0916a718",
    ......
    "internal_transactions": [
        {
            "hash": "792b26cb6fbd1c92030721c62f7fd14522a94f412e04b05442d78e1ce743c9f4",
            "caller_address": "TNaDYZaXEpL1LY8Uk4LtGTwwQrGzXTwss9",
            "callValueInfo": [
                {}
            ],
            "note": "766f74655769746e657373",
            "extra": "{\"votes\":[{\"vote_address\":\"TUoHaVjx7n5xz8LwPRDckgFrDWhMhuSuJM\",\"vote_count\":200},{\"vote_address\":\"TUznHJfHe6gdYY7gvWmf6bNZHuPHDZtowf\",\"vote_count\":400}]}"
        }
    ],
    ......
}
  • internal_transactions.caller_address:是为超级代表投票的地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address:对于合约投票交易,该字段值为空,所以在返回结果中不显示该字段
  • internal_transactions.callValueInfo: 对于合约投票交易,该字段值为空数组
  • internal_transactions.note:是指令说明,本例中为voteWitness,表示为超级代表投票操作
  • internal_transactions.extra:投票详情,以JSON格式记录投票的SR及其票数:votes[i].vote_address为SR地址,votes[i].vote_count为票数

9. 智能合约提取奖励

这里有一个示例,该交易是一个外部地址调用了"TNaDY...."合约,"TNaDY...."合约中又进行了提取奖励操作,提取了443803418sun的奖励:

{
    "id": "8dc24b5ce1399b553cd173529e77b22172d9abf31e9f50dd32c473bcc5234b71",
    ......
    "internal_transactions": [
        {
            "hash": "e5b047a4a3d64407c93a9e667a083fe52c52b24e859e3a44488249436e79c8d4",
            "caller_address": "TNaDYZaXEpL1LY8Uk4LtGTwwQrGzXTwss9",
            "transferTo_address": "TNaDYZaXEpL1LY8Uk4LtGTwwQrGzXTwss9",
            "callValueInfo": [
                {
                    "callValue": 443803418
                }
            ],
            "note": "7769746864726177526577617264"
        }
    ]
}
  • internal_transactions.caller_address:是提取奖励的地址,即外部地址直接调用的合约地址
  • internal_transactions.transferTo_address:是接收奖励的地址,即外部地址直接调用的合约地址
  • internal_transactions.callValueInfo[0].callValue: 提取的TRX奖励数额,单位为sun
  • internal_transactions.note:是指令说明,本例中为withdrawReward,表示提取奖励