diff --git a/README.md b/README.md
index 5b8eb43..401fa97 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,7 @@ For more information on Jettons compatibility, see [Jettons compatibility](/jett
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `LITESERVER` | IP and port of lite server, example: `185.86.76.183:5815` |
| `LITESERVER_KEY` | public key of lite server `5v2dHtSclsGsZVbNVwTj4hQDso5xvQjzL/yPEHJevHk=`.
Be careful with base64 encoding and ENV var. Use '' |
+| `LITESERVER_RATE_LIMIT` | If you have a rented node with an RPS limit, set the RPS value here equal to (or preferably slightly less than) the limit. Default: 100. |
| `SEED` | seed phrase for main hot wallet. 24 words compatible with standard TON wallets |
| `DB_URI` | URI for DB connection, example:
`postgresql://db_user:db_password@localhost:5432/payment_processor` |
| `POSTGRES_DB` | name of database for storing payments data |
diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go
index 6824334..e9066c2 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -53,7 +53,7 @@ type contract struct {
}
// NewConnection creates new Blockchain connection
-func NewConnection(addr, key string) (*Connection, error) {
+func NewConnection(addr, key string, rateLimit int) (*Connection, error) {
client := liteclient.NewConnectionPool()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*120)
@@ -64,6 +64,8 @@ func NewConnection(addr, key string) (*Connection, error) {
return nil, fmt.Errorf("connection err: %v", err.Error())
}
+ limitedClient := newLimitedClient(client, rateLimit)
+
var wrappedClient ton.APIClientWrapped
if config.Config.ProofCheckEnabled {
@@ -77,7 +79,7 @@ func NewConnection(addr, key string) (*Connection, error) {
return nil, fmt.Errorf("get network config from url err: %s", err.Error())
}
- wrappedClient = ton.NewAPIClient(client, ton.ProofCheckPolicySecure).WithRetry()
+ wrappedClient = ton.NewAPIClient(limitedClient, ton.ProofCheckPolicySecure).WithRetry()
wrappedClient.SetTrustedBlockFromConfig(cfg)
log.Infof("Fetching and checking proofs since config init block ...")
@@ -88,7 +90,7 @@ func NewConnection(addr, key string) (*Connection, error) {
log.Infof("Proof checks are completed")
} else {
- wrappedClient = ton.NewAPIClient(client, ton.ProofCheckPolicyUnsafe).WithRetry()
+ wrappedClient = ton.NewAPIClient(limitedClient, ton.ProofCheckPolicyUnsafe).WithRetry()
}
// TODO: replace after tonutils fix
diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go
index 0582a33..f68c2cc 100644
--- a/blockchain/blockchain_test.go
+++ b/blockchain/blockchain_test.go
@@ -30,7 +30,7 @@ func connect(t *testing.T) *Connection {
if key == "" {
t.Fatal("empty key var")
}
- c, err := NewConnection(server, key)
+ c, err := NewConnection(server, key, 100)
if err != nil {
t.Fatal("connections err: ", err)
}
diff --git a/blockchain/limited_client.go b/blockchain/limited_client.go
new file mode 100644
index 0000000..fb1d5da
--- /dev/null
+++ b/blockchain/limited_client.go
@@ -0,0 +1,46 @@
+package blockchain
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/xssnick/tonutils-go/tl"
+ "github.com/xssnick/tonutils-go/ton"
+ "golang.org/x/time/rate"
+)
+
+type limitedLiteClient struct {
+ limiter *rate.Limiter
+ original ton.LiteClient
+}
+
+func newLimitedClient(lc ton.LiteClient, rateLimit int) *limitedLiteClient {
+ return &limitedLiteClient{
+ original: lc,
+ limiter: rate.NewLimiter(rate.Limit(rateLimit), 1),
+ }
+}
+
+func (w *limitedLiteClient) QueryLiteserver(ctx context.Context, payload tl.Serializable, result tl.Serializable) error {
+ err := w.limiter.Wait(ctx)
+ if err != nil {
+ return fmt.Errorf("limiter err: %w", err)
+ }
+ return w.original.QueryLiteserver(ctx, payload, result)
+}
+
+func (w *limitedLiteClient) StickyContext(ctx context.Context) context.Context {
+ return w.original.StickyContext(ctx)
+}
+
+func (w *limitedLiteClient) StickyNodeID(ctx context.Context) uint32 {
+ return w.original.StickyNodeID(ctx)
+}
+
+func (w *limitedLiteClient) StickyContextNextNode(ctx context.Context) (context.Context, error) {
+ return w.original.StickyContextNextNode(ctx)
+}
+
+func (w *limitedLiteClient) StickyContextNextNodeBalanced(ctx context.Context) (context.Context, error) {
+ return w.original.StickyContextNextNodeBalanced(ctx)
+}
diff --git a/cmd/processor/main.go b/cmd/processor/main.go
index 5fdca78..a185e06 100644
--- a/cmd/processor/main.go
+++ b/cmd/processor/main.go
@@ -32,7 +32,7 @@ func main() {
signal.Notify(sigChannel, os.Interrupt, syscall.SIGTERM)
wg := new(sync.WaitGroup)
- bcClient, err := blockchain.NewConnection(config.Config.LiteServer, config.Config.LiteServerKey)
+ bcClient, err := blockchain.NewConnection(config.Config.LiteServer, config.Config.LiteServerKey, config.Config.LiteServerRateLimit)
if err != nil {
log.Fatalf("blockchain connection error: %v", err)
}
diff --git a/cmd/testutil/main.go b/cmd/testutil/main.go
index 2083e62..7863e0d 100644
--- a/cmd/testutil/main.go
+++ b/cmd/testutil/main.go
@@ -51,7 +51,7 @@ func main() {
log.Fatalf("invalid HOT_WALLET_B env var")
}
- bcClient, err := blockchain.NewConnection(config.Config.LiteServer, config.Config.LiteServerKey)
+ bcClient, err := blockchain.NewConnection(config.Config.LiteServer, config.Config.LiteServerKey, config.Config.LiteServerRateLimit)
if err != nil {
log.Fatalf("blockchain connection error: %v", err)
}
diff --git a/config/config.go b/config/config.go
index dda3955..7a1ff5d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -1,15 +1,16 @@
package config
import (
+ "log"
+ "math/big"
+ "strings"
+ "time"
+
"github.com/caarlos0/env/v6"
"github.com/shopspring/decimal"
"github.com/tonkeeper/tongo/boc"
"github.com/xssnick/tonutils-go/address"
"github.com/xssnick/tonutils-go/tlb"
- "log"
- "math/big"
- "strings"
- "time"
)
const MaxJettonForwardTonAmount = 20_000_000
@@ -39,6 +40,7 @@ const MaxCommentLength = 1000 // qty in chars
var Config = struct {
LiteServer string `env:"LITESERVER,required"`
LiteServerKey string `env:"LITESERVER_KEY,required"`
+ LiteServerRateLimit int `env:"LITESERVER_RATE_LIMIT" envDefault:"100"`
Seed string `env:"SEED,required"`
DatabaseURI string `env:"DB_URI,required"`
APIPort int `env:"API_PORT,required"`
diff --git a/go.mod b/go.mod
index 28bb0e1..95e4e8c 100644
--- a/go.mod
+++ b/go.mod
@@ -12,6 +12,7 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/tonkeeper/tongo v1.9.9
github.com/xssnick/tonutils-go v1.10.2
+ golang.org/x/time v0.10.0
)
require (
diff --git a/go.sum b/go.sum
index 8081be6..4db737c 100644
--- a/go.sum
+++ b/go.sum
@@ -196,6 +196,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
+golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=