Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KIAB Streams Trigger Provisioner #14326

Draft
wants to merge 33 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
139ad08
Add node api wrapper for ergonomic cmd usage
HenryNguyen5 Sep 4, 2024
2f14875
Add streams trigger template
HenryNguyen5 Sep 4, 2024
0defb7d
Add mock external adapter for v03 mercury
HenryNguyen5 Sep 4, 2024
1b4d298
First pass of streams trigger provisioning
HenryNguyen5 Sep 4, 2024
4b03324
WIP: Add capabilities registry provisioner script
HenryNguyen5 Sep 7, 2024
7154202
Update nix flake
HenryNguyen5 Sep 13, 2024
7e0602c
Fixup provisioning scripts
HenryNguyen5 Sep 13, 2024
29980a4
Change default chainid to be 1337
HenryNguyen5 Sep 16, 2024
fc07b49
Add nil check for balances
HenryNguyen5 Sep 16, 2024
2785ec7
Add ability to skip tls verification for local dev
HenryNguyen5 Sep 16, 2024
1338c9c
Gently fail on not loading contracts for ocr job deletion
HenryNguyen5 Sep 16, 2024
0881e8a
fixup! Change default chainid to be 1337
HenryNguyen5 Sep 16, 2024
0cb9a2e
Formatting
HenryNguyen5 Sep 17, 2024
85ddd1a
Change ocr file flag default
HenryNguyen5 Sep 17, 2024
49b6a4d
Allow for multiple OCR2KB selection in key fetching
HenryNguyen5 Sep 17, 2024
3eccbb3
Support on/offchain transmitter OCR3 config generation
HenryNguyen5 Sep 17, 2024
c3b76cb
Properly reset clientmethod on each invocation
HenryNguyen5 Sep 17, 2024
f5e8623
Add mercury contract deployment feature
HenryNguyen5 Sep 17, 2024
9c49773
Get oracles to successfully connect to each other
HenryNguyen5 Sep 18, 2024
7abd46d
Keep OCR3 and OCR2 config separate
HenryNguyen5 Sep 18, 2024
e8883d1
Add goreleaser setup for mock ea
HenryNguyen5 Sep 19, 2024
efe1657
Add support for updating bridges
HenryNguyen5 Sep 19, 2024
9e6eb11
Add UpdateBridge CLI command
HenryNguyen5 Sep 19, 2024
f52f128
Cleanup comments
HenryNguyen5 Sep 20, 2024
1c25c1f
Fix typo
HenryNguyen5 Sep 20, 2024
fa9ab1a
Add revert detection and revert reason extraction
HenryNguyen5 Sep 20, 2024
efccb8b
WIP: Sendtx helper
HenryNguyen5 Sep 20, 2024
c87a41e
Add missing env field to CR struct
HenryNguyen5 Sep 20, 2024
b37f41a
Fix CR deployment bugs
HenryNguyen5 Sep 20, 2024
74af819
Fix trigger capability typo
HenryNguyen5 Sep 20, 2024
2182cde
Add external registry and capability p2p config gen
HenryNguyen5 Sep 20, 2024
011ddce
Add redial support for logging in
HenryNguyen5 Sep 20, 2024
baabe0b
Fix capability registration
HenryNguyen5 Sep 20, 2024
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
23 changes: 23 additions & 0 deletions core/cmd/bridge_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,29 @@ func (s *Shell) CreateBridge(c *cli.Context) (err error) {
return s.renderAPIResponse(resp, &BridgePresenter{})
}

func (s *Shell) UpdateBridge(c *cli.Context) (err error) {
if !c.Args().Present() {
return s.errorOut(errors.New("must pass the name of the bridge to be updated"))
}
bridgeName := c.Args().First()
buf, err := getBufferFromJSON(c.Args().Get(1))
if err != nil {
return s.errorOut(err)
}

resp, err := s.HTTP.Patch(s.ctx(), "/v2/bridge_types/"+bridgeName, buf)
if err != nil {
return s.errorOut(err)
}
defer func() {
if cerr := resp.Body.Close(); cerr != nil {
err = multierr.Append(err, cerr)
}
}()

return s.renderAPIResponse(resp, &BridgePresenter{})
}

// RemoveBridge removes a specific Bridge by name.
func (s *Shell) RemoveBridge(c *cli.Context) (err error) {
if !c.Args().Present() {
Expand Down
42 changes: 42 additions & 0 deletions core/cmd/bridge_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd_test
import (
"bytes"
"flag"
"fmt"
"testing"
"time"

Expand Down Expand Up @@ -191,3 +192,44 @@ func TestShell_RemoveBridge(t *testing.T) {
assert.Equal(t, bt.URL.String(), p.URL)
assert.Equal(t, bt.Confirmations, p.Confirmations)
}
func TestShell_UpdateBridge(t *testing.T) {
t.Parallel()

app := startNewApplicationV2(t, nil)
client, _ := app.NewShellAndRenderer()
name := testutils.RandomizeName("updatebridge")

bt := &bridges.BridgeType{
Name: bridges.MustParseBridgeName(name),
URL: cltest.WebURL(t, "https://testing.com/bridges"),
Confirmations: 0,
}
require.NoError(t, app.BridgeORM().CreateBridgeType(testutils.Context(t), bt))
tests := []struct {
name string
args []string
errored bool
}{
{"NoArgs", []string{}, true},
{"OnlyName", []string{name}, true},
{"ValidUpdate", []string{name, fmt.Sprintf(`{ "name": "%s", "url": "http://localhost:3000/updated" }`, name)}, false},
{"InvalidJSON", []string{name, `{ "url": "http://localhost:3000/updated"`}, true},
}

for _, tt := range tests {
test := tt
t.Run(test.name, func(t *testing.T) {
set := flag.NewFlagSet("bridge", 0)
flagSetApplyFromAction(client.UpdateBridge, set, "")

require.NoError(t, set.Parse(test.args))

c := cli.NewContext(nil, set, nil)
if test.errored {
assert.Error(t, client.UpdateBridge(c))
} else {
assert.Nil(t, client.UpdateBridge(c))
}
})
}
}
16 changes: 12 additions & 4 deletions core/scripts/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package common
import (
"context"
"crypto/ecdsa"
"crypto/tls"
"encoding/hex"
"flag"
"fmt"
"math/big"
"net/http"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -69,11 +71,17 @@ func SetupEnv(overrideNonce bool) Environment {
panic("need account key")
}

ec, err := ethclient.Dial(ethURL)
PanicErr(err)

jsonRPCClient, err := rpc.Dial(ethURL)
insecureSkipVerify := os.Getenv("INSECURE_SKIP_VERIFY") == "true"
tr := &http.Transport{
// User enables this at their own risk!
// #nosec G402
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify},
}
httpClient := &http.Client{Transport: tr}
rpcConfig := rpc.WithHTTPClient(httpClient)
jsonRPCClient, err := rpc.DialOptions(context.Background(), ethURL, rpcConfig)
PanicErr(err)
ec := ethclient.NewClient(jsonRPCClient)

chainID, err := strconv.ParseInt(chainIDEnv, 10, 64)
PanicErr(err)
Expand Down
2 changes: 1 addition & 1 deletion core/scripts/keystone/01_deploy_contracts-sample.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
go run main.go \
deploy-contracts \
--ocrfile=ocr_config.json \
--chainid=11155111 \
--chainid=1337 \
--ethurl=ETH_URL \
--accountkey=ACCOUNT_KEY \
--onlysetconfig=false \
Expand Down
2 changes: 1 addition & 1 deletion core/scripts/keystone/02_deploy_jobspecs-sample.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

go run main.go \
deploy-jobspecs \
--chainid=11155111 \
--chainid=1337 \
--p2pport=6690 \
--onlyreplay=false
2 changes: 1 addition & 1 deletion core/scripts/keystone/03_gen_crib-sample.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

go run main.go \
generate-crib \
--chainid=11155111 \
--chainid=1337 \
--outpath=/tmp
12 changes: 12 additions & 0 deletions core/scripts/keystone/04_deploy_streams_trigger-sample.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
# This is for arb sepolia, see jobspec on https://cl-df-mercury-arb-sepolia-0.main.stage.cldev.sh/jobs/34/definition
go run main.go \
deploy-streams-trigger \
--verifierproxycontractaddress=$VERIFIER_PROXY_CONTRACT_ADDRESS \
--verifiercontractaddress=$VERIFIER_CONTRACT_ADDRESS \
--chainid=$CHAIN_ID \
--fromblock=$FROM_BLOCK \
--linkfeedid=$LINK_FEED_ID \
--nativefeedid=$NATIVE_FEED_ID \
--feedid=$FEED_ID \
--dryrun=true
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

go run main.go \
deploy-and-initialize-capabilities-registry \
--chainid=11155111 \
--chainid=1337 \
--ethurl=$ETH_URL \
--accountkey=$ACCOUNT_KEY \
--craddress=$CR_ADDRESS \ // 0x0d36aAC2Fd9d6d1C1F59251be6A2B337af27C52B
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

go run main.go provision-capabilites-registry \
--chainid=11155111 \
--ethurl=$ETH_URL \
--accountkey=$ACCOUNT_KEY
2 changes: 2 additions & 0 deletions core/scripts/keystone/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ func main() {
src.NewDeployAndInitializeCapabilitiesRegistryCommand(),
src.NewDeployWorkflowsCommand(),
src.NewDeleteWorkflowsCommand(),
src.NewDeployStreamsTriggerCommand(),
src.NewProvisionCapabilitesRegistryCommand(),
}

commandsList := func(commands []command) string {
Expand Down
25 changes: 13 additions & 12 deletions core/scripts/keystone/src/01_deploy_contracts_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import (
)

type deployedContracts struct {
OCRContract common.Address `json:"ocrContract"`
ForwarderContract common.Address `json:"forwarderContract"`
OCRContract common.Address `json:"ocrContract"`
ForwarderContract common.Address `json:"forwarderContract"`
CapabilityRegistry common.Address `json:"capabilityRegistry"`
// The block number of the transaction that set the config on the OCR3 contract. We use this to replay blocks from this point on
// when we load the OCR3 job specs on the nodes.
SetConfigTxBlock uint64 `json:"setConfigTxBlock"`
Expand All @@ -43,11 +44,11 @@ func (g *deployContracts) Name() string {
// 5. Funds the transmitters
func (g *deployContracts) Run(args []string) {
fs := flag.NewFlagSet(g.Name(), flag.ExitOnError)
ocrConfigFile := fs.String("ocrfile", "config_example.json", "path to OCR config file")
ocrConfigFile := fs.String("ocrfile", "ocr_config.json", "path to OCR config file")
// create flags for all of the env vars then set the env vars to normalize the interface
// this is a bit of a hack but it's the easiest way to make this work
ethUrl := fs.String("ethurl", "", "URL of the Ethereum node")
chainID := fs.Int64("chainid", 11155111, "chain ID of the Ethereum network to deploy to")
chainID := fs.Int64("chainid", 1337, "chain ID of the Ethereum network to deploy to")
accountKey := fs.String("accountkey", "", "private key of the account to deploy from")
skipFunding := fs.Bool("skipfunding", false, "skip funding the transmitters")
onlySetConfig := fs.Bool("onlysetconfig", false, "set the config on the OCR3 contract without deploying the contracts or funding transmitters")
Expand Down Expand Up @@ -80,7 +81,7 @@ func (g *deployContracts) Run(args []string) {
os.Setenv("ETH_URL", *ethUrl)
os.Setenv("ETH_CHAIN_ID", fmt.Sprintf("%d", *chainID))
os.Setenv("ACCOUNT_KEY", *accountKey)

os.Setenv("INSECURE_SKIP_VERIFY", "true")
deploy(*nodeList, *publicKeys, *ocrConfigFile, *skipFunding, *dryRun, *onlySetConfig, *artefactsDir)
}

Expand Down Expand Up @@ -133,11 +134,7 @@ func deploy(
OCRContract: ocrContract.Address(),
ForwarderContract: forwarderContract.Address(),
}
jsonBytes, err := json.Marshal(contracts)
PanicErr(err)

err = os.WriteFile(DeployedContractsFilePath(artefacts), jsonBytes, 0600)
PanicErr(err)
WriteDeployedContracts(contracts, artefacts)

setOCR3Config(env, ocrConfig, artefacts)

Expand Down Expand Up @@ -178,9 +175,13 @@ func setOCR3Config(

// Write blocknumber of the transaction to the deployed contracts file
loadedContracts.SetConfigTxBlock = receipt.BlockNumber.Uint64()
jsonBytes, err := json.Marshal(loadedContracts)
WriteDeployedContracts(loadedContracts, artefacts)
}

func WriteDeployedContracts(contracts deployedContracts, artefactsDir string) {
jsonBytes, err := json.Marshal(contracts)
PanicErr(err)
err = os.WriteFile(DeployedContractsFilePath(artefacts), jsonBytes, 0600)
err = os.WriteFile(DeployedContractsFilePath(artefactsDir), jsonBytes, 0600)
PanicErr(err)
}

Expand Down
89 changes: 10 additions & 79 deletions core/scripts/keystone/src/02_deploy_jobspecs_cmd.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
package src

import (
"bytes"
"errors"
"flag"
"fmt"
"os"
"reflect"
"runtime"
"strings"

"github.com/urfave/cli"

helpers "github.com/smartcontractkit/chainlink/core/scripts/common"
"github.com/smartcontractkit/chainlink/v2/core/cmd"
)

// Could be useful https://github.com/smartcontractkit/chainlink/blob/4d5fc1943bd6a60b49cbc3d263c0aa47dc3cecb7/core/scripts/chaincli/handler/scrape_node_config.go#L102
type deployJobSpecs struct{}

func NewDeployJobSpecsCommand() *deployJobSpecs {
Expand All @@ -28,7 +21,7 @@ func (g *deployJobSpecs) Name() string {

func (g *deployJobSpecs) Run(args []string) {
fs := flag.NewFlagSet(g.Name(), flag.ContinueOnError)
chainID := fs.Int64("chainid", 11155111, "chain id")
chainID := fs.Int64("chainid", 1337, "chain id")
p2pPort := fs.Int64("p2pport", 6690, "p2p port")
onlyReplay := fs.Bool("onlyreplay", false, "only replay the block from the OCR3 contract setConfig transaction")
templatesLocation := fs.String("templates", "", "Custom templates location")
Expand Down Expand Up @@ -79,87 +72,25 @@ func (g *deployJobSpecs) Run(args []string) {
}

for i, n := range nodes {
output := &bytes.Buffer{}
client, app := newApp(n, output)
fmt.Println("Logging in:", n.url)
loginFs := flag.NewFlagSet("test", flag.ContinueOnError)
loginFs.Bool("bypass-version-check", true, "")
loginCtx := cli.NewContext(app, loginFs, nil)
err := client.RemoteLogin(loginCtx)
helpers.PanicErr(err)
output.Reset()

api := newNodeAPI(n)
if !*onlyReplay {
specToDeploy := flattenedSpecs[i].spec.ToString()
specFragment := flattenedSpecs[i].spec[0:1]
fmt.Printf("Deploying jobspec: %s\n... \n", specFragment)
fs := flag.NewFlagSet("test", flag.ExitOnError)
err = fs.Parse([]string{specToDeploy})

helpers.PanicErr(err)
err = client.CreateJob(cli.NewContext(app, fs, nil))
_, err := api.withArg(specToDeploy).exec(api.methods.CreateJob)
if err != nil {
fmt.Println("Failed to deploy job spec:", specFragment, "Error:", err)
}
output.Reset()
}

replayFs := flag.NewFlagSet("test", flag.ExitOnError)
flagSetApplyFromAction(client.ReplayFromBlock, replayFs, "")
err = replayFs.Set("block-number", fmt.Sprint(deployedContracts.SetConfigTxBlock))
helpers.PanicErr(err)
err = replayFs.Set("evm-chain-id", fmt.Sprint(*chainID))
helpers.PanicErr(err)

fmt.Printf("Replaying from block: %d\n", deployedContracts.SetConfigTxBlock)
fmt.Printf("EVM Chain ID: %d\n\n", *chainID)
replayCtx := cli.NewContext(app, replayFs, nil)
err = client.ReplayFromBlock(replayCtx)
helpers.PanicErr(err)
}
}

// flagSetApplyFromAction applies the flags from action to the flagSet.
//
// `parentCommand` will filter the app commands and only applies the flags if the command/subcommand has a parent with that name, if left empty no filtering is done
//
// Taken from: https://github.com/smartcontractkit/chainlink/blob/develop/core/cmd/shell_test.go#L590
func flagSetApplyFromAction(action interface{}, flagSet *flag.FlagSet, parentCommand string) {
cliApp := cmd.Shell{}
app := cmd.NewApp(&cliApp)

foundName := parentCommand == ""
actionFuncName := getFuncName(action)

for _, command := range app.Commands {
flags := recursiveFindFlagsWithName(actionFuncName, command, parentCommand, foundName)

for _, flag := range flags {
flag.Apply(flagSet)
}
}
}

func recursiveFindFlagsWithName(actionFuncName string, command cli.Command, parent string, foundName bool) []cli.Flag {
if command.Action != nil {
if actionFuncName == getFuncName(command.Action) && foundName {
return command.Flags
}
}

for _, subcommand := range command.Subcommands {
if !foundName {
foundName = strings.EqualFold(subcommand.Name, parent)
}

found := recursiveFindFlagsWithName(actionFuncName, subcommand, parent, foundName)
if found != nil {
return found
}
api.withFlags(api.methods.ReplayFromBlock, func(fs *flag.FlagSet) {
err = fs.Set("block-number", fmt.Sprint(deployedContracts.SetConfigTxBlock))
helpers.PanicErr(err)
err = fs.Set("evm-chain-id", fmt.Sprint(*chainID))
helpers.PanicErr(err)
}).mustExec()
}
return nil
}

func getFuncName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
Loading
Loading