@@ -2,38 +2,44 @@ package main
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
7+ "net/http"
68 "os"
79 "sort"
810 "sync"
911 "time"
1012
1113 sse "github.com/r3labs/sse/v2"
14+ "github.com/tonkeeper/tonapi-go"
1215 "github.com/tonkeeper/tongo/liteapi"
1316 "github.com/tonkeeper/tongo/tlb"
1417 "github.com/tonkeeper/tongo/ton"
1518 "github.com/tonkeeper/tongo/wallet"
1619)
1720
1821const (
19- numRuns = 20
22+ numRuns = 10
2023)
2124
2225type RunResult struct {
23- SSELatency time.Duration
24- LiteLatency time.Duration
25- SSESuccess bool
26- LiteSuccess bool
26+ SSELatency time.Duration
27+ LiteLatency time.Duration
28+ TonapiLatency time.Duration
29+ ToncenterLatency time.Duration
30+ SSESuccess bool
31+ LiteSuccess bool
32+ TonapiSuccess bool
33+ ToncenterSuccess bool
2734}
2835
2936func main () {
3037 seed := ""
31- destinationStr := ""
3238 apiKey := ""
39+ toncenterApiKey := ""
40+ version := wallet .V4R2
3341 amount := uint64 (10_000_000 ) // 0.01 TON
3442
35- destination := ton .MustParseAccountID (destinationStr )
36-
3743 cli , err := liteapi .NewClient (liteapi .Testnet ())
3844 if err != nil {
3945 fmt .Printf ("failed to create liteapi client: %v\n " , err )
@@ -46,18 +52,19 @@ func main() {
4652 os .Exit (1 )
4753 }
4854
49- w , err := wallet .New (privateKey , wallet . V3R2 , cli )
55+ w , err := wallet .New (privateKey , version , cli )
5056 if err != nil {
5157 fmt .Printf ("failed to create wallet: %v\n " , err )
5258 os .Exit (1 )
5359 }
5460
5561 walletAddress := w .GetAddress ()
62+ destination := walletAddress
5663 fmt .Printf ("Wallet address: %v\n " , walletAddress .ToHuman (true , false ))
5764 fmt .Printf ("Running %d tests...\n \n " , numRuns )
5865
5966 var results []RunResult
60- var sseLatencies , liteLatencies []time.Duration
67+ var sseLatencies , liteLatencies , tonapiLatencies , toncenterLatencies []time.Duration
6168
6269 for i := 1 ; i <= numRuns ; i ++ {
6370 fmt .Printf ("=== RUN %d/%d ===\n " , i , numRuns )
@@ -68,7 +75,7 @@ func main() {
6875 continue
6976 }
7077
71- result := runTest (cli , w , walletAddress , destination , amount , apiKey )
78+ result := runTest (cli , w , walletAddress , destination , amount , apiKey , toncenterApiKey )
7279 results = append (results , result )
7380
7481 if result .SSESuccess {
@@ -85,6 +92,15 @@ func main() {
8592 fmt .Printf (" Liteserver: ERROR\n " )
8693 }
8794
95+ if result .TonapiSuccess {
96+ tonapiLatencies = append (tonapiLatencies , result .TonapiLatency )
97+ fmt .Printf (" Tonapi: %v\n " , result .TonapiLatency )
98+ }
99+ if result .ToncenterSuccess {
100+ toncenterLatencies = append (toncenterLatencies , result .ToncenterLatency )
101+ fmt .Printf (" Toncenter: %v\n " , result .ToncenterLatency )
102+ }
103+
88104 fmt .Println ()
89105
90106 if i < numRuns {
@@ -117,9 +133,111 @@ func main() {
117133 } else {
118134 fmt .Printf ("Liteserver: No successful runs\n " )
119135 }
136+
137+ fmt .Println ()
138+
139+ if len (tonapiLatencies ) > 0 {
140+ fmt .Printf ("Tonapi Statistics (%d successful runs):\n " , len (tonapiLatencies ))
141+ fmt .Printf (" Average: %v\n " , average (tonapiLatencies ))
142+ fmt .Printf (" Min: %v\n " , min (tonapiLatencies ))
143+ fmt .Printf (" Max: %v\n " , max (tonapiLatencies ))
144+ fmt .Printf (" Median: %v\n " , median (tonapiLatencies ))
145+ } else {
146+ fmt .Printf ("Tonapi: No successful runs\n " )
147+ }
148+
149+ fmt .Println ()
150+
151+ if len (toncenterLatencies ) > 0 {
152+ fmt .Printf ("Toncenter Statistics (%d successful runs):\n " , len (toncenterLatencies ))
153+ fmt .Printf (" Average: %v\n " , average (toncenterLatencies ))
154+ fmt .Printf (" Min: %v\n " , min (toncenterLatencies ))
155+ fmt .Printf (" Max: %v\n " , max (toncenterLatencies ))
156+ fmt .Printf (" Median: %v\n " , median (toncenterLatencies ))
157+ } else {
158+ fmt .Printf ("Toncenter: No successful runs\n " )
159+ }
160+
120161}
121162
122- func runTest (cli * liteapi.Client , w wallet.Wallet , walletAddress ton.AccountID , destination ton.AccountID , amount uint64 , apiKey string ) RunResult {
163+ func pollTonapi (ctx context.Context , account ton.AccountID , token string , initialLT uint64 , foundCh chan <- time.Time ) {
164+ ticker := time .NewTicker (50 * time .Millisecond )
165+ defer ticker .Stop ()
166+ api , _ := tonapi .NewClient ("https://testnet.tonapi.io" , tonapi .WithToken (token ))
167+ for {
168+ select {
169+ case <- ctx .Done ():
170+ return
171+ case <- ticker .C :
172+ txs , err := api .GetBlockchainAccountTransactions (ctx , tonapi.GetBlockchainAccountTransactionsParams {
173+ AccountID : account .String (),
174+ Limit : tonapi .NewOptInt32 (3 ),
175+ })
176+ if err != nil {
177+ if ctx .Err () != nil {
178+ return
179+ }
180+ continue
181+ }
182+
183+ currentLT := uint64 (txs .Transactions [0 ].Lt )
184+ if currentLT > initialLT {
185+ select {
186+ case foundCh <- time .Now ():
187+ default :
188+ }
189+ return
190+ }
191+ }
192+ }
193+ }
194+
195+ func pollToncenter (ctx context.Context , account ton.AccountID , token string , initialLT uint64 , foundCh chan <- time.Time ) {
196+ ticker := time .NewTicker (50 * time .Millisecond )
197+ defer ticker .Stop ()
198+ req , _ := http .NewRequest ("GET" , fmt .Sprintf ("https://testnet.toncenter.com/api/v3/transactions?account=%s&limit=3&offset=0&sort=desc" , account .String ()), nil )
199+ req .Header .Add ("X-Api-Key" , token )
200+ for {
201+ select {
202+ case <- ctx .Done ():
203+ return
204+ case <- ticker .C :
205+ resp , err := http .DefaultClient .Do (req )
206+ if err != nil {
207+ fmt .Println (err )
208+ return
209+ }
210+ if resp .StatusCode != http .StatusOK {
211+ fmt .Printf ("unexpected status code: %d\n " , resp .StatusCode )
212+ return
213+ }
214+ var body struct {
215+ Transactions []struct {
216+ Lt uint64 `json:"lt,string"`
217+ } `json:"transactions"`
218+ }
219+ err = json .NewDecoder (resp .Body ).Decode (& body )
220+ if err != nil {
221+ if ctx .Err () != nil {
222+ fmt .Println (err )
223+ return
224+ }
225+ continue
226+ }
227+
228+ currentLT := uint64 (body .Transactions [0 ].Lt )
229+ if currentLT > initialLT {
230+ select {
231+ case foundCh <- time .Now ():
232+ default :
233+ }
234+ return
235+ }
236+ }
237+ }
238+ }
239+
240+ func runTest (cli * liteapi.Client , w wallet.Wallet , walletAddress ton.AccountID , destination ton.AccountID , amount uint64 , apiKey , toncenterApikey string ) RunResult {
123241 result := RunResult {}
124242
125243 initialState , err := cli .GetAccountState (context .Background (), walletAddress )
@@ -131,6 +249,8 @@ func runTest(cli *liteapi.Client, w wallet.Wallet, walletAddress ton.AccountID,
131249
132250 sseFoundCh := make (chan time.Time , 1 )
133251 liteFoundCh := make (chan time.Time , 1 )
252+ tonapiFoundCh := make (chan time.Time , 1 )
253+ toncenterFoundCh := make (chan time.Time , 1 )
134254 ctx , cancel := context .WithCancel (context .Background ())
135255 defer cancel ()
136256
@@ -141,6 +261,16 @@ func runTest(cli *liteapi.Client, w wallet.Wallet, walletAddress ton.AccountID,
141261 defer wg .Done ()
142262 listenSSE (ctx , walletAddress .ToRaw (), apiKey , sseFoundCh )
143263 }()
264+ wg .Add (1 )
265+ go func () {
266+ defer wg .Done ()
267+ pollTonapi (ctx , walletAddress , apiKey , initialLT , tonapiFoundCh )
268+ }()
269+ wg .Add (1 )
270+ go func () {
271+ defer wg .Done ()
272+ pollToncenter (ctx , walletAddress , toncenterApikey , initialLT , toncenterFoundCh )
273+ }()
144274
145275 time .Sleep (500 * time .Millisecond )
146276
@@ -170,7 +300,7 @@ func runTest(cli *liteapi.Client, w wallet.Wallet, walletAddress ton.AccountID,
170300
171301 timeout := time .After (60 * time .Second )
172302
173- for ! result .SSESuccess || ! result .LiteSuccess {
303+ for ! result .SSESuccess || ! result .LiteSuccess || ! result . TonapiSuccess || ! result . ToncenterSuccess {
174304 select {
175305 case t := <- sseFoundCh :
176306 if ! result .SSESuccess {
@@ -182,6 +312,16 @@ func runTest(cli *liteapi.Client, w wallet.Wallet, walletAddress ton.AccountID,
182312 result .LiteLatency = t .Sub (sendTime )
183313 result .LiteSuccess = true
184314 }
315+ case t := <- tonapiFoundCh :
316+ if ! result .TonapiSuccess {
317+ result .TonapiLatency = t .Sub (sendTime )
318+ result .TonapiSuccess = true
319+ }
320+ case t := <- toncenterFoundCh :
321+ if ! result .ToncenterSuccess {
322+ result .ToncenterLatency = t .Sub (sendTime )
323+ result .ToncenterSuccess = true
324+ }
185325 case <- timeout :
186326 cancel ()
187327 return result
0 commit comments