Giao dịch TRON pending, expired hay không tìm thấy: mỗi trường hợp nghĩa là gì với một lần chuyển USDT
TRON tạo một khối mỗi ba giây, nên năm phút trên chuỗi là một trăm khối. Một lần chuyển USDT vẫn hiện là pending sau chừng ấy thời gian đang nằm ở một trong bốn chỗ: đã ký nhưng chưa bao giờ được phát đi, đã được một nút chấp nhận nhưng chưa vào khối, nằm trong một khối chưa thể đảo ngược, hoặc đã chung cuộc trên chuỗi và đang đợi nền tảng nhận ghi có cho nó. Hai chữ khác thường xuất hiện trên đường đi: một block explorer không tìm thấy mã băm, và một nút gọi giao dịch là expired. Mỗi trường hợp có cách sửa riêng, và một trong các cách sửa, nếu áp dụng quá sớm, sẽ trả tiền cho cùng một lần chuyển hai lần.
Mỗi giao dịch mang hạn chót của riêng nó
Khoảng cách giữa các khối là một hằng số của giao thức, 3,000 mili giây. Con số kia nằm bên trong giao dịch. Khi một chiếc ví dựng một lần chuyển, nó ghi một thời điểm expiration vào raw_data, phần được ký, và mọi nút đều kiểm tra nó. Một giao dịch có thời điểm hết hạn đã qua bị từ chối, và giao dịch có thời điểm hết hạn nằm quá một ngày sau khối đầu chuỗi của nút cũng vậy. Chữ của nút cho cả hai là TRANSACTION_EXPIRATION_ERROR.
Một cặp trường thứ hai buộc giao dịch vào một khối gần đây. ref_block_bytes và ref_block_hash nêu tên một khối mà mạng lưới vẫn còn giữ, và một nút nhớ 65,536 khối gần nhất, khoảng 54 giờ của chuỗi. Một tham chiếu cũ hơn thế, hoặc lấy từ một mạng thử nghiệm, thì nhận TAPOS_ERROR thay vào đó. Đồng hồ của cả hai bắt đầu chạy khi giao dịch được dựng.
Bốn điều mà «pending» có thể có nghĩa
Đã ký, chưa bao giờ được phát
Một chiếc ví hoặc một kịch bản chi trả có thể ký một lần chuyển rồi không bao giờ trao nó cho một nút, sau một lần quá thời gian chờ hoặc một vụ sập giữa lúc ký và lúc gửi. Lần chuyển vẫn có mã băm, vì mã băm được tính từ chính các byte của giao dịch. Nó là SHA-256 của raw_data, và nó tồn tại trước khi bất kỳ nút nào thấy gì. Một mã băm trong nhật ký của bạn chỉ chứng minh lần chuyển đã được dựng. Một block explorer trả lời «không tìm thấy» cho nó là đúng: không nút nào mà nó đọc từ đó giữ những byte ấy.
Đã được một nút chấp nhận, chưa vào khối
Một nút nhận một giao dịch sẽ trả lời ngay và giữ nó trong nhóm giao dịch đang chờ của mình cho tới khi một khối mang nó đi. Việc chấp nhận và việc được đưa vào khối là hai sự kiện riêng, và các trạng thái đơn hàng của chúng tôi giữ chúng tách biệt: ở mode B, nơi chúng tôi phát một lần chuyển mà khách hàng đã ký, broadcasted nghĩa là một nút đã chấp nhận giao dịch và chưa nói gì về một khối. Trên một chuỗi ba giây một khối, trạng thái này ngắn. Một nút cũng có thể chấp nhận một giao dịch mà không khối nào từng mang, thường vì nó bị loại khỏi nhóm đó. Một lần chuyển như vậy mất hẳn khi thời điểm hết hạn của nó trôi qua.
Đã vào khối, chưa thể đảo ngược
Các khối mới nhất ở đầu chuỗi vẫn có thể bị thay thế. TRON giữ một con trỏ thứ hai phía sau đầu chuỗi, khối đã chốt (solidified) mới nhất, là khối mới nhất mà mạng lưới coi là không thể đảo ngược, và một nút phục vụ cả hai. Khoảng cách giữa chúng là thời gian một lần chuyển nằm trong khối mà chưa chung cuộc. Chúng tôi đọc cả hai con trỏ một lần từ một nút đầy đủ công khai, bằng hai lệnh gọi thực hiện cùng một thời điểm.
| Đọc ngày 27 tháng 10 năm 2026, 21:27 UTC | Số khối | Thời gian khối, UTC |
|---|---|---|
| Khối mới nhất | 87,487,718 | 21:27:06 |
| Khối đã chốt mới nhất | 87,487,699 | 21:26:09 |
| Chênh lệch | 19 khối | 57 giây |
Chênh lệch về số khối và chênh lệch về dấu thời gian khớp nhau ở mức ba giây một khối. Các mục mode B của chúng tôi chỉ tới confirmed sau khi khối được chốt, mà tài liệu tham khảo API của chúng tôi ghi là khoảng một phút, và lần đọc phù hợp với con số đó. Từ đó có câu trả lời thông thường cho việc một lần chuyển USDT trên TRON mất bao lâu: một khối mỗi ba giây, và việc chốt cuối cùng khoảng một phút sau. Đó chỉ là một lần đọc từ một nút. Chúng tôi chưa đo khoảng chênh dịch chuyển ra sao trong một ngày, cũng chưa đo thời gian của chính các đơn hàng của mình từ lúc giao tới lúc phát tới lúc vào khối.
Đã chung cuộc trên chuỗi, chưa được ghi có
Một sàn giao dịch hoặc một bộ xử lý thanh toán ghi có một khoản nạp sau một số khối mà nó tự đặt ra. Chúng tôi không biết số đó của bất kỳ nền tảng nào và không trích dẫn con số nào. Trước khi hỏi nền tảng, hãy đọc kết quả được ghi bên cạnh lần chuyển. Một lần chuyển có thể nằm trong khối mà vẫn hỏng, phí đã tiêu và không token nào dịch chuyển, và bất cứ thứ gì khác SUCCESS ở chỗ đó đều là một thất bại (OUT_OF_ENERGY nghĩa là gì, và những cách khác khiến một lần chuyển USDT hỏng). Một lần chuyển thành công trong một khối đã chốt đã tới địa chỉ của người nhận. Phần còn lại là sổ sách của nền tảng, và bộ phận hỗ trợ của họ có thể truy vết nó từ mã băm.
Expired nghĩa là gì, và cách gửi lại
Quá thời điểm hết hạn, một giao dịch không thể vào bất kỳ khối nào. Mọi nút đều từ chối nó, nên phát lại chính những byte đã ký ấy chỉ thu thêm một lời từ chối nữa. Cách khôi phục là một giao dịch mới: dựng lại lần chuyển, với một thời điểm hết hạn mới và một tham chiếu tới một khối gần đây, rồi ký nó.
Việc dựng lại không trả tiền hai lần. Một giao dịch mà không khối nào mang thì chưa bao giờ được thực thi: nó không chuyển token nào và không đốt gì, vì một lần chuyển tiêu năng lượng và TRX của nó trong lúc chạy trong một khối. Một khi giao dịch đã nằm trong một khối, không nút nào sẽ chạy nó lần thứ hai. Cách duy nhất để gửi tiền hai lần là ký một giao dịch thay thế trong lúc bản gốc vẫn còn có thể tới nơi. Một nút xét thời điểm hết hạn theo thời gian của khối đầu chuỗi của nó, thứ có thể chậm hơn đồng hồ của bạn, nên một khối được tạo ra trong những giây cuối trước hạn chót vẫn có thể mang bản gốc, và một nút hay block explorer bị trễ có thể chưa hiển thị nó. Phần mềm đã dựng bản gốc giữ nó và có thể đọc raw_data.expiration, tính bằng mili giây kể từ epoch. Hãy đợi cho tới khi khối đã chốt mới nhất vượt qua thời điểm đó, mà trong lần đọc của chúng tôi mất lâu hơn khoảng một phút, rồi hỏi một nút theo mã băm. Nếu nút vẫn không biết giao dịch ấy, bản gốc không còn có thể tới nơi nữa, và lần chuyển mới là lần duy nhất.
Pending và expired trên một đơn hàng năng lượng
Năng lượng thuê thêm một chiếc đồng hồ thứ hai. Khi năng lượng cho một đơn hàng được giao, đơn hàng mang theo send_before, thời hạn thuê trừ ba giây: 297 giây ở thời hạn thuê năm phút và 3,597 ở thời hạn một giờ. Cửa sổ được tính từ lần ủy quyền mà chúng tôi thấy được xác nhận, và thời hạn thuê trên chuỗi đã bắt đầu sớm hơn một khối và một chu kỳ hỏi lại, nên hãy coi những giây cuối của cửa sổ là đã mất (Năng lượng TRON thuê thực sự kéo dài bao lâu). Một lần chuyển tới một khối sau khi năng lượng đã rời ví sẽ đốt TRX của người gửi ở mức giao thức là 100 sun mỗi đơn vị, khoảng 6.5 TRX cho một lần chuyển tới địa chỉ đang giữ USDT.
Điều gì xảy ra khi cửa sổ đóng phụ thuộc vào ai gửi. Ở mode A bạn tự phát lần chuyển. Chúng tôi theo dõi mạng lưới, đánh dấu mục là sent khi lần chuyển của bạn xuất hiện, và gửi webhook order.item.sent kèm mã băm của nó trong data.txid. Nếu tới send_before mà chưa có lần chuyển nào xuất hiện, mục chuyển sang expired và bị tính tiền, vì năng lượng đã được giao.
Ở mode B, bạn trao cho chúng tôi một giao dịch đã ký và chúng tôi phát nó ngay khi năng lượng đáp xuống (mode B hoạt động ra sao). Mục đi qua broadcasting và broadcasted tới confirmed, trạng thái cuối chỉ sau khi khối được chốt. Chúng tôi không bao giờ phát sau send_before: một mục mà chúng tôi không gửi kịp sẽ đóng ở failed với error: broadcast_window_missed, và phần giữ lại được nhả ra đầy đủ. Cửa sổ ở đó còn bị chặn trên bởi thời điểm hết hạn của chính giao dịch, trừ một biên cho việc phát, nên một giao dịch tới chỗ chúng tôi khi còn ít thời gian sống sẽ nhận một cửa sổ ngắn.
Mode B cũng kiểm tra thời điểm hết hạn ngay từ đầu vào. Khi chúng tôi nhận giao dịch, nó cần còn ít nhất 180 giây sống và không quá 23 giờ 59 phút. Một hạn chót quá xa trả về dưới dạng 400 invalid_request với details.reason đặt là expiration_too_far, còn quá ít thời gian sống thì trả về cùng 400 đó chỉ với details.index. Cả hai câu trả lời đều tới trước khi bất kỳ năng lượng nào được mua.
Cần kiểm tra gì, theo thứ tự
- Có nút nào từng chấp nhận giao dịch hay không. Phần mềm đã gửi nó giữ câu trả lời của nút, hoặc không giữ gì vì việc phát chưa bao giờ xảy ra. Một mã băm tự nó không giải quyết được gì, vì nó tồn tại trước mọi lần phát.
- Mã băm có được tìm thấy hay không, trên một block explorer hoặc từ một nút được hỏi theo mã băm. Nếu không tìm thấy mà thời điểm hết hạn còn ở phía trước, hãy phát lại chính những byte đã ký ấy. Nếu khối đã chốt mới nhất đã vượt qua thời điểm hết hạn mà mã băm vẫn không được tìm thấy, hãy dựng một giao dịch mới và ký nó.
- Kết quả bên cạnh một mã băm đã tìm thấy.
SUCCESSnghĩa là lần chuyển đã đi qua. Bất cứ thứ gì khác nghĩa là nó đã chạy và hỏng, và phí đã tiêu rồi. - Khối của nó đã được chốt chưa. Trong lần đọc của chúng tôi, khối không thể đảo ngược mới nhất chậm hơn đầu chuỗi khoảng một phút, nên một lần chuyển thành công chưa được một phút thì vẫn chưa được chốt.
- Số khối riêng của nền tảng nhận, và sau đó là bộ phận hỗ trợ của họ, kèm mã băm.
- Trên một đơn hàng của chúng tôi, là mục:
sentkèmtxidcủa nó ở mode A,confirmedở mode B. Khi cửa sổ đóng trước, mode A hiệnexpiredvà mode B hiệnfailedvớierror: broadcast_window_missed. Mộtexpiredở mode B nghĩa là một nút đã từ chối giao dịch vì chính bản chất của nó, hoặc giao dịch đã revert (bị hoàn tác) trong một khối, và nó bị tính tiền.
Hãy xem một mục nằm ở ready rồi chuyển sang expired mà không có gì thật bị đặt cược: môi trường thử nghiệm có một người nhận mà lần chuyển của nó không bao giờ tới →