Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions devenv/offchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ func (m *CCIP16TON) ConfigureNodes(ctx context.Context, bc *blockchain.Input) (s
Enabled = true
NetworkName = 'ton-localnet'

[TON.TransactionManager]
CleanupInterval = '5m'

[[TON.Nodes]]
Name = '%s'
URL = '%s'`,
Expand All @@ -105,9 +108,11 @@ func (m *CCIP16TON) ConfigureNodes(ctx context.Context, bc *blockchain.Input) (s
), nil
}

const defaultNodeFundingTON = "500"

func (m *CCIP16TON) FundNodes(ctx context.Context, cls []*simple_node_set.Input, nodeKeyBundles map[string]clclient.NodeKeysBundle, bc *blockchain.Input, linkAmount, nativeAmount *big.Int) error {
l := zerolog.Ctx(ctx)
l.Info().Msg("Funding CL nodes with native and LINK")
l.Info().Str("amount", defaultNodeFundingTON).Msg("Funding CL nodes with native TON")
keys := make([]*address.Address, 0)
amounts := make([]tlb.Coins, 0)
for _, nk := range nodeKeyBundles {
Expand All @@ -116,7 +121,7 @@ func (m *CCIP16TON) FundNodes(ctx context.Context, cls []*simple_node_set.Input,
return err
}
keys = append(keys, address.MustParseAddr(addr))
amounts = append(amounts, tlb.MustFromTON(nativeAmount.String()))
amounts = append(amounts, tlb.MustFromTON(defaultNodeFundingTON))
}
client, err := testutils.CreateClient(ctx, bc.Out.Nodes[0].ExternalHTTPUrl)
if err != nil {
Expand Down
45 changes: 42 additions & 3 deletions pkg/relay/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sync"
"time"

"github.com/xssnick/tonutils-go/liteclient"
"github.com/xssnick/tonutils-go/ton"
"github.com/xssnick/tonutils-go/ton/wallet"
"github.com/xssnick/tonutils-go/tvm/cell"
Expand Down Expand Up @@ -85,6 +86,7 @@ type chain struct {

clientCache map[int]*cachedClient
cacheMu sync.RWMutex
pool *liteclient.ConnectionPool
}

func NewChain(cfg *config.TOMLConfig, opts ChainOpts) (Chain, error) {
Expand Down Expand Up @@ -208,7 +210,16 @@ func (c *chain) Start(ctx context.Context) error {
func (c *chain) Close() error {
return c.starter.StopOnce("Chain", func() error {
c.lggr.Debug("Stopping txm, log poller, and balance monitor")
return services.CloseAll(c.txm, c.lp, c.bm)
err := services.CloseAll(c.txm, c.lp, c.bm)

c.cacheMu.Lock()
if c.pool != nil {
c.pool.Stop()
c.pool = nil
}
c.cacheMu.Unlock()

return err
})
}

Expand Down Expand Up @@ -355,8 +366,7 @@ func (c *chain) GetClient(ctx context.Context) (ton.APIClientWrapped, error) {
}

// Build new client, expected URL format: liteserver://publickey@host:port
liteServerURL := node.URL.String()
connectionPool, cerr := tonchain.CreateLiteserverConnectionPool(ctx, liteServerURL)
connectionPool, cerr := c.getOrCreatePool(ctx, i)
if cerr != nil {
c.lggr.Warnw("failed to get connection pool", "name", node.Name, "ton-url", node.URL, "err", cerr)
continue
Expand Down Expand Up @@ -440,6 +450,35 @@ func (c *chain) GetSignerWallet(ctx context.Context, client ton.APIClientWrapped
return w, nil
}

// getOrCreatePool returns the long-lived ConnectionPool, creating it on first call.
// Caller must NOT hold cacheMu — this method locks it internally.
func (c *chain) getOrCreatePool(ctx context.Context, nodeIndex int) (*liteclient.ConnectionPool, error) {
c.cacheMu.RLock()
pool := c.pool
c.cacheMu.RUnlock()
if pool != nil {
return pool, nil
}

liteServerURL := c.cfg.Nodes[nodeIndex].URL.String()
pool, err := tonchain.CreateLiteserverConnectionPool(ctx, liteServerURL)
if err != nil {
return nil, err
}

c.cacheMu.Lock()
// Double-check: another goroutine may have created it
if c.pool != nil {
c.cacheMu.Unlock()
pool.Stop() // discard the one we just made
return c.pool, nil
}
c.pool = pool
c.cacheMu.Unlock()

return pool, nil
}

func (c *chain) evictClient(index int, name string, reason string) {
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
Expand Down
8 changes: 7 additions & 1 deletion pkg/ton/tracetracking/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,14 @@ func (m *ReceivedMessage) WaitForOutgoingMessagesToBeReceived(ctx context.Contex

receivedMessage, err := waitForMatchingMessage(subCtx, transactionsReceived, sentMessage)

// Cancel context as soon as we have the result to prevent leaks
// Cancel context and drain the channel so the SubscribeOnTransactions goroutine
// can unblock from its bare `channel <- tx` send, reach the `workerCtx.Done()`
// select, and exit. Without draining, the goroutine leaks forever.
cancel()
go func() {
for range transactionsReceived {
}
}()

if err != nil {
return err
Expand Down
7 changes: 4 additions & 3 deletions pkg/txm/txstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package txm

import (
"fmt"
"math/big"
"sort"
"sync"

Expand All @@ -20,7 +21,7 @@ type UnconfirmedTx struct {
}

type FinalizedTx struct {
ReceivedMessage tracetracking.ReceivedMessage
TotalActionFees *big.Int
ExitCode tvm.ExitCode
TraceSucceeded bool
}
Expand Down Expand Up @@ -78,7 +79,7 @@ func (s *TxStore) MarkFinalized(lt uint64, success bool, exitCode tvm.ExitCode)

// move transaction to finalized map
s.finalizedTxs[lt] = &FinalizedTx{
ReceivedMessage: unconfirmedTx.Tx.ReceivedMessage,
TotalActionFees: unconfirmedTx.Tx.ReceivedMessage.TotalActionFees,
ExitCode: exitCode,
TraceSucceeded: success,
}
Expand Down Expand Up @@ -125,7 +126,7 @@ func (s *TxStore) GetTxState(lt uint64) (tracetracking.MsgStatus, bool, tvm.Exit

if tx, exists := s.finalizedTxs[lt]; exists {
// Transaction is finalized (success or failure is indicated separately)
totalActionFees := tlb.MustFromNano(tx.ReceivedMessage.TotalActionFees, 9)
totalActionFees := tlb.MustFromNano(tx.TotalActionFees, 9)
return tracetracking.Finalized, tx.TraceSucceeded, tx.ExitCode, totalActionFees, true
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/.core_version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
306cebe992240ebd08cec58adef6a2c3308b91d1
b7531451e5f0569f5f617982a09a61454eddfe0c
5 changes: 3 additions & 2 deletions scripts/e2e/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ setup_contracts "$CHAINLINK_CORE_DIR"
# verifying gitRef match might be redundant for local workflow.
verify_plugin_config "$CHAINLINK_CORE_DIR"

build_ton_binary
# disable LOOP plugin — run TON relayer in-process for profiling
export CL_TON_CMD=""

# test database URL availability validation
if [ -z "${CL_DATABASE_URL:-}" ]; then
Expand All @@ -110,7 +111,7 @@ fi
log_info "=== CCIP Test Execution ==="
log_info "Using Chainlink Core: $CHAINLINK_CORE_DIR"
log_info "Using Database URL: $CL_DATABASE_URL"
log_info "Using TON Binary: $CL_TON_CMD"
log_info "CL_TON_CMD: '${CL_TON_CMD}' (empty = embedded/in-process)"
log_info "Test Command: $ARG_TEST_COMMAND"

log_info "Executing Test Command in $CHAINLINK_CORE_DIR: $ARG_TEST_COMMAND"
Expand Down
15 changes: 7 additions & 8 deletions scripts/e2e/setup-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ replace_ton_modules() {
go mod tidy
fi
done

# scan for go.mod files that use chainlink-ton
find "$CHAINLINK_CORE_DIR" -name "go.mod" -type f -print0 | while IFS= read -r -d '' gomod; do
dir=$(dirname "$gomod")

# check if any chainlink-ton modules are used
needs_update=false
for mod in "${!MODULES_TON[@]}"; do
Expand All @@ -125,10 +125,10 @@ replace_ton_modules() {
break
fi
done

if [ "$needs_update" = true ]; then
log_info " Updating ${dir#$CHAINLINK_CORE_DIR/}"

pushd "$dir" > /dev/null
for mod in "${!MODULES_TON[@]}"; do
if grep -q "$mod" go.mod; then
Expand All @@ -140,7 +140,7 @@ replace_ton_modules() {
popd > /dev/null
fi
done

go run github.com/jmank88/gomods@v0.1.6 tidy
log_info "Module replacements complete"
}
Expand Down Expand Up @@ -188,9 +188,8 @@ validate_core_version "$CHAINLINK_CORE_DIR"
# This allows testing with previous contract versions without rebuilding
setup_contracts "$CHAINLINK_CORE_DIR"

# TODO: Revisit to check if this is needed. we already have nix build for chainlink-ton.
# but the point is building the binary for every test run in local dev env
build_ton_binary
# disable LOOP plugin — run TON relayer in-process for profiling
export CL_TON_CMD=""

setup_postgres

Expand Down
Loading