Skip to content

Commit 619c2aa

Browse files
authored
Merge pull request #299 from xssnick/dev-v1-11
Dict String() & LoadAll from proof, RLDP Unexpected transfers limits,…
2 parents 5abade9 + 5a472e8 commit 619c2aa

File tree

10 files changed

+205
-48
lines changed

10 files changed

+205
-48
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[![Based on TON][ton-svg]][ton]
66
[![Telegram Channel][tgc-svg]][tg-channel]
7-
![Coverage](https://img.shields.io/badge/Coverage-72.6%25-brightgreen)
7+
![Coverage](https://img.shields.io/badge/Coverage-72.8%25-brightgreen)
88

99
Golang library for interacting with TON blockchain.
1010

adnl/adnl.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"encoding/hex"
1010
"errors"
1111
"fmt"
12-
"log"
1312
"reflect"
1413
"strings"
1514
"sync"
@@ -85,7 +84,7 @@ type ADNL struct {
8584
mx sync.RWMutex
8685
}
8786

88-
var Logger = log.Println
87+
var Logger = func(v ...any) {}
8988

9089
func (g *Gateway) initADNL() *ADNL {
9190
tm := int32(time.Now().Unix())

adnl/gateway.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ type udpPacket struct {
6868
type Gateway struct {
6969
conn net.PacketConn
7070

71-
dhtIP net.IP
71+
dhtIP net.IP
72+
dhtPort uint16
73+
7274
addrList address.List
7375
key ed25519.PrivateKey
7476
processors map[string]*srvProcessor
@@ -169,6 +171,10 @@ func (g *Gateway) SetExternalIP(ip net.IP) {
169171
g.dhtIP = ip
170172
}
171173

174+
func (g *Gateway) SetExternalPort(port uint16) {
175+
g.dhtPort = port
176+
}
177+
172178
func (g *Gateway) StartServer(listenAddr string, listenThreads ...int) (err error) {
173179
threads := 1
174180
if len(listenThreads) > 0 && listenThreads[0] > 0 {
@@ -186,9 +192,12 @@ func (g *Gateway) StartServer(listenAddr string, listenThreads ...int) (err erro
186192
}
187193

188194
if ip = ip.To4(); !ip.Equal(net.IPv4zero) {
189-
port, err := strconv.ParseUint(adr[1], 10, 16)
190-
if err != nil {
191-
return fmt.Errorf("invalid listen port")
195+
port := uint64(g.dhtPort)
196+
if port == 0 {
197+
port, err = strconv.ParseUint(adr[1], 10, 16)
198+
if err != nil {
199+
return fmt.Errorf("invalid listen port")
200+
}
192201
}
193202

194203
tm := int32(time.Now().Unix())

adnl/rldp/client.go

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,23 @@ type activeTransfer struct {
4747
}
4848

4949
type activeRequest struct {
50-
id string
5150
deadline int64
5251
result chan<- AsyncQueryResult
5352
}
5453

54+
type expectedTransfer struct {
55+
deadline int64
56+
maxSize int64
57+
}
58+
5559
type RLDP struct {
5660
adnl ADNL
5761
useV2 bool
5862

5963
activateRecoverySender chan bool
6064
activeRequests map[string]*activeRequest
6165
activeTransfers map[string]*activeTransfer
66+
expectedTransfers map[string]*expectedTransfer
6267

6368
recvStreams map[string]*decoderStream
6469

@@ -94,6 +99,7 @@ type decoderStream struct {
9499
}
95100

96101
var DefaultSymbolSize uint32 = 768
102+
var MaxUnexpectedTransferSize int64 = 1 << 16 // 64 KB
97103

98104
const _MTU = 1 << 37
99105

@@ -103,6 +109,7 @@ func NewClient(a ADNL) *RLDP {
103109
activeRequests: map[string]*activeRequest{},
104110
activeTransfers: map[string]*activeTransfer{},
105111
recvStreams: map[string]*decoderStream{},
112+
expectedTransfers: map[string]*expectedTransfer{},
106113
activateRecoverySender: make(chan bool, 1),
107114
}
108115

@@ -168,12 +175,22 @@ func (r *RLDP) handleMessage(msg *adnl.MessageCustom) error {
168175
id := string(m.TransferID)
169176
r.mx.RLock()
170177
stream := r.recvStreams[id]
178+
expected := r.expectedTransfers[id]
171179
r.mx.RUnlock()
172180

173181
if stream == nil {
174-
// TODO: limit unexpected transfer size to 1024 bytes
175182
if m.TotalSize > _MTU || m.TotalSize <= 0 {
176-
return fmt.Errorf("bad rldp packet total size")
183+
return fmt.Errorf("bad rldp packet total size %d", m.TotalSize)
184+
}
185+
186+
// unexpected transfers limited to this size, for protection
187+
var maxTransferSize = MaxUnexpectedTransferSize
188+
if expected != nil {
189+
maxTransferSize = expected.maxSize
190+
}
191+
192+
if m.TotalSize > maxTransferSize {
193+
return fmt.Errorf("too big transfer size %d, max allowed %d", m.TotalSize, maxTransferSize)
177194
}
178195

179196
stream = &decoderStream{
@@ -189,6 +206,7 @@ func (r *RLDP) handleMessage(msg *adnl.MessageCustom) error {
189206
} else {
190207
r.recvStreams[id] = stream
191208
}
209+
delete(r.expectedTransfers, id)
192210
r.mx.Unlock()
193211
}
194212

@@ -405,7 +423,8 @@ func (r *RLDP) recoverySender() {
405423
packets := make([]tl.Serializable, 0, 1024)
406424
transfersToProcess := make([]*activeTransfer, 0, 128)
407425
timedOut := make([]*activeTransfer, 0, 32)
408-
timedOutReq := make([]*activeRequest, 0, 32)
426+
timedOutReq := make([]string, 0, 32)
427+
timedOutExp := make([]string, 0, 32)
409428
closerCtx := r.adnl.GetCloserCtx()
410429
ticker := time.NewTicker(1 * time.Millisecond)
411430
defer ticker.Stop()
@@ -419,6 +438,7 @@ func (r *RLDP) recoverySender() {
419438
transfersToProcess = transfersToProcess[:0]
420439
timedOut = timedOut[:0]
421440
timedOutReq = timedOutReq[:0]
441+
timedOutExp = timedOutExp[:0]
422442

423443
ms := time.Now().UnixNano() / int64(time.Millisecond)
424444

@@ -436,13 +456,19 @@ func (r *RLDP) recoverySender() {
436456
}
437457
}
438458

439-
for _, req := range r.activeRequests {
459+
for id, req := range r.activeRequests {
440460
if req.deadline < ms {
441-
timedOutReq = append(timedOutReq, req)
461+
timedOutReq = append(timedOutReq, id)
442462
}
443463
}
444464

445-
if len(r.activeRequests)+len(r.activeTransfers) == 0 {
465+
for id, req := range r.expectedTransfers {
466+
if req.deadline < ms {
467+
timedOutExp = append(timedOutExp, id)
468+
}
469+
}
470+
471+
if len(r.activeRequests)+len(r.activeTransfers)+len(r.expectedTransfers) == 0 {
446472
// stop ticks to not consume resources
447473
ticker.Stop()
448474
}
@@ -481,13 +507,16 @@ func (r *RLDP) recoverySender() {
481507
}
482508
}
483509

484-
if len(timedOut) > 0 || len(timedOutReq) > 0 {
510+
if len(timedOut) > 0 || len(timedOutReq) > 0 || len(timedOutExp) > 0 {
485511
r.mx.Lock()
486512
for _, transfer := range timedOut {
487513
delete(r.activeTransfers, string(transfer.id))
488514
}
489515
for _, req := range timedOutReq {
490-
delete(r.activeRequests, req.id)
516+
delete(r.activeRequests, req)
517+
}
518+
for _, req := range timedOutExp {
519+
delete(r.expectedTransfers, req)
491520
}
492521
r.mx.Unlock()
493522
}
@@ -580,17 +609,9 @@ func (r *RLDP) DoQuery(ctx context.Context, maxAnswerSize int64, query, result t
580609

581610
select {
582611
case resp := <-res:
583-
r.mx.Lock()
584-
delete(r.activeRequests, string(qid))
585-
r.mx.Unlock()
586-
587612
reflect.ValueOf(result).Elem().Set(reflect.ValueOf(resp.Result))
588613
return nil
589614
case <-ctx.Done():
590-
r.mx.Lock()
591-
delete(r.activeRequests, string(qid))
592-
r.mx.Unlock()
593-
594615
return fmt.Errorf("response deadline exceeded, err: %w", ctx.Err())
595616
}
596617
}
@@ -627,6 +648,7 @@ func (r *RLDP) DoQueryAsync(ctx context.Context, maxAnswerSize int64, id []byte,
627648
if err != nil {
628649
return err
629650
}
651+
reverseId := reverseTransferId(transferId)
630652

631653
out := timeout.UnixNano() / int64(time.Millisecond)
632654

@@ -635,6 +657,10 @@ func (r *RLDP) DoQueryAsync(ctx context.Context, maxAnswerSize int64, id []byte,
635657
deadline: out,
636658
result: result,
637659
}
660+
r.expectedTransfers[string(reverseId)] = &expectedTransfer{
661+
deadline: out,
662+
maxSize: maxAnswerSize,
663+
}
638664
r.mx.Unlock()
639665

640666
if err = r.sendMessageParts(ctx, transferId, data, (time.Duration(q.Timeout)-time.Duration(time.Now().Unix()))*time.Second); err != nil {
@@ -659,17 +685,14 @@ func (r *RLDP) SendAnswer(ctx context.Context, maxAnswerSize int64, queryId, toT
659685
return fmt.Errorf("too big answer for that client, client wants no more than %d bytes", maxAnswerSize)
660686
}
661687

662-
transferId := make([]byte, 32)
688+
var transferId []byte
663689

664690
if toTransferId != nil {
665691
// if we have transfer to respond, invert it and use id
666-
copy(transferId, toTransferId)
667-
for i := range transferId {
668-
transferId[i] ^= 0xFF
669-
}
692+
transferId = reverseTransferId(toTransferId)
670693
} else {
671-
_, err = rand.Read(transferId)
672-
if err != nil {
694+
transferId = make([]byte, 32)
695+
if _, err = rand.Read(transferId); err != nil {
673696
return err
674697
}
675698
}
@@ -680,3 +703,12 @@ func (r *RLDP) SendAnswer(ctx context.Context, maxAnswerSize int64, queryId, toT
680703

681704
return nil
682705
}
706+
707+
func reverseTransferId(id []byte) []byte {
708+
rev := make([]byte, 32)
709+
copy(rev, id)
710+
for i := range rev {
711+
rev[i] ^= 0xFF
712+
}
713+
return rev
714+
}

adnl/rldp/client_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ func TestRLDP_handleMessage(t *testing.T) {
233233
queryId := string(tQuery.ID)
234234
tChan := make(chan AsyncQueryResult, 2)
235235
cli.activeRequests[queryId] = &activeRequest{
236-
id: queryId,
237236
deadline: time.Now().Add(time.Second * 10).Unix(),
238237
result: tChan,
239238
}
@@ -540,11 +539,6 @@ func TestRLDP_DoQuery(t *testing.T) {
540539
if !reflect.DeepEqual(res, answer.Data) {
541540
t.Error("got bad response")
542541
}
543-
time.Sleep(1 * time.Second)
544-
if len(cli.activeRequests) != 0 {
545-
t.Error("invalid activeRequests and activeTransfers after response", len(cli.activeRequests))
546-
}
547-
548542
})
549543

550544
t.Run("negative case (deadline exceeded)", func(t *testing.T) {

example/accept-payments/main.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,11 @@ func main() {
7474
src := ti.SrcAddr
7575

7676
if dsc, ok := tx.Description.(tlb.TransactionDescriptionOrdinary); ok && dsc.BouncePhase != nil {
77-
// transaction was bounced, and coins was returned to sender
78-
// this can happen mostly on custom contracts
79-
continue
77+
if _, ok = dsc.BouncePhase.Phase.(tlb.BouncePhaseOk); ok {
78+
// transaction was bounced, and coins were returned to sender
79+
// this can happen mostly on custom contracts
80+
continue
81+
}
8082
}
8183

8284
if !ti.ExtraCurrencies.IsEmpty() {

example/proof-cell/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,34 @@ func main() {
132132

133133
println("\n\nProof of 2 keys in 2 dictionaries on diff depth:")
134134
println(proof.Dump())
135+
136+
////////////////////////////////////////////////////
137+
///// VERIFY PROOF
138+
////////////////////////////////////////////////////
139+
140+
println("Checking and parsing proof:")
141+
expectedHash := exampleCell.Hash()
142+
143+
proofBody, err := cell.UnwrapProof(proof, expectedHash)
144+
if err != nil {
145+
panic(err)
146+
}
147+
148+
println("proof verified, now we can trust its body and parse it")
149+
150+
var dataProof ExampleStruct
151+
// LoadFromCellAsProof loads only not pruned branches and maps them to struct field, pruned fields stays empty
152+
if err = tlb.LoadFromCellAsProof(&dataProof, proofBody.BeginParse()); err != nil {
153+
panic(err)
154+
}
155+
156+
val, err := dataProof.DictA.LoadValueByIntKey(big.NewInt(778))
157+
if err != nil {
158+
panic(err)
159+
}
160+
161+
println("Trusted data inside proof mapped to struct:")
162+
println("Some struct fields:", dataProof.A, val.String())
163+
164+
println("Not pruned dict keys:\n", dataProof.DictA.String())
135165
}

tlb/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ func loadFromCell(v any, slice *cell.Slice, skipProofBranches, skipMagic bool) e
364364
Tag: reflect.StructTag(fmt.Sprintf("tlb:%q", strings.Join(settings[3:], " "))),
365365
}})
366366

367-
values, err := dict.LoadAll()
367+
values, err := dict.LoadAll(skipProofBranches)
368368
if err != nil {
369369
return fmt.Errorf("failed to load dict values for %v: %w", structField.Name, err)
370370
}

0 commit comments

Comments
 (0)