Skip to content

Commit

Permalink
TRON network support (#1568)
Browse files Browse the repository at this point in the history
TRON network support
  • Loading branch information
skudasov authored Jan 17, 2025
1 parent 661546a commit ddb6854
Show file tree
Hide file tree
Showing 12 changed files with 245 additions and 5 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/framework-golden-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ jobs:
config: smoke_aptos.toml
count: 1
timeout: 10m
- name: TestTRONSmoke
config: smoke_tron.toml
count: 1
timeout: 10m
- name: TestSolanaSmoke
config: smoke_solana.toml
count: 1
Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- [Solana](framework/components/blockchains/solana.md)
- [Aptos](framework/components/blockchains/aptos.md)
- [Sui](framework/components/blockchains/sui.md)
- [TRON](framework/components/blockchains/tron.md)
- [Optimism Stack]()
- [Arbitrum Stack]()
- [Chainlink](framework/components/chainlink.md)
Expand Down
71 changes: 71 additions & 0 deletions book/src/framework/components/blockchains/tron.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# TRON Blockchain Client

## Configuration
```toml
[blockchain_a]
type = "tron"
# image = "tronbox/tre" is default image
```
Default port is `9090`

## Usage
```golang
package examples

import (
"github.com/smartcontractkit/chainlink-testing-framework/framework"
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
"github.com/stretchr/testify/require"
"testing"
)

type CfgTron struct {
BlockchainA *blockchain.Input `toml:"blockchain_a" validate:"required"`
}

func TestTRONSmoke(t *testing.T) {
in, err := framework.Load[CfgTron](t)
require.NoError(t, err)

bc, err := blockchain.NewBlockchainNetwork(in.BlockchainA)
require.NoError(t, err)

// all private keys are funded
_ = blockchain.TRONAccounts.PrivateKeys[0]

t.Run("test something", func(t *testing.T) {
// use internal URL to connect Chainlink nodes
_ = bc.Nodes[0].DockerInternalHTTPUrl
// use host URL to interact
_ = bc.Nodes[0].HostHTTPUrl

// use bc.Nodes[0].HostHTTPUrl + "/wallet" to access full node
// use bc.Nodes[0].HostHTTPUrl + "/walletsolidity" to access Solidity node
})
}
```

## More info

Follow the [guide](https://developers.tron.network/reference/tronbox-quickstart) if you want to work with `TRONBox` environment via JS

## Golang HTTP Client

TRON doesn't have any library to interact with it in `Golang` but we maintain our internal fork [here](https://github.com/smartcontractkit/chainlink-internal-integrations/tree/69e35041cdea0bc38ddf642aa93fd3cc3fb5d0d9/tron/relayer/gotron-sdk)

Check TRON [HTTP API](https://tronprotocol.github.io/documentation-en/api/http/)

Full node is on `:9090/wallet`
```
curl -X POST http://127.0.0.1:9090/wallet/createtransaction -d '{
"owner_address": "TRGhNNfnmgLegT4zHNjEqDSADjgmnHvubJ",
"to_address": "TJCnKsPa7y5okkXvQAidZBzqx3QyQ6sxMW",
"amount": 1000000,
"visible": true
}'
```

Solidity node is on `:9090/walletsolidity`
```
curl -X POST http://127.0.0.1:9090/walletsolidity/getaccount -d '{"address": "41E552F6487585C2B58BC2C9BB4492BC1F17132CD0"}'
```
1 change: 1 addition & 0 deletions framework/.changeset/v0.4.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add TRON network support
2 changes: 1 addition & 1 deletion framework/cmd/observability/compose/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
- ./conf/prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
- "9999:9090"
loki:
image: grafana/loki:2.5.0
volumes:
Expand Down
4 changes: 3 additions & 1 deletion framework/components/blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
// Input is a blockchain network configuration params
type Input struct {
// Common EVM fields
Type string `toml:"type" validate:"required,oneof=anvil geth besu solana aptos sui" envconfig:"net_type"`
Type string `toml:"type" validate:"required,oneof=anvil geth besu solana aptos tron sui" envconfig:"net_type"`
Image string `toml:"image"`
PullImage bool `toml:"pull_image"`
Port string `toml:"port"`
Expand Down Expand Up @@ -71,6 +71,8 @@ func NewBlockchainNetwork(in *Input) (*Output, error) {
out, err = newAptos(in)
case "sui":
out, err = newSui(in)
case "tron":
out, err = newTron(in)
default:
return nil, fmt.Errorf("blockchain type is not supported or empty, must be 'anvil' or 'geth'")
}
Expand Down
124 changes: 124 additions & 0 deletions framework/components/blockchain/tron.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package blockchain

import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/smartcontractkit/chainlink-testing-framework/framework"
"os"
"time"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

type Accounts struct {
HDPath string `json:"hdPath"`
Mnemonic string `json:"mnemonic"`
PrivateKeys []string `json:"privateKeys"`
More []string `json:"more"`
}

var TRONAccounts = Accounts{
HDPath: "m/44'/195'/0'/0/",
Mnemonic: "resemble birth wool happy sun burger fatal trumpet globe purity health ritual",
PrivateKeys: []string{
"932a39242805a1b1095638027f26af9664d1d5bf8ab3b7527ee75e7efb2946dd",
"1c17c9c049d36cde7e5ea99df6c86e0474b04f0e258ab619a1e674f397a17152",
"458130a239671674746582184711a6f8d633355df1a491b9f3b323576134c2e9",
"2676fd1427968e07feaa9aff967d4ba7607c5497c499968c098d0517cd75cfbb",
"d26b24a691ff2b03ee6ab65bf164def216f73574996b9ca6299c43a9a63767ac",
"55df6adf3d081944dbe4688205d94f236fb4427ac44f3a286a96d47db0860667",
"8a9a60ddd722a40753c2a38edd6b6fa38e806d681c9b08a520ba4912e62b6458",
"75eb182fb623acf5e53d9885c4e8578f2530533a96c753481cc4277ecc6022de",
"6c4b22b1d9d68ef7a8ecd151cd4ffdd4ecc2a7b3a3f8a9f9f9bbdbcef6671f10",
"e578d66453cb41b6c923b9caa91c375a0545eeb171ccafc60b46fa834ce5c200",
},
// should not be empty, otherwise TRE will panic
More: []string{},
}

const (
DefaultTronPort = "9090"
)

func defaultTron(in *Input) {
if in.Image == "" {
in.Image = "tronbox/tre"
}
if in.Port == "" {
in.Port = DefaultTronPort
}
}

func newTron(in *Input) (*Output, error) {
defaultTron(in)
ctx := context.Background()

containerName := framework.DefaultTCName("blockchain-node")
bindPort := fmt.Sprintf("%s/tcp", in.Port)

accounts, err := os.CreateTemp("", "accounts.json")
if err != nil {
return nil, err
}
accountsData, err := json.Marshal(TRONAccounts)
if err != nil {
return nil, err
}

_, err = accounts.WriteString(string(accountsData))
if err != nil {
return nil, err
}

req := testcontainers.ContainerRequest{
AlwaysPullImage: in.PullImage,
Image: in.Image,
Name: containerName,
ExposedPorts: []string{bindPort},
Networks: []string{framework.DefaultNetworkName},
NetworkAliases: map[string][]string{
framework.DefaultNetworkName: {containerName},
},
Labels: framework.DefaultTCLabels(),
HostConfigModifier: func(h *container.HostConfig) {
h.PortBindings = framework.MapTheSamePort(bindPort)
},
WaitingFor: wait.ForLog("Mnemonic").WithPollInterval(200 * time.Millisecond).WithStartupTimeout(1 * time.Minute),
Files: []testcontainers.ContainerFile{
{
HostFilePath: accounts.Name(),
ContainerFilePath: "/config/accounts.json",
FileMode: 0644,
},
},
}

c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
return nil, err
}

host, err := c.Host(ctx)
if err != nil {
return nil, err
}

return &Output{
UseCache: true,
ChainID: in.ChainID,
Family: "tron",
ContainerName: containerName,
Nodes: []*Node{
{
HostHTTPUrl: fmt.Sprintf("http://%s:%s", host, in.Port),
DockerInternalHTTPUrl: fmt.Sprintf("http://%s:%s", containerName, in.Port),
},
},
}, nil
}
4 changes: 2 additions & 2 deletions framework/components/blockchain/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import (
)

// VerifyContract wraps the forge verify-contract command.
func VerifyContract(out *Output, address, foundryDir, contractFile, contractName string) error {
func VerifyContract(out *Output, address, foundryDir, contractFile, contractName, compilerVersion string) error {
args := []string{
"verify-contract",
"--rpc-url", out.Nodes[0].HostHTTPUrl,
"--chain-id",
out.ChainID,
"--compiler-version=0.8.24",
fmt.Sprintf("--compiler-version=%s", compilerVersion),
address,
fmt.Sprintf("%s:%s", contractFile, contractName),
"--verifier", "blockscout",
Expand Down
2 changes: 1 addition & 1 deletion framework/examples/myproject/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
github.com/blocto/solana-go-sdk v1.30.0
github.com/ethereum/go-ethereum v1.14.11
github.com/go-resty/resty/v2 v2.15.3
github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.1
github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.4
github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.10
github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2
github.com/stretchr/testify v1.10.0
Expand Down
3 changes: 3 additions & 0 deletions framework/examples/myproject/smoke_tron.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[blockchain_a]
type = "tron"
image = "tronbox/tre"
33 changes: 33 additions & 0 deletions framework/examples/myproject/smoke_tron_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package examples

import (
"github.com/smartcontractkit/chainlink-testing-framework/framework"
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
"github.com/stretchr/testify/require"
"testing"
)

type CfgTron struct {
BlockchainA *blockchain.Input `toml:"blockchain_a" validate:"required"`
}

func TestTRONSmoke(t *testing.T) {
in, err := framework.Load[CfgTron](t)
require.NoError(t, err)

bc, err := blockchain.NewBlockchainNetwork(in.BlockchainA)
require.NoError(t, err)

// all private keys are funded
_ = blockchain.TRONAccounts.PrivateKeys[0]

t.Run("test something", func(t *testing.T) {
// use internal URL to connect Chainlink nodes
_ = bc.Nodes[0].DockerInternalHTTPUrl
// use host URL to interact
_ = bc.Nodes[0].HostHTTPUrl

// use bc.Nodes[0].HostHTTPUrl + "/wallet" to access full node
// use bc.Nodes[0].HostHTTPUrl + "/walletsolidity" to access Solidity node
})
}
1 change: 1 addition & 0 deletions framework/examples/myproject/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func TestVerify(t *testing.T) {
"example_components/onchain",
"src/Counter.sol",
"Counter",
"0.8.13",
)
require.NoError(t, err)
})
Expand Down

0 comments on commit ddb6854

Please sign in to comment.