本篇文章介绍fullnode节点收到用户发送的过来的交易之后的处理流程,一般用户通过http接口将签名好的交易发送到fullnode节点, fullnode节点会对交易进行相关的检查, 然后执行交易,如果执行的结果没有问题, 就会广播交易。当然其他节点收到这笔广播的交易之后也会做相同的操作。
1 fullnode http 处理函数
//java-tron/src/main/java/org/tron/core/services/http/BroadcastServlet
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
try {
String input = request.getReader().lines()
.collect(Collectors.joining(System.lineSeparator()));
Util.checkBodySize(input);
boolean visible = Util.getVisiblePost(input);
Transaction transaction = Util.packTransaction(input, visible);
GrpcAPI.Return retur = wallet.broadcastTransaction(transaction);
response.getWriter().println(JsonFormat.printToString(retur, visible));
} catch (Exception e) {
logger.debug("Exception: {}", e.getMessage());
try {
response.getWriter().println(Util.printErrorMsg(e));
} catch (IOException ioe) {
logger.debug("IOException: {}", ioe.getMessage());
}
}
}
}
用户通过http发送的广播交易的数据包会被传到这里处理,这个函数调用了wallet.broadcastTransaction进行处理。
2 broadcastTransaction 函数
///Users/tron/tron-ws/java-tron/src/main/java/org/tron/core/Wallet.java
//交易广播
//task1:确认可广播的节点
//task2:判断本地是否能够接收这笔交易
//task3:预执行交易,将交易放入pending列表
//task4:错误处理
public GrpcAPI.Return broadcastTransaction(Transaction signaturedTransaction) {
GrpcAPI.Return.Builder builder = GrpcAPI.Return.newBuilder();
//----------------------------------------------------------------------
//task1:确认可广播的节点
//----------------------------------------------------------------------
//将transaction类型转换成TransactionCapsule类型
TransactionCapsule trx = new TransactionCapsule(signaturedTransaction);
try {
Message message = new TransactionMessage(signaturedTransaction.toByteArray());
//如果允许的最小的链接数量不为0
if (minEffectiveConnection != 0) {
//如果当前活跃节点数为空,返回错误
if (tronNetDelegate.getActivePeer().isEmpty()) {
logger.warn("Broadcast transaction {} failed, no connection.", trx.getTransactionId());
return builder.setResult(false).setCode(response_code.NO_CONNECTION)
.setMessage(ByteString.copyFromUtf8("no connection"))
.build();
}
//找出可广播节点,满足如下条件(1.活跃, 2.不需要互相同步的节点)
int count = (int) tronNetDelegate.getActivePeer().stream()
.filter(p -> !p.isNeedSyncFromUs() && !p.isNeedSyncFromPeer())
.count();
//如果可广播节点小于允许的最小链接数量,返回错误
if (count < minEffectiveConnection) {
String info = "effective connection:" + count + " lt minEffectiveConnection:"
+ minEffectiveConnection;
logger.warn("Broadcast transaction {} failed, {}.", trx.getTransactionId(), info);
return builder.setResult(false).setCode(response_code.NOT_ENOUGH_EFFECTIVE_CONNECTION)
.setMessage(ByteString.copyFromUtf8(info))
.build();
}
}
//----------------------------------------------------------------------
//task2:判断本地是否能够接收这笔交易
//----------------------------------------------------------------------
//等待交易过多,网络阻塞,pendign列表 + repush列表总和 > 2000
if (dbManager.isTooManyPending()) {
logger.warn("Broadcast transaction {} failed, too many pending.", trx.getTransactionId());
return builder.setResult(false).setCode(response_code.SERVER_BUSY).build();
}
//如果本节点是sr节点, 并且在出块,拒绝交易,返回错误
if (dbManager.isGeneratingBlock()) {
logger
.warn("Broadcast transaction {} failed, is generating block.", trx.getTransactionId());
return builder.setResult(false).setCode(response_code.SERVER_BUSY).build();
}
//如果交易已经收到过了,拒绝交易,返回错误
if (dbManager.getTransactionIdCache().getIfPresent(trx.getTransactionId()) != null) {
logger.warn("Broadcast transaction {} failed, is already exist.", trx.getTransactionId());
return builder.setResult(false).setCode(response_code.DUP_TRANSACTION_ERROR).build();
} else {
//如果没有收到过, 将交易放入idcache
dbManager.getTransactionIdCache().put(trx.getTransactionId(), true);
}
//初始化transaction的result,为执行智能合约做准备
if (dbManager.getDynamicPropertiesStore().supportVM()) {
trx.resetResult();
}
//---------------------------------------------------