# 交易所 FAQ
# 常用信息
# 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 会对所管辖的账户的交易进行打包并独立出块。
64 个 Table 子链地址对应 Ta0000@0 ~ Ta0000@63。
64 个 Table 子链序号(ID)为 0 ~ 63。
# 4. 账户地址格式
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. 如何获取用户地址下的余额
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 查询对应的 Table 块
Self 交易为发送和接受均为自己的地址,所以 self 交易只有一个块,而非 self 交易每笔交易有 3 个块。
send block 对应发送交易的块。
recv block 对应接收交易的块。
confirm block 对应确认交易的块。
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));
}
}
# 9. 如何发送交易,以及如何在交易里携带 Memo 信息
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());
}
}
# 10. 如何计算交易手续费
交易手续费 = 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"
}
# 11. (高级用法)如何让创建的所有用户地址,都分布在同一个 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 链相关
# 12. 查询用户账户所在的 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());
}
}
# 13. 查询指定 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));
}
}
# 14. 扫描指定 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));
}
}
# 15. 如何扫描所有的 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));
}
}
}
# 16. 如何查询所有 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()));
}
}
# 浏览器相关
# 17. 如何从 TOP 浏览器查询一个账户信息
点击此处 (opens new window) 进入 TOPscan 查询账户信息。
# 18. 如何从 TOP 浏览器查询一笔交易
点击此处 (opens new window) 进入 TOPscan 查询交易。