# 交易所 FAQ
# 常用信息
TOP节点程序编译 (opens new window),执行时参考编译相关章节,也可以由官方提供编译好的二进制程序。
- 说明:
- 目前只能在centos上编译和运行,不支持在Ubuntu上编译。
- 官方的RPC域名是有限流的,不能操作太频繁。交易所自己的节点,可以增加编译选项 noratelimit,来规避限流问题。
-
- 说明:
- 交易所节点不需要质押TOP,只要有0.1TOP币就可以。
- 有些节点端口,可以关闭。
- TCP 19081 RPC服务 要使用,可以不开放到公网
- TCP 19082 GRPC服务 可以关闭
- TCP 19085 WEBSOCKET服务 可以关闭
- TCP 8080 EVM RPC服务 可以关闭
- UDP 9000和9001 节点同步消息 要使用,要开放到公网
- 在没有搭建好交易所自己的节点之前,可以使用官方域名进行调试 http://mainnet.edge.topnetwork.org (opens new window)
分片多链的说明
- TOP是一条全状态分片的区块链,总共64个分片,分片也称为Table。一个分片具有一条独立的Table链,64个Table链的名称分别是Ta0000@0 ~ Ta0000@63。
- 每个Table链是相互独立不影响的。
- 对于交易所来说,我们强烈建议把账户地址创建到指定的一条table链上,好处是:
- 同一个table内的账号之间转账,只需要一次共识,交易只会打包在一个区块上,交易实时性好。
- 交易所只需要监控一条Table链,和非分片链一样的逻辑,监控方式简单。
- 如何监控一条Table:
- 查询Table链的最新块,getBlock接口 (opens new window)
- 查询区块关联的交易详情,getTransaction接口 (opens new window)
多少个区块可以确认不回滚?
- TOP采用BFT共识算法,一个交易会触发出3个块,分别是commit块,lock块,cert块,3个块之后,区块就变成确认不可回滚的状态。TOP的getBlock接口只能查询到确认状态的区块。
- 所以,我们建议只要通过RPC接口查询到区块就认为区块确认了。不要再等待一定数量的区块才确认。
- 如果采用多个区块确认的方式,可能会导致交易确认时间很长。因为TOP是分片链,单个TABLE上的交易量比较少,如果没有交易,就会停止出块。 当然,我们自己会随机定时发一下测试交易,但是这个交易是不可靠发的。
RPC接口的公共字段
- 以RPC接口“getBlock”为例子:
- RPC请求
- curl -X 'POST' -d 'target_account_addr=Ta0000@2&body={"params":{"account_addr":"Ta0000@2","height":"latest"}}&method=getBlock&sequence_id=8&version=2.0'
- RPC响应
{
"data": {
"value": {
"body": {
"tableblock": {
"txs": [
{
"tx_consensus_phase": "send",
"tx_hash": "0x33fce026ca88e9132bdf492dcbc8135660a156c35e7e5f4d2a6a0a7efd1f4ead"
}
],
"units": [
{
"account": "T00000Lf68NwzEfQT8BmVdZrvxotGxJNrbfxuq91",
"unit_height": 138028
}
]
}
},
"hash": "66316913b18a3515cb39a4f00dd8639be159892daab3b9b9a172baecb884d658",
"header": {
"auditor": "T00000LgDBrJ4TpoyW3Lk15jPicZ2agQPNuvDAXg",
"auditor_xip": "1000000000007aa3:f60000000004043",
"multisign_auditor": "740000005f00000089205f1300000000210002782ae6869158e00f59cc0b003473c62f236a224b4eb3ed7084275243cc3df38d20000b21bf9333f982735b2d151d44abddd1dc86070e885a8445d6462b8c01b861284000bffbfadbc3d6b89f",
"multisign_validator": "740000006700000089205f13000000002100021813ee23c0cdfa3abf043f7fbf6bb1c25a9ad8aef1eb93a333c68436f062d1482000c72b898282f346ea7cbd9d74cad543e7ed13b13755e180de986b65e0aee03ee880007bee3d7d9d7f7a66d4fb9d955ff9b2f6",
"timerblock_height": 10664162,
"validator_xip": "2000000000007aa3:f6000000000503f",
"version": 327680
},
"height": 519281,
"owner": "Ta0000@2",
"prev_hash": "9baec8ff4e3129f113a85230f48fb208f98ae52b3f980780885862618e249f37",
"table_height": 519281,
"timestamp": 1679830820
}
},
"errmsg": "OK",
"errno": 0,
"sequence_id": "8"
}
说明:
1)正常返回时,errno字段为0,errmsg为"ok"。查询失败时,errno为非0值,errmsg显示具体错误信息。
比如:账户地址非法,"errmsg": "account address is valid","errno": 1,
比如:账户地址或交易hash不存在,"errmsg": "account address or transaction hash error/does not exist","errno": 3,
2)请求头里面的"target_account_addr"字段是必须要填写的,目的是用于路由查找地址所在的分片。对于交易所节点来说,如果是查询命令,总是向交易所节点查询,该字段可以填写任意的T8地址或者Table地址。但是,如果是发送交易的请求,这个字段必须填写成交易的from地址。
3)请求头里面的“sequence_id”字段必须填写,对于交易所来说,可以填写成固定值,比如1。
4)body里面的"account_addr"字段表示账户地址或者Table链地址,比如上述getBlock命令填写为指定Table的table地址。
- 交易所节点启动信息和监控说明
- topio node isJoined 返回yes,就表示节点入网成功。然后节点会自动进行数据同步。所以,需要只需要监控“topio node isJoined 返回yes”,然后等待节点数据同步好并开启端口。
- 一个新的交易所节点启动时,数据同步需要花费一段时间(几个小时),直到找到节点的注册节点数据,才会真正开启交易所节点功能,比如启用TCP 19081端口。
- 节点启动的提示信息有以下几类:
//数据同步还未同步到节点的注册信息,调用topio node startNode时的启动信息
topio node startNode
The miner has not joined in node-standby-pool, please start node by command 'topio node startnode'.
Start node successfully.
//数据同步还未同步到节点选举信息数据,调用topio node startNode时的启动信息
topio node startNode
Not elected to any node role.
Start node successfully.
//数据同步完成时,调用topio node startNode时的启动信息
topio node startNode
Elected as exchange.
Start node successfully.
# TOP Token 相关
# 1. TOP Token
TOP 里最小单位为:微(uTOP)
- 1 TOP = 10 ^ 6 微(uTOP)
- 1 分(cTOP):Cent-top = 1/100 TOP, 1/hundred
- 1 毫(mTOP):Milli-top = 1/1000 TOP, 1/Thousand
- 1 微(μTOP):Micro-TOP = 1/10^6 TOP, 1/Million
# 2. TOP Token 总发行量
TOP Token 的总发行量为 200亿。
# 账户、交易相关
# 3. 用户账户(地址)和 Table
TOP 采用的是 Account 模型。
TOP 账户地址以 T80000 开头,格式为 T80000 + 以太坊格式地址。
任一个账户地址通过计算 Hash 逻辑上映射到 64 个 table 中的固定一个,每个 Table 类似一条独立的子链(也是一个逻辑分片)。账户地址和Table的映射规则为:
- 第一步:对整个账户地址进行hash64计算:uint32_t account_index = hash64(account_addr);
- 第二步:对hash64结果进行强制转换成uint16:uint16_t ledger_sub_addr = (uint16_t)(account_index);
- 第三步:对uint16结果进行64求余:uint16_t tableID = (ledger_sub_addr &63);
每个 table 会对所管辖的账户的交易进行打包并独立出块。
64 个 Table 子链地址对应 Ta0000@0 ~ Ta0000@63。
64 个 Table 子链序号(ID)为 0 ~ 63。
# 4. 账户地址格式
说明:
1)交易所需要使用T8开头的地址,例子:T80000bf28ca5dc9f1f4cddabeb6da4c29e0db47d4b9c4
2)地址对大小写敏感,要求除了首字母T之外,其余全部小写。
package org.topnetwork.account;
import java.io.IOException;
import org.topnetwork.account.property.AccountUtils;
import com.alibaba.fastjson.JSONObject;
/**
* 构建离线 account
*/
public class CreateOfflineAccount {
public static void main(String[] args) throws IOException {
// 1.随机创建离线地址
Account account=new Account();
System.out.println("account > "+ JSONObject.toJSONString(account));
System.out.println("privateKeyBytes > "+ account.getPrivateKeyBytes());
// 2.指定 table 创建离线地址,targetTableId[0,63]
int targetTableId = 0;
Account account1 = AccountUtils.genAccount(targetTableId);
System.out.println("account1 > "+ JSONObject.toJSONString(account1));
// 3.根据私钥构建地址
String privateKey = "0x638785b5e9bb9271f031f6ef852e3d5f33b9f46bff6d920b8622d44e69d6666f";
Account account2 = new Account("0x638785b5e9bb9271f031f6ef852e3d5f33b9f46bff6d920b8622d44e69d6666f");
System.out.println("account2 > "+ JSONObject.toJSONString(account2));
// 4. 根据 privateKeyBytes 构建帐户
byte[] privateKeyBytes = account2.getPrivateKeyBytes();
Account account3 = new Account(account2.getPrivateKeyBytes());
System.out.println("account3 >" + JSONObject.toJSONString(account3));
}
}
# 5. 如何扫描某个账户下所有交易
您可以先 查询用户账户所在的 Table 子链地址以及最新块高,再 扫描指定 Table 子链下的所有块。
# 6. 如何获取用户地址下的余额
RPC接口为getAccount (opens new window) :
- table_id字段表示账户所在的tableid。
- burned_token字段表示该账户历史花费的交易费用,交易费用是销毁掉的。
Java范例代码:
package org.topnetwork.account;
import java.io.IOException;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.AccountInfoResponse;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
/**
* 获取指定帐户余额
*/
public class GetAccountBalance {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
// 查询指定地址的帐户余额
String address = "T80000f4d41bf4035e972649a8168ba06a15fa19a15ded";
Account account=new Account();
account.setAddress(address);
topj.passport(account);
ResponseBase<AccountInfoResponse> accountResult = topj.getAccount(account);
System.out.println("account balance (utop) > "+accountResult.getData().getBalance());
}
}
# 7. 如何获取用户账户下的最新 nonce
package org.topnetwork.account;
import java.io.IOException;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.AccountInfoResponse;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
/**
* 获取指定帐户最新 nonce
*/
public class GetAccountNonce {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
// 查询指定地址的帐户信息
String address = "T80000f4d41bf4035e972649a8168ba06a15fa19a15ded";
Account account=new Account();
account.setAddress(address);
topj.passport(account);
ResponseBase<AccountInfoResponse> accountResult = topj.getAccount(account);
System.out.println("account latest nonce > "+accountResult.getData().getNonce());
}
}
# 8. 如何通过交易 Hash 查询交易详情
RPC接口为getTransaction (opens new window)
- 交易是否成功,只要关注tx_state字段,判断是否为success即可。
- 实际扣除的交易手续费 = send_block_info.tx_fee + send_block_info.used_deposit + confirm_block_info.used_deposit
- getTransaction查询到的信息,都是不可回滚的
- top是一条分片链,交易的两个账户可能分布在不同table(也叫做跨table交易),跨table交易会有3个阶段(即三次共识,分别是send,recv,confirm),所以交易会有三部分信息,分别是send_block_info,recv_block_info,confirm_block_info。 转账交易只有两次共识,confirm和send总是相同。
curl -X 'POST' -d 'target_account_addr=T00000LWY6p1GfHJQ65NyiXGnEtc51i71ujuGDJQ&body={"params":{"account_addr":"T00000LWY6p1GfHJQ65NyiXGnEtc51i71ujuGDJQ","tx_hash":"0x76db850ced18deb00f176a7ecad93d20d6df2b5ad806810a8ed5965450edf012"}}&method=getTransaction&sequence_id=8&version=2.0' http://mainnet.edge.topnetwork.org
{
"data": {
"original_tx_info": {
"amount": 1,
"authorization": "0x00684998cde3d692ae2cf85b0e6889328bfbe1c9fe185027a5ad8f6da59f5afae34821bed2f7c029ea27b4534f70b9b34543004ea886a7c5930782870f4a54a2c5",
"edge_nodeid": "",
"ext": "",
"last_tx_nonce": 60722,
"note": "subscription",
"premium_price": 0,
"receiver_account": "T00000LMnPbhyrVSjuZPTibWGWK112sCor6aVcvm",
"receiver_action_name": "",
"receiver_action_param": {
"amount": 1,
"token_name": "TOP"
},
"send_timestamp": 1679922302,
"sender_account": "T00000LWY6p1GfHJQ65NyiXGnEtc51i71ujuGDJQ",
"sender_action_name": "",
"sender_action_param": {
"amount": 1,
"token_name": "TOP"
},
"token_name": "",
"tx_deposit": 100000,
"tx_expire_duration": 100,
"tx_hash": "0x76db850ced18deb00f176a7ecad93d20d6df2b5ad806810a8ed5965450edf012",
"tx_len": 187,
"tx_structure_version": 2,
"tx_type": 4
},
"tx_consensus_state": {
"confirm_block_info": {
"account": "Ta0000@0",
"exec_status": "success",
"height": 1227248,
"recv_tx_exec_status": "success",
"used_deposit": 0,
"used_gas": 0
},
"recv_block_info": {
"account": "Ta0000@56",
"height": 563013,
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"used_gas": 0
},
"send_block_info": {
"account": "Ta0000@0",
"height": 1227248,
"tx_fee": 0,
"used_deposit": 0,
"used_gas": 561
}
},
"tx_state": "success"
},
"errmsg": "OK",
"errno": 0,
"sequence_id": "8"
}
# 9. 如何通过交易 Hash 查询对应的 Table 块
Self 交易为发送和接受均为自己的地址,所以 self 交易只有一个块,而非 self 交易每笔交易有 3 个块。
- send block 对应发送交易的块。
- recv block 对应接收交易的块。
- confirm block 对应确认交易的块。
RPC接口为getBlock (opens new window)
- 查询指定Table链的最高块,设置参数account_addr为Table链名称和参数height为latest,比如"account_addr":"Ta0000@10","height":"latest"
- 查询指定Table链和指定高度的块,设置参数account_addr为Table链名称和参数height为具体高度,比如"account_addr":"Ta0000@10","height":"10000"
- getBlock返回的内容,包含每条交易的hash和共识阶段信息(tx_consensus_phase字段)。tx_consensus_phase取值范围:send,recv,confirm,self,其中self表示的是交易的发送地址和接收地址是相同的。对于转账交易来说,只有send和recv两种情况。
curl -X 'POST' -d 'target_account_addr=Ta0000@10&body={"params":{"account_addr":"Ta0000@10","height":"latest"}}&method=getBlock&sequence_id=8&version=2.0' http://mainnet.edge.topnetwork.org
{
"data": {
"value": {
"body": {
"tableblock": {
"txs": [{
"tx_consensus_phase": "send",
"tx_hash": "0x692ea56daeba98383db35cb8fdbc4a111941999c6b44b66580d6e08ce3aabb61"
}],
"units": [{
"account": "T00000LYpGz3V6QJ52SGumo1yWwX7LyxrQqjDLdq",
"unit_height": 178899
}]
}
},
"hash": "01fdabdaee0856b1960c2eae7c2fe53fa0dfabcffd9ad28e6ac80319ce573007",
"header": {
"auditor_xip": "1000000000007ae1:f6000000000407f",
"multisign_auditor": "740000005f0000006cc26cfc00000000210002e0e03814ac48d9e8427d8a97e1dfb4f52f8f061d11e4cebf634c12ad107f44fe20001274c5ad1672c5761021c261f5dd4ce6d35fb2457bd41900f895c0469cd695b84000fffee7ffffbfdfff",
"multisign_validator": "74000000670000006cc26cfc00000000210002b2b041d64a0ea1eba01c3994673e0c1c8d15db43fcbed304030a9a2a7c81bf38200060cda855245ebb99fad75f283ab7b5d64d5d2e767d329df0c8125c6a58d8a12980003fce7fed2bce85eff5fb9f77fcb0ba33",
"timerblock_height": 10687171,
"validator": "T00000LUoiK1jSZMvEzfu7urJ4G9sH1PitAqsuWe",
"validator_xip": "2000000000007ae1:f60000000005003",
"version": 327680
},
"height": 592406,
"owner": "Ta0000@10",
"prev_hash": "24ed46340ef4387b6bcb3b46bde22dc360e0c99682c3a16836af1e72014f7843",
"table_height": 592406,
"timestamp": 1680060910
}
},
"errmsg": "OK",
"errno": 0,
"sequence_id": "8"
}
Java范例代码为:
package org.topnetwork.block;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.topnetwork.account.Account;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.methods.response.block.TableBlockResponse;
import org.topnetwork.methods.response.tx.TxConsensusState;
import org.topnetwork.methods.response.tx.XTransactionResponse;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
import java.io.IOException;
/**
* 如何通过交易 Hash 查询对应的 Table 块
*/
public class GetTableBlockByTxHash {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
Account account=new Account();
topj.passport(account);
// 正常发送交易每笔交易会有 3 个块
String txHash = "0x052945e6f8f56bd9215e603aecde92a255ada57bd3d40cf662fc802805be406a";
ResponseBase<XTransactionResponse> transactionResponseResponseBase = topj.getTransaction(account,txHash);
System.out.println("transaction >> " + JSON.toJSONString(transactionResponseResponseBase));
TxConsensusState state = transactionResponseResponseBase.getData().getTxConsensusState();
// 1.send block
ResponseBase<TableBlockResponse> sendTableIdBlock = topj.getTableBlockByHeight(account,state.getSendBlockInfo().getAccount(),state.getSendBlockInfo().getHeight().intValue());
System.out.println("sendTableIdBlock info > "+ JSONObject.toJSONString(sendTableIdBlock));
// 2.recv block
ResponseBase<TableBlockResponse> recvTableIdBlock = topj.getTableBlockByHeight(account,state.getSendBlockInfo().getAccount(),state.getRecvBlockInfo().getHeight().intValue());
System.out.println("recvTableIdBlock info > "+ JSONObject.toJSONString(recvTableIdBlock));
// 3.confirm block
ResponseBase<TableBlockResponse> confirmTableIdBlock = topj.getTableBlockByHeight(account,state.getSendBlockInfo().getAccount(),state.getConfirmBlockInfo().getHeight().intValue());
System.out.println("confirmTableIdBlock info > "+ JSONObject.toJSONString(confirmTableIdBlock));
}
}
# 10. 如何发送交易,以及如何在交易里携带 Memo 信息
交易里面有一个memo字段,可以自定义设置内容,要求长度不能超过100字节。交易所可以利用memo实现memo模式,把memo字段设置成一个中心化用户id,从而识别出这笔交易的目标用户。当然,交易所也可以采用地址模式,TOP的交易费用非常低。
Java范例代码:
package org.topnetwork.transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Map;
import org.topnetwork.account.Account;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.Model.TransferParams;
import org.topnetwork.methods.request.Transfer;
import org.topnetwork.methods.response.AccountInfoResponse;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.methods.response.XTransaction;
import org.topnetwork.methods.response.tx.XTransactionResponse;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.utils.ArgsUtils;
/**
* 连接rpc直接发送交易
*/
public class SendTransaction {
// 根据节点地址和端口,初始化通信协议对象,支持websocket
private static HttpService httpService = new HttpService("http://206.189.210.106:19081");
private static Topj topj = Topj.build(httpService);
public static void main(String[] args) throws IOException {
//1. 构建发送帐户
Account sendAccount=new Account("0x638785b5e9bb9271f031f6ef852e3d5f33b9f46bff6d920b8622d44e69d6666f");
topj.passport(sendAccount);
ResponseBase<AccountInfoResponse> accountResult = topj.getAccount(sendAccount);
System.out.println("当前账户 nonce > "+accountResult.getData().getBalance());
System.out.println("当前账户 nonce > "+accountResult.getData().getNonce());
// 2. 接收者地址
Account toAccount = new Account();
// 3. 构建发送交易参数,签名信息
Transfer transfer = new Transfer();
TransferParams transferParams = new TransferParams(toAccount.getAddress(), BigInteger.valueOf(1000000), "your note");
// 发送交易方式一:
Map<String, String> requestTokenArgsMap = transfer.getArgs(sendAccount, Arrays.asList(transferParams));
System.out.println("交易体 > "+requestTokenArgsMap);
// 4.发送交易
ResponseBase<XTransactionResponse> result = httpService.send(requestTokenArgsMap, XTransactionResponse.class);
XTransaction xTransaction = ArgsUtils.decodeXTransFromArgs(requestTokenArgsMap);
XTransactionResponse xTransactionResponse = new XTransactionResponse();
xTransactionResponse.setOriginalTxInfo(xTransaction);
result.setData(xTransactionResponse);
System.out.println(result.getData().getOriginalTxInfo().getTxHash());
// 发送交易方式二:
ResponseBase<XTransactionResponse> result2 = topj.transfer(sendAccount,transferParams);
System.out.println(result2.getData().getOriginalTxInfo().getTxHash());
}
}
# 11. 交易超时机制
交易有两个字段,fire_timestamp字段表示发起交易的时间戳,要求和链上节点时间在5分钟的偏差之内,expire_duration字段表示交易在交易池持续的时间,范围0-65535秒。超时的交易将被丢弃。
有几种情况会导致交易超时:
- 客户端构建好交易后,过了较长时间才发到链上——如果是这种情况,可以将expire_duration字段设置成更大,默认是100秒。
- 客户端的时间同步功能有问题,落后于标准的UTC时间。
# 12. 如何计算交易手续费
机制说明:
- 免费机制。账号余额大于100TOP,预估一天能发10多笔免费的转账交易。
- 低费用。免费额度用完后,交易需要付费。对于转账交易,费用上限(也称为交易保证金txDeposit)设置为0.1TOP,可以保证100%成功,实际费用不会超过0.1TOP。
- 每个账户有0.1TOP是不能转出去的,账户至少要有0.1TOP才能发交易。
- 无论是否为跨片交易,还是片内交易,都是发送账户付费。
公式:
交易手续费 = used_deposit
(send_block_info
) + used_deposit
(confirm_block_info
) + tx_fee
。其中:
used_deposit
是作为手续费而被扣除的 TOP,当免费的 Tgas 充足时,该值为 0。- 对于普通交易,扣除的是
send_block_info
下的used_deposit
;对于合约交易,扣除的是confirm_block_info
下的used_deposit
,详见下方代码示例。 tx_fee
是一部分系统合约交易的固定手续费(例如在注册节点时会扣除 100 TOP 手续费),对于普通转账交易,该值为 0。
{
"data": {
"original_tx_info": {
"amount": 0,
"authorization": "0x00da74315ede21da0ebc0ce4f8d1fb8409c978c74a0be4d7660410e3eae7ebcfa36f386bff302c3fd6c7c1be040076fe7f5cda50afc7f842aa71bf05d1a6feea02",
"edge_nodeid": "",
"ext": "",
"last_tx_nonce": 0,
"note": "",
"premium_price": 0,
"receiver_account": "T800002276a7d58218ac4978733e5cca927a7d86cb7c87",
"receiver_action_name": "",
"receiver_action_param": "0x2e00000054383030303033376434666263303862663435313361363861323837656432313862306164626434393765663330",
"send_timestamp": 1631791128,
"sender_account": "T8000037d4fbc08bf4513a68a287ed218b0adbd497ef30",
"sender_action_name": "",
"sender_action_param": "",
"token_name": "",
"tx_deposit": 100000,
"tx_expire_duration": 100,
"tx_hash": "0xfb33b056757f7d3ba6bccd0c8cd1a923a68dec1fd0c0633f513cee58214b648d",
"tx_len": 189,
"tx_structure_version": 2,
"tx_type": 0
},
"tx_consensus_state": {
"confirm_block_info": {
"account": "Ta0000@39",
"exec_status": "success",
"height": 7,
"recv_tx_exec_status": "success",
"used_deposit": 0,
"used_gas": 0
},
"recv_block_info": {
"account": "Ta0000@55",
"height": 7,
"used_gas": 0
},
"send_block_info": {
"account": "Ta0000@39",
"height": 4,
"tx_fee": 0,
"used_deposit": 0,
"used_gas": 468
}
},
"tx_state" : "success"
},
"errmsg": "ok",
"errno": 0,
"sequence_id": "17"
}
# 13. (高级用法)如何让创建的所有用户地址,都分布在同一个 Table 子链下
package org.topnetwork.account;
import java.io.IOException;
import org.topnetwork.account.property.AccountUtils;
import com.alibaba.fastjson.JSONObject;
/**
* 构建离线 account
*/
public class CreateOfflineAccount {
public static void main(String[] args) throws IOException {
// 指定 table 创建离线地址,targetTableId[0,63]
int targetTableId = 0;
Account account1 = AccountUtils.genAccount(targetTableId);
System.out.println("account1 > "+ JSONObject.toJSONString(account1));
}
}
# Table 链相关
# 14. 查询用户账户所在的 Table 子链地址以及最新块高
package org.topnetwork.account;
import java.io.IOException;
import org.topnetwork.account.property.AccountUtils;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.AccountInfoResponse;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.methods.response.block.TableBlockResponse;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
import com.alibaba.fastjson.JSONObject;
/**
* 查询用户账号所在的 Table 子链地址,以及最新块高
*/
public class CheckAccount {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
// 离线获取指定地址对应的 table 子链 id[0,63]
int tableId = AccountUtils.getAddressTableId(account2.getAddress());
System.out.println("tableId::"+tableId);
// 查询帐户最新块高
ResponseBase<TableBlockResponse> lastTableBlock = topj.getLastTableBlock(account2,account2.getAddress());
System.out.println("Last Block info > "+ lastTableBlock.getData().getValue().getTableHeight());
}
}
# 15. 查询指定 Table 子链下指定块高
package org.topnetwork.block;
import java.io.IOException;
import org.topnetwork.account.Account;
import org.topnetwork.account.property.AccountUtils;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.methods.response.block.TableBlockResponse;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
import com.alibaba.fastjson.JSONObject;
/**
* 查询指定帐户所属子链的块信息
*/
public class GetTableBlockByHeight {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
int height = 67;// 指定块高
String address = "T80000f4d41bf4035e972649a8168ba06a15fa19a15ded";//指定地址
Account account=new Account();
account.setAddress(address);
topj.passport(account);
// 指定帐户所在的子链地址
String targetTableAccount = AccountUtils.getAddressTable(account.getAddress());
// 查询指定 Table 子链下指定块高的块信息
ResponseBase<TableBlockResponse> subTableIdBlock = topj.getTableBlockByHeight(account, targetTableAccount,height);
System.out.println("Block info > "+ JSONObject.toJSONString(subTableIdBlock));
}
}
# 16. 扫描指定 Table 子链下的最新块
package org.topnetwork.block;
import java.io.IOException;
import org.topnetwork.account.Account;
import org.topnetwork.account.property.AccountUtils;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.methods.response.block.TableBlockResponse;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
import com.alibaba.fastjson.JSONObject;
/**
* 查询指定 Table 子链最新的块信息
*/
public class GetTableBlockByTableId {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
int height = 67;// 指定块高
String address = "T80000f4d41bf4035e972649a8168ba06a15fa19a15ded";//指定地址
Account account=new Account();
account.setAddress(address);
topj.passport(account);
// 指定帐户所在的子链地址
String targetTableAccount = AccountUtils.getAddressTable(account.getAddress());
// 查询指定 Table 子链最新的块信息
ResponseBase<TableBlockResponse> subTableIdBlock = topj.getLastTableBlock(account, targetTableAccount);
System.out.println("Block info > "+ JSONObject.toJSONString(subTableIdBlock));
}
}
# 17. 如何扫描所有的 Table 下指定高度的块
遍历 Ta0000@0 ~ Ta0000@63,扫描每一个 Table 子链中高度为 0 的块。
package org.topnetwork.block;
import java.io.IOException;
import org.topnetwork.account.Account;
import org.topnetwork.account.property.AccountUtils;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.methods.response.block.TableBlockResponse;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
import org.topnetwork.utils.TopjConfig;
import com.alibaba.fastjson.JSONObject;
/**
* 扫描所有子链的块
*/
public class ScanAllTableBlock {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
// 请求失败每 5s 循环调用,最多 3 次 默认 topj.setTransactionReceiptProcessor(new NoOpProcessor());
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
Account account=new Account();
topj.passport(account);
// 扫描指定子链帐户下的块信息,height 从 0 开始 ,
// 扫描所有的 tabe 子链 [0-63],可以选择每个子链开启线程 height 从 0 开始扫描,最终到 latest height
int height = 0;
for (int i=0;i<64;i++){
// 子链地址
String targetTableAddress = TopjConfig.getShardingTableBlockAddr() + "@" + i;
ResponseBase<TableBlockResponse> subTableIdBlock = topj.getTableBlockByHeight(account, targetTableAddress,height);
System.out.println("Block info > table" +i +" >"+ JSONObject.toJSONString(subTableIdBlock));
}
}
}
# 18. 如何查询所有 Table 子链的最新高度
package org.topnetwork.block;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import org.topnetwork.account.Account;
import org.topnetwork.core.Topj;
import org.topnetwork.methods.response.ResponseBase;
import org.topnetwork.procotol.http.HttpService;
import org.topnetwork.tx.PollingTransactionReceiptProcessor;
import com.alibaba.fastjson.JSON;
/**
* 如何查询所有 Table 子链的最新高度
*/
public class GetAllLastTableBlockHeight {
private static Topj topj =null;
public static void main(String[] args) throws IOException {
HttpService httpService = new HttpService("http://206.189.210.106:19081");
topj = Topj.build(httpService);
topj.setTransactionReceiptProcessor(new PollingTransactionReceiptProcessor(5000, 3));
// 构建随机帐户
Account firstAccount = new Account();
// 设置 identityToken
topj.passport(firstAccount);
// 获取 64 个 table 的最新高度
ResponseBase<List<BigInteger>> latestTables = topj.getLatestTables(firstAccount);
System.out.println("latestTables info > " + JSON.toJSONString(latestTables.getData()));
}
}
# 浏览器相关
# 19. 如何从 TOP 浏览器查询一个账户信息
点击此处 (opens new window) 进入 TOPscan 查询账户信息。
# 20. 如何从 TOP 浏览器查询一笔交易
点击此处 (opens new window) 进入 TOPscan 查询交易。