Skip to content

Commit 64e5150

Browse files
authored
feat: backport TON PRs (#3705)
* feat(ton): lite-server connection tweaks (#3697) [backport] * feat(ton): send real gas usage (#3699) [backport]
1 parent ecb332b commit 64e5150

File tree

8 files changed

+80
-65
lines changed

8 files changed

+80
-65
lines changed

changelog.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
* [3702](https://github.com/zeta-chain/node/pull/3702) - upgrade cosmos sdk to v0.50.13
88

9+
### Features
10+
* [3699](https://github.com/zeta-chain/node/pull/3699) - use real gas usage for TON withdrawals
11+
912
## v29.0.2
1013

1114
### Fixes
@@ -18,7 +21,7 @@
1821
### Fixes
1922

2023
* [3664](https://github.com/zeta-chain/node/pull/3664/) - add a check to stop posting inbound votes if the cctx has already been created
21-
24+
2225
## v29.0.0
2326

2427
### Breaking Changes

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ require (
131131
github.com/elastic/gosigar v0.14.2 // indirect
132132
github.com/felixge/httpsnoop v1.0.4 // indirect
133133
github.com/flynn/noise v1.0.0 // indirect
134-
github.com/fsnotify/fsnotify v1.7.0 // indirect
134+
github.com/fsnotify/fsnotify v1.7.0
135135
github.com/gagliardetto/binary v0.8.0
136136
github.com/gagliardetto/treeout v0.1.4 // indirect
137137
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
@@ -310,7 +310,7 @@ require (
310310
github.com/cosmos/ibc-go/modules/capability v1.0.1
311311
github.com/montanaflynn/stats v0.7.1
312312
github.com/showa-93/go-mask v0.6.2
313-
github.com/tonkeeper/tongo v1.9.3
313+
github.com/tonkeeper/tongo v1.14.8
314314
github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20250212192042-34095b214e51
315315
)
316316

go.sum

+2-6
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,6 @@ github.com/cosmos/cosmos-db v1.1.1 h1:FezFSU37AlBC8S98NlSagL76oqBRWq/prTPvFcEJNC
420420
github.com/cosmos/cosmos-db v1.1.1/go.mod h1:AghjcIPqdhSLP/2Z0yha5xPH3nLnskz81pBx3tcVSAw=
421421
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
422422
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
423-
github.com/cosmos/cosmos-sdk v0.50.12 h1:WizeD4K74737Gq46/f9fq+WjyZ1cP/1bXwVR3dvyp0g=
424-
github.com/cosmos/cosmos-sdk v0.50.12/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw=
425423
github.com/cosmos/cosmos-sdk v0.50.13 h1:xQ32hhzVy7agEe7behMdZN0ezWhPss3KoLZsF9KoBnw=
426424
github.com/cosmos/cosmos-sdk v0.50.13/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw=
427425
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
@@ -1357,8 +1355,8 @@ github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0h
13571355
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
13581356
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
13591357
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
1360-
github.com/tonkeeper/tongo v1.9.3 h1:VNIZIuPeMw0+KZPvP57+EbgRwGZocN2v5CulRxba20A=
1361-
github.com/tonkeeper/tongo v1.9.3/go.mod h1:MjgIgAytFarjCoVjMLjYEtpZNN1f2G/pnZhKjr28cWs=
1358+
github.com/tonkeeper/tongo v1.14.8 h1:hIj3rGqAhhPxHBiFXAwDDELEw63hLcQlLdSztmEIyaA=
1359+
github.com/tonkeeper/tongo v1.14.8/go.mod h1:MjgIgAytFarjCoVjMLjYEtpZNN1f2G/pnZhKjr28cWs=
13621360
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
13631361
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
13641362
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
@@ -1404,8 +1402,6 @@ github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 h1:FmO3HfVdZ7
14041402
github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4/go.mod h1:TBv5NY/CqWYIfUstXO1fDWrt4bDoqgCw79yihqBspg8=
14051403
github.com/zeta-chain/go-tss v0.0.0-20241216161449-be92b20f8102 h1:jMb9ydfDFjgdlxpn8zClEPlUIJcz9ElahaAAXUPNFv0=
14061404
github.com/zeta-chain/go-tss v0.0.0-20241216161449-be92b20f8102/go.mod h1:nqelgf4HKkqlXaVg8X38a61WfyYB+ivCt6nnjoTIgCc=
1407-
github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20250124151021-87b63e845f1c h1:iD7O6gFot1QHM6ggrt96N9eXnZ7vqkg2mFVm7OTaisw=
1408-
github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20250124151021-87b63e845f1c/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w=
14091405
github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20250225132027-d46f98d569a9 h1:rMTvyhs7NR8REZnVdhUr6h9PqfqRvZlu18R4Zv4GnBI=
14101406
github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20250225132027-d46f98d569a9/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w=
14111407
github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20250212192042-34095b214e51 h1:r3cG+whGN8MFwfLG2Y2Irs2x1zyMznUDJHcOgV2X4UM=

zetaclient/chains/sui/sui.go

-6
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,6 @@ func (s *Sui) Start(ctx context.Context) error {
6363
return !app.IsOutboundObservationEnabled()
6464
})
6565

66-
// todo
67-
// - [ ] ObserveInbound
68-
// - [ ] ProcessInboundTrackers
69-
// - [ ] ProcessOutboundTrackers
70-
// - [ ] ScheduleCCTX
71-
7266
register := func(exec scheduler.Executable, name string, opts ...scheduler.Opt) {
7367
opts = append([]scheduler.Opt{
7468
scheduler.GroupName(s.group()),

zetaclient/chains/ton/liteapi/client.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,16 @@ func NewFromSource(ctx context.Context, urlOrPath string) (*Client, error) {
4444
return nil, errors.Wrap(err, "unable to get config")
4545
}
4646

47+
// most likely, cfg would contain a single lite server (or a small group)
48+
// thus we want several connection per lite-server to speed up the requests
49+
const workers = 8
50+
4751
client, err := liteapi.NewClient(
4852
liteapi.WithConfigurationFile(*cfg),
49-
liteapi.WithDetectArchiveNodes(),
53+
liteapi.WithMaxConnectionsNumber(len(cfg.LiteServers)),
54+
liteapi.WithWorkersPerConnection(workers),
5055
)
56+
5157
if err != nil {
5258
return nil, errors.Wrap(err, "unable to create client")
5359
}

zetaclient/chains/ton/observer/inbound.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ func (ob *Observer) voteDeposit(
254254
eventIndex = 0 // not a smart contract call
255255
coinType = coin.CoinType_Gas
256256
asset = "" // empty for gas coin
257-
gasLimit = 0
257+
gasLimit = maxGasLimit
258258
retryGasLimit = zetacore.PostVoteInboundExecutionGasLimit
259259
)
260260

zetaclient/chains/ton/observer/observer.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package observer
22

33
import (
44
"context"
5+
"sync/atomic"
56
"time"
67

78
lru "github.com/hashicorp/golang-lru"
@@ -23,6 +24,8 @@ type Observer struct {
2324
gateway *toncontracts.Gateway
2425

2526
outbounds *lru.Cache
27+
28+
latestGasPrice atomic.Uint64
2629
}
2730

2831
const outboundsCacheSize = 1024
@@ -83,14 +86,19 @@ func (ob *Observer) PostGasPrice(ctx context.Context) error {
8386
return errors.Wrap(err, "failed to get latest masterchain block")
8487
}
8588

89+
blockNum := uint64(blockID.Seqno)
90+
8691
// There's no concept of priority fee in TON
8792
const priorityFee = 0
8893

89-
_, errVote := ob.
90-
ZetacoreClient().
91-
PostVoteGasPrice(ctx, ob.Chain(), gasPrice, priorityFee, uint64(blockID.Seqno))
94+
_, err = ob.ZetacoreClient().PostVoteGasPrice(ctx, ob.Chain(), gasPrice, priorityFee, blockNum)
95+
if err != nil {
96+
return errors.Wrap(err, "failed to post gas price")
97+
}
98+
99+
ob.setLatestGasPrice(gasPrice)
92100

93-
return errVote
101+
return nil
94102
}
95103

96104
// CheckRPCStatus checks TON RPC status and alerts if necessary.
@@ -123,3 +131,13 @@ func (ob *Observer) getLatestMasterchainBlock(ctx context.Context) (ton.BlockIDE
123131

124132
return mc.Last.ToBlockIdExt(), nil
125133
}
134+
135+
func (ob *Observer) getLatestGasPrice() (uint64, bool) {
136+
price := ob.latestGasPrice.Load()
137+
138+
return price, price != 0
139+
}
140+
141+
func (ob *Observer) setLatestGasPrice(price uint64) {
142+
ob.latestGasPrice.Store(price)
143+
}

zetaclient/chains/ton/observer/outbound.go

+42-44
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,25 @@ import (
1010
"github.com/zeta-chain/node/pkg/chains"
1111
"github.com/zeta-chain/node/pkg/coin"
1212
toncontracts "github.com/zeta-chain/node/pkg/contracts/ton"
13-
cc "github.com/zeta-chain/node/x/crosschain/types"
13+
cctypes "github.com/zeta-chain/node/x/crosschain/types"
1414
"github.com/zeta-chain/node/zetaclient/chains/interfaces"
1515
"github.com/zeta-chain/node/zetaclient/chains/ton/liteapi"
16-
gasconst "github.com/zeta-chain/node/zetaclient/zetacore"
16+
"github.com/zeta-chain/node/zetaclient/logs"
17+
"github.com/zeta-chain/node/zetaclient/zetacore"
1718
)
1819

20+
// https://tonscan.com/config-parameters (N21: "Computation costs")
21+
// This might changes in the future by TON's gov proposal (very unlikely though)
22+
const maxGasLimit = 1_000_000
23+
1924
type outbound struct {
2025
tx *toncontracts.Transaction
2126
receiveStatus chains.ReceiveStatus
2227
nonce uint64
2328
}
2429

2530
// VoteOutboundIfConfirmed checks outbound status and returns (continueKeysign, error)
26-
func (ob *Observer) VoteOutboundIfConfirmed(ctx context.Context, cctx *cc.CrossChainTx) (bool, error) {
31+
func (ob *Observer) VoteOutboundIfConfirmed(ctx context.Context, cctx *cctypes.CrossChainTx) (bool, error) {
2732
nonce := cctx.GetCurrentOutboundParam().TssNonce
2833

2934
outboundRes, exists := ob.getOutboundByNonce(nonce)
@@ -39,8 +44,7 @@ func (ob *Observer) VoteOutboundIfConfirmed(ctx context.Context, cctx *cc.CrossC
3944
// TODO: Add compliance check
4045
// https://github.com/zeta-chain/node/issues/2916
4146

42-
txHash := liteapi.TransactionToHashString(outboundRes.tx.Transaction)
43-
if err = ob.postVoteOutbound(ctx, cctx, withdrawal, txHash, outboundRes.receiveStatus); err != nil {
47+
if err = ob.postVoteOutbound(ctx, cctx, outboundRes, withdrawal); err != nil {
4448
return false, errors.Wrap(err, "unable to post vote")
4549
}
4650

@@ -95,7 +99,7 @@ func (ob *Observer) ProcessOutboundTrackers(ctx context.Context) error {
9599

96100
// processOutboundTracker checks TON tx and stores it in memory for further processing
97101
// by VoteOutboundIfConfirmed.
98-
func (ob *Observer) processOutboundTracker(ctx context.Context, cctx *cc.CrossChainTx, txHash string) error {
102+
func (ob *Observer) processOutboundTracker(ctx context.Context, cctx *cctypes.CrossChainTx, txHash string) error {
99103
if cctx.InboundParams.CoinType != coin.CoinType_Gas {
100104
return errors.New("only gas cctxs are supported")
101105
}
@@ -204,73 +208,67 @@ func (ob *Observer) setOutboundByNonce(o outbound) {
204208

205209
func (ob *Observer) postVoteOutbound(
206210
ctx context.Context,
207-
cctx *cc.CrossChainTx,
211+
cctx *cctypes.CrossChainTx,
212+
outboundRes outbound,
208213
w toncontracts.Withdrawal,
209-
txHash string,
210-
status chains.ReceiveStatus,
211214
) error {
212-
// I. Gas
213-
// TON implements a different tx fee model. Basically, each operation in our Gateway has a
214-
// tx_fee(operation) which is based on hard-coded gas values per operation
215-
// multiplied by the current gas fees on-chain. Each withdrawal tx takes gas directly
216-
// from the Gateway i.e. gw pays tx fees for itself.
217-
//
218-
// - Gas price is stores in zetacore thanks to Observer.postGasPrice()
219-
// - Gas limit should be hardcoded in TON ZRC-20
220-
//
221-
// II. Block height
222-
// TON doesn't sequential block height because different txs might end up in different shard chains
223-
// tlb.BlockID is essentially a workchain+shard+seqno tuple. We can't use it as a block height. Thus let's use 0.
224-
// Note that for the sake of gas tracking, we use masterchain block height (not applicable here).
225-
const (
226-
outboundGasUsed = 0
227-
outboundGasPrice = 0
228-
outboundGasLimit = 0
229-
outboundBlockHeight = 0
230-
)
215+
// There's no sequential block height. Also, different txs might end up in different shards.
216+
// tlb.BlockID is essentially a workchain+shard+seqno tuple. We can't use it as a block height, thus zero.
217+
const tonBlockHeight = 0
231218

232219
var (
233220
chainID = ob.Chain().ChainId
221+
txHash = liteapi.TransactionToHashString(outboundRes.tx.Transaction)
234222
nonce = cctx.GetCurrentOutboundParam().TssNonce
235223
signerAddress = ob.ZetacoreClient().GetKeys().GetOperatorAddress()
236224
coinType = cctx.InboundParams.CoinType
237225
)
238226

239-
msg := cc.NewMsgVoteOutbound(
227+
gasPrice, ok := ob.getLatestGasPrice()
228+
229+
// should not happen
230+
if !ok {
231+
return errors.New("gas price is not set (call PostGasPrice first)")
232+
}
233+
234+
// #nosec G115 len always in range
235+
gasPriceInt := math.NewInt(int64(gasPrice))
236+
237+
msg := cctypes.NewMsgVoteOutbound(
240238
signerAddress.String(),
241239
cctx.Index,
242240
txHash,
243-
outboundBlockHeight,
244-
outboundGasUsed,
245-
math.NewInt(outboundGasPrice),
246-
outboundGasLimit,
241+
tonBlockHeight,
242+
outboundRes.tx.GasUsed().Uint64(),
243+
gasPriceInt,
244+
maxGasLimit,
247245
w.Amount,
248-
status,
246+
outboundRes.receiveStatus,
249247
chainID,
250248
nonce,
251249
coinType,
252-
cc.ConfirmationMode_SAFE,
250+
cctypes.ConfirmationMode_SAFE,
253251
)
254252

255-
const gasLimit = gasconst.PostVoteOutboundGasLimit
253+
const gasLimit = zetacore.PostVoteOutboundGasLimit
256254

257255
var retryGasLimit uint64
258256
if msg.Status == chains.ReceiveStatus_failed {
259-
retryGasLimit = gasconst.PostVoteOutboundRevertGasLimit
257+
retryGasLimit = zetacore.PostVoteOutboundRevertGasLimit
260258
}
261259

262260
log := ob.Logger().Outbound.With().
263-
Uint64("outbound.nonce", nonce).
264-
Str("outbound.outbound_tx_hash", txHash).
261+
Uint64(logs.FieldNonce, nonce).
262+
Str(logs.FieldTx, txHash).
265263
Logger()
266264

267265
zetaTxHash, ballot, err := ob.ZetacoreClient().PostVoteOutbound(ctx, gasLimit, retryGasLimit, msg)
268-
if err != nil {
269-
log.Error().Err(err).Msg("PostVoteOutbound: error posting vote")
270-
return err
271-
}
272266

273-
if zetaTxHash != "" {
267+
switch {
268+
case err != nil:
269+
log.Error().Err(err).Msg("PostVoteOutbound: failed to post vote")
270+
return err
271+
case zetaTxHash != "":
274272
log.Info().
275273
Str("outbound.vote_tx_hash", zetaTxHash).
276274
Str("outbound.ballot_id", ballot).

0 commit comments

Comments
 (0)