Skip to content

Commit

Permalink
[TT-414] Solana Dockerization WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
tateexon committed Sep 22, 2023
1 parent 26fdcf3 commit 4543e46
Show file tree
Hide file tree
Showing 11 changed files with 2,042 additions and 261 deletions.
2 changes: 1 addition & 1 deletion .github/actions/build_contract_artifacts/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ runs:
repository: smartcontractkit/chainlink-solana
ref: ${{ inputs.ref }}
- name: Setup go
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version-file: "go.mod"
check-latest: true
Expand Down
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ gauntlet/packages/gauntlet-serum-multisig/networks/.env.local

# test
id.json
tests/e2e/logs
tests/e2e/smoke/logs
tests/e2e/smoke/contracts-chaos-state.json
integration-tests/smoke/logs
integration-tests/smoke/contracts-chaos-state.json
tmp-manifest-*
tests-smoke-report.xml
.env.test*
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Contents

- [How To Run E2E Tests](../../docs/RunningE2eTests.md)
- [How To Run E2E Tests](../docs/RunningE2eTests.md)
203 changes: 156 additions & 47 deletions integration-tests/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/smartcontractkit/chainlink-env/environment"
"github.com/smartcontractkit/chainlink-env/pkg/alias"
"github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink"
"github.com/smartcontractkit/chainlink-env/pkg/helm/mock-adapter"
mock_adapter "github.com/smartcontractkit/chainlink-env/pkg/helm/mock-adapter"
"github.com/smartcontractkit/chainlink-env/pkg/helm/sol"

"github.com/smartcontractkit/libocr/offchainreporting2/confighelper"
Expand All @@ -30,10 +30,18 @@ import (

"github.com/smartcontractkit/chainlink/integration-tests/client"
"github.com/smartcontractkit/chainlink/integration-tests/contracts"
"github.com/smartcontractkit/chainlink/integration-tests/docker/test_env"
"github.com/smartcontractkit/chainlink/integration-tests/types/config/node"
"github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/smartcontractkit/chainlink/v2/core/chains/solana"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
"github.com/smartcontractkit/chainlink/v2/core/store/models"

relay_utils "github.com/smartcontractkit/chainlink-relay/pkg/utils"
test_env_sol "github.com/smartcontractkit/chainlink-solana/integration-tests/docker/test_env"
"github.com/smartcontractkit/chainlink-solana/integration-tests/solclient"
solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
cl "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
)

const (
Expand All @@ -47,6 +55,7 @@ const (
)

type Common struct {
IsK8s bool
ChainName string
ChainId string
NodeCount int
Expand All @@ -55,19 +64,27 @@ type Common struct {
EnvConfig map[string]interface{}
K8Config *environment.Config
Env *environment.Environment
DockerEnv *SolCLClusterTestEnv
SolanaUrl string
}

type SolCLClusterTestEnv struct {
*test_env.CLClusterTestEnv
Sol *test_env_sol.Solana
}

// ContractNodeInfo contains the indexes of the nodes, bridges, NodeKeyBundles and nodes relevant to an OCR2 Contract
type ContractNodeInfo struct {
OCR2 *solclient.OCRv2
Store *solclient.Store
BootstrapNodeIdx int
BootstrapNode *client.ChainlinkK8sClient
BootstrapNode *client.ChainlinkClient
BootstrapNodeK8s *client.ChainlinkK8sClient
BootstrapNodeKeysBundle client.NodeKeysBundle
BootstrapBridgeInfo BridgeInfo
NodesIdx []int
Nodes []*client.ChainlinkK8sClient
Nodes []*client.ChainlinkClient
NodesK8s []*client.ChainlinkK8sClient
NodeKeysBundle []client.NodeKeysBundle
BridgeInfos []BridgeInfo
}
Expand All @@ -94,17 +111,19 @@ func stripKeyPrefix(key string) string {
return key
}

func New(env string) *Common {
func New(env string, isK8s bool) *Common {
var err error
var c *Common
if env == "devnet" {
c = &Common{
IsK8s: isK8s,
ChainName: ChainName,
ChainId: DevnetChainID,
SolanaUrl: SolanaDevnetURL,
}
} else {
c = &Common{
IsK8s: isK8s,
ChainName: ChainName,
ChainId: LocalnetChainID,
SolanaUrl: SolanaLocalNetURL,
Expand Down Expand Up @@ -237,18 +256,19 @@ func FundOracles(c *solclient.Client, nkb []client.NodeKeysBundle, amount *big.F
}

// OffChainConfigParamsFromNodes creates contracts.OffChainAggregatorV2Config
func OffChainConfigParamsFromNodes(nodes []*client.ChainlinkK8sClient, nkb []client.NodeKeysBundle) (contracts.OffChainAggregatorV2Config, error) {
func OffChainConfigParamsFromNodes(nodeCount int, nkb []client.NodeKeysBundle) (contracts.OffChainAggregatorV2Config, error) {
oi, err := createOracleIdentities(nkb)
if err != nil {
return contracts.OffChainAggregatorV2Config{}, err
}
s := make([]int, 0)
for range nodes {
// for range nodes {
for i := 0; i < nodeCount; i++ {
s = append(s, 1)
}
faultyNodes := 0
if len(nodes) > 1 {
faultyNodes = len(nodes)/3 - 1
if nodeCount > 1 {
faultyNodes = nodeCount/3 - 1
}
if faultyNodes == 0 {
faultyNodes = 1
Expand Down Expand Up @@ -277,10 +297,16 @@ func OffChainConfigParamsFromNodes(nodes []*client.ChainlinkK8sClient, nkb []cli
}, nil
}

func CreateBridges(ContractsIdxMapToContractsNodeInfo map[int]*ContractNodeInfo, mockUrl string) error {
func CreateBridges(ContractsIdxMapToContractsNodeInfo map[int]*ContractNodeInfo, mockUrl string, isK8s bool) error {
for i, nodesInfo := range ContractsIdxMapToContractsNodeInfo {
// Bootstrap node first
nodeContractPairID, err := BuildNodeContractPairID(nodesInfo.BootstrapNode.ChainlinkClient, nodesInfo.OCR2.Address())
var err error
var nodeContractPairID string
if isK8s {
nodeContractPairID, err = BuildNodeContractPairID(nodesInfo.BootstrapNodeK8s.ChainlinkClient, nodesInfo.OCR2.Address())
} else {
nodeContractPairID, err = BuildNodeContractPairID(nodesInfo.BootstrapNode, nodesInfo.OCR2.Address())
}
if err != nil {
return err
}
Expand All @@ -290,7 +316,11 @@ func CreateBridges(ContractsIdxMapToContractsNodeInfo map[int]*ContractNodeInfo,
RequestData: "{}",
}
observationSource := client.ObservationSourceSpecBridge(&sourceValueBridge)
err = nodesInfo.BootstrapNode.MustCreateBridge(&sourceValueBridge)
if isK8s {
err = nodesInfo.BootstrapNodeK8s.MustCreateBridge(&sourceValueBridge)
} else {
err = nodesInfo.BootstrapNode.MustCreateBridge(&sourceValueBridge)
}
if err != nil {
return err
}
Expand All @@ -300,14 +330,30 @@ func CreateBridges(ContractsIdxMapToContractsNodeInfo map[int]*ContractNodeInfo,
RequestData: "{}",
}
juelsSource := client.ObservationSourceSpecBridge(&juelsBridge)
err = nodesInfo.BootstrapNode.MustCreateBridge(&juelsBridge)
if isK8s {
err = nodesInfo.BootstrapNodeK8s.MustCreateBridge(&juelsBridge)
} else {
err = nodesInfo.BootstrapNode.MustCreateBridge(&juelsBridge)
}
if err != nil {
return err
}
ContractsIdxMapToContractsNodeInfo[i].BootstrapBridgeInfo = BridgeInfo{ObservationSource: observationSource, JuelsSource: juelsSource}
// Other nodes later
for _, node := range nodesInfo.Nodes {
nodeContractPairID, err := BuildNodeContractPairID(node.ChainlinkClient, nodesInfo.OCR2.Address())
var nodeCount int
if isK8s {
nodeCount = len(nodesInfo.NodesK8s)
} else {
nodeCount = len(nodesInfo.Nodes)
}
for j := 0; j < nodeCount; j++ {
var clClient *client.ChainlinkClient
if isK8s {
clClient = nodesInfo.NodesK8s[j].ChainlinkClient
} else {
clClient = nodesInfo.Nodes[j]
}
nodeContractPairID, err := BuildNodeContractPairID(clClient, nodesInfo.OCR2.Address())
if err != nil {
return err
}
Expand All @@ -317,7 +363,11 @@ func CreateBridges(ContractsIdxMapToContractsNodeInfo map[int]*ContractNodeInfo,
RequestData: "{}",
}
observationSource := client.ObservationSourceSpecBridge(&sourceValueBridge)
err = node.MustCreateBridge(&sourceValueBridge)
if isK8s {
err = nodesInfo.NodesK8s[j].MustCreateBridge(&sourceValueBridge)
} else {
err = nodesInfo.Nodes[j].MustCreateBridge(&sourceValueBridge)
}
if err != nil {
return err
}
Expand All @@ -327,7 +377,11 @@ func CreateBridges(ContractsIdxMapToContractsNodeInfo map[int]*ContractNodeInfo,
RequestData: "{}",
}
juelsSource := client.ObservationSourceSpecBridge(&juelsBridge)
err = node.MustCreateBridge(&juelsBridge)
if isK8s {
err = nodesInfo.NodesK8s[j].MustCreateBridge(&juelsBridge)
} else {
err = nodesInfo.Nodes[j].MustCreateBridge(&juelsBridge)
}
if err != nil {
return err
}
Expand All @@ -344,6 +398,15 @@ func PluginConfigToTomlFormat(pluginConfig string) job.JSONConfig {
}

func (c *Common) CreateJobsForContract(contractNodeInfo *ContractNodeInfo) error {
var bootstrapNodeInternalIP string
var nodeCount int
if c.IsK8s {
nodeCount = len(contractNodeInfo.NodesK8s)
bootstrapNodeInternalIP = contractNodeInfo.BootstrapNodeK8s.InternalIP()
} else {
nodeCount = len(contractNodeInfo.Nodes)
bootstrapNodeInternalIP = contractNodeInfo.BootstrapNode.InternalIP()
}
relayConfig := job.JSONConfig{
"nodeEndpointHTTP": fmt.Sprintf("\"%s\"", SolanaLocalNetURL),
"ocr2ProgramID": fmt.Sprintf("\"%s\"", contractNodeInfo.OCR2.ProgramAddress()),
Expand All @@ -353,7 +416,7 @@ func (c *Common) CreateJobsForContract(contractNodeInfo *ContractNodeInfo) error
}
bootstrapPeers := []client.P2PData{
{
InternalIP: contractNodeInfo.BootstrapNode.InternalIP(),
InternalIP: bootstrapNodeInternalIP,
InternalPort: "6690",
PeerID: contractNodeInfo.BootstrapNodeKeysBundle.PeerID,
},
Expand All @@ -372,11 +435,19 @@ func (c *Common) CreateJobsForContract(contractNodeInfo *ContractNodeInfo) error
ContractConfigTrackerPollInterval: models.Interval(15 * time.Second),
},
}
if _, err := contractNodeInfo.BootstrapNode.MustCreateJob(jobSpec); err != nil {
s, _ := jobSpec.String()
return fmt.Errorf("failed creating job for boostrap node: %w\n spec:\n%s", err, s)
if c.IsK8s {
if _, err := contractNodeInfo.BootstrapNodeK8s.MustCreateJob(jobSpec); err != nil {
s, _ := jobSpec.String()
return fmt.Errorf("failed creating job for boostrap node: %w\n spec:\n%s", err, s)
}
} else {
if _, err := contractNodeInfo.BootstrapNode.MustCreateJob(jobSpec); err != nil {
s, _ := jobSpec.String()
return fmt.Errorf("failed creating job for boostrap node: %w\n spec:\n%s", err, s)
}
}
for nIdx, n := range contractNodeInfo.Nodes {

for nIdx := 0; nIdx < nodeCount; nIdx++ {
jobSpec := &client.OCR2TaskJobSpec{
Name: fmt.Sprintf("sol-OCRv2-%d-%s", nIdx, uuid.NewV4().String()),
JobType: "offchainreporting2",
Expand All @@ -394,8 +465,16 @@ func (c *Common) CreateJobsForContract(contractNodeInfo *ContractNodeInfo) error
PluginConfig: PluginConfigToTomlFormat(contractNodeInfo.BridgeInfos[nIdx].JuelsSource),
},
}
if _, err := n.MustCreateJob(jobSpec); err != nil {
return fmt.Errorf("failed creating job for node %s: %w", n.URL(), err)
if c.IsK8s {
n := contractNodeInfo.NodesK8s[nIdx]
if _, err := n.MustCreateJob(jobSpec); err != nil {
return fmt.Errorf("failed creating job for node %s: %w", n.URL(), err)
}
} else {
n := contractNodeInfo.Nodes[nIdx]
if _, err := n.MustCreateJob(jobSpec); err != nil {
return fmt.Errorf("failed creating job for node %s: %w", n.URL(), err)
}
}
}
return nil
Expand All @@ -414,36 +493,66 @@ func BuildNodeContractPairID(node *client.ChainlinkClient, ocr2Addr string) (str
return strings.ToLower(fmt.Sprintf("node_%s_contract_%s", shortNodeAddr, shortOCRAddr)), nil
}

func (c *Common) DefaultBaseToml() string {
return fmt.Sprintf(`[[Solana]]
Enabled = true
ChainID = '%s'
[[Solana.Nodes]]
Name = 'primary'
URL = '%s'
[OCR2]
Enabled = true
[P2P]
[P2P.V2]
Enabled = true
DeltaDial = '5s'
DeltaReconcile = '5s'
ListenAddresses = ['0.0.0.0:6690']
`, c.ChainId, c.SolanaUrl)
}

func (c *Common) DefaultNodeConfig() *cl.Config {
solConfig := solana.SolanaConfig{
Enabled: utils.Ptr(true),
ChainID: utils.Ptr(c.ChainId),
Nodes: []*solcfg.Node{
{
Name: utils.Ptr("primary"),
URL: relay_utils.MustParseURL(c.SolanaUrl),
},
},
}
baseConfig := node.NewBaseConfig()
baseConfig.Solana = solana.SolanaConfigs{
&solConfig,
}
baseConfig.OCR2.Enabled = utils.Ptr(true)
baseConfig.P2P.V2.Enabled = utils.Ptr(true)
fiveSecondDuration := models.MustMakeDuration(5 * time.Second)
baseConfig.P2P.V2.DeltaDial = &fiveSecondDuration
baseConfig.P2P.V2.DeltaReconcile = &fiveSecondDuration
baseConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"}

return baseConfig
}

func (c *Common) Default(t *testing.T, namespacePrefix string) *Common {
c.K8Config = &environment.Config{
NamespacePrefix: fmt.Sprintf("solana-%s", namespacePrefix),
TTL: c.TTL,
Test: t,
}
baseTOML := fmt.Sprintf(`[[Solana]]
Enabled = true
ChainID = '%s'
[[Solana.Nodes]]
Name = 'primary'
URL = '%s'
[OCR2]
Enabled = true
[P2P]
[P2P.V2]
Enabled = true
DeltaDial = '5s'
DeltaReconcile = '5s'
ListenAddresses = ['0.0.0.0:6690']
`, c.ChainId, c.SolanaUrl)
c.Env = environment.New(c.K8Config).
AddHelm(sol.New(nil)).
AddHelm(mock_adapter.New(nil)).
AddHelm(chainlink.New(0, map[string]interface{}{
"toml": baseTOML,
"replicas": c.NodeCount,
}))
if c.IsK8s {
c.Env = environment.New(c.K8Config).
AddHelm(sol.New(nil)).
AddHelm(mock_adapter.New(nil)).
AddHelm(chainlink.New(0, map[string]interface{}{
"toml": c.DefaultBaseToml(),
"replicas": c.NodeCount,
}))
}

return c
}
Loading

0 comments on commit 4543e46

Please sign in to comment.