Skip to content

Commit

Permalink
Removing chain dependencies from NewCommitServices construct (#1361)
Browse files Browse the repository at this point in the history
## Motivation
LOOP-ify

## Solution

---------

Co-authored-by: Bartek Tofel <[email protected]>
Co-authored-by: lukaszcl <[email protected]>
  • Loading branch information
3 people authored and valerii-kabisov-cll committed Oct 1, 2024
1 parent 258c699 commit 95da540
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 120 deletions.
4 changes: 4 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ install-chainlink: operator-ui ## Install the chainlink binary.
install-chainlink-cover: operator-ui ## Install the chainlink binary with cover flag.
go install -cover $(GOFLAGS) .

.PHONY: install-chainlink-delve
install-chainlink-delve: operator-ui ## Install the chainlink binary.
go install $(GOFLAGS) -gcflags "all=-N -l" .

.PHONY: chainlink
chainlink: ## Build the chainlink binary.
go build $(GOFLAGS) .
Expand Down
97 changes: 97 additions & 0 deletions core/chainlink.debug.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Build image: Chainlink binary
FROM golang:1.22-bullseye as buildgo
RUN go version
WORKDIR /chainlink

COPY GNUmakefile package.json ./
COPY tools/bin/ldflags ./tools/bin/

ADD go.mod go.sum ./
RUN go mod download

# Env vars needed for chainlink build
ARG COMMIT_SHA

# Build chainlink bin with cover flag https://go.dev/doc/build-cover#FAQ
ARG GO_COVER_FLAG=false

COPY . .

RUN apt-get update && apt-get install -y jq

# Build the golang binary
RUN if [ "$GO_COVER_FLAG" = "true" ]; then \
make install-chainlink-cover; \
else \
make install-chainlink-delve; \
fi

# Link LOOP Plugin source dirs with simple names
RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds | xargs -I % ln -s % /chainlink-feeds
RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana

# Build image: Plugins
FROM golang:1.22-bullseye as buildplugins
RUN go version

WORKDIR /chainlink-feeds
COPY --from=buildgo /chainlink-feeds .
RUN go install ./cmd/chainlink-feeds

WORKDIR /chainlink-solana
COPY --from=buildgo /chainlink-solana .
RUN go install ./pkg/solana/cmd/chainlink-solana

# Final image: ubuntu with chainlink binary
FROM golang:1.22-bullseye

ARG CHAINLINK_USER=root
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y ca-certificates gnupg lsb-release curl

# Install Postgres for CLI tools, needed specifically for DB backups
RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |tee /etc/apt/sources.list.d/pgdg.list \
&& apt-get update && apt-get install -y postgresql-client-16 \
&& apt-get clean all \
&& rm -rf /var/lib/apt/lists/*

COPY --from=buildgo /go/bin/chainlink /usr/local/bin/

# Install (but don't enable) LOOP Plugins
COPY --from=buildplugins /go/bin/chainlink-feeds /usr/local/bin/
COPY --from=buildplugins /go/bin/chainlink-solana /usr/local/bin/

# Dependency of CosmWasm/wasmd
COPY --from=buildgo /go/pkg/mod/github.com/\!cosm\!wasm/wasmvm@v*/internal/api/libwasmvm.*.so /usr/lib/
RUN chmod 755 /usr/lib/libwasmvm.*.so

RUN if [ ${CHAINLINK_USER} != root ]; then \
useradd --uid 14933 --create-home ${CHAINLINK_USER}; \
fi
USER ${CHAINLINK_USER}
WORKDIR /home/${CHAINLINK_USER}
RUN mkdir -p go
# explicit set the cache dir. needed so both root and non-root user has an explicit location
ENV XDG_CACHE_HOME /home/${CHAINLINK_USER}/.cache
RUN mkdir -p ${XDG_CACHE_HOME}

# Set up env and dir for go coverage profiling https://go.dev/doc/build-cover#FAQ
ARG GO_COVER_DIR="/var/tmp/go-coverage"
ENV GOCOVERDIR=${GO_COVER_DIR}
RUN mkdir -p $GO_COVER_DIR

# Install dlv
ENV GOPATH=/home/${CHAINLINK_USER}/go
ENV PATH=$PATH:$GOPATH/bin
RUN go install github.com/go-delve/delve/cmd/dlv@latest

EXPOSE 6688
ENTRYPOINT ["chainlink"]

HEALTHCHECK CMD curl -f http://localhost:6688/health || exit 1

# Delve port
EXPOSE 40000

CMD ["dlv", "exec", "/usr/local/bin/chainlink", "--accept-multiclient", "--headless", "--listen=0.0.0.0:40000", "--api-version=2", "--", "local", "node"]
92 changes: 80 additions & 12 deletions core/services/ocr2/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,20 @@ import (
"fmt"
"log"
"strconv"
"strings"
"time"

"gopkg.in/guregu/null.v4"

cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
"github.com/smartcontractkit/chainlink-common/pkg/types/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"

"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"google.golang.org/grpc"
"gopkg.in/guregu/null.v4"

chainselectors "github.com/smartcontractkit/chain-selectors"
"github.com/smartcontractkit/libocr/commontypes"
libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
"google.golang.org/grpc"

ocr2keepers20 "github.com/smartcontractkit/chainlink-automation/pkg/v2"
ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config"
Expand All @@ -38,10 +35,11 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins/ocr3"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
"github.com/smartcontractkit/chainlink-common/pkg/types"
cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
"github.com/smartcontractkit/chainlink-common/pkg/types/core"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
"github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
datastreamsllo "github.com/smartcontractkit/chainlink-data-streams/llo"

"github.com/smartcontractkit/chainlink/v2/core/bridges"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
coreconfig "github.com/smartcontractkit/chainlink/v2/core/config"
Expand All @@ -51,8 +49,11 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
"github.com/smartcontractkit/chainlink/v2/core/services/llo"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipcommit"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipexec"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/liquiditymanager"
Expand All @@ -62,7 +63,6 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper"

"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21"
ocr2keeper21core "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate"
Expand All @@ -78,8 +78,6 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
"github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
"github.com/smartcontractkit/chainlink/v2/plugins"

ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
)

type ErrJobSpecNoRelayer struct {
Expand Down Expand Up @@ -1611,7 +1609,77 @@ func (d *Delegate) newServicesCCIPCommit(ctx context.Context, lggr logger.Sugare
MetricsRegisterer: prometheus.WrapRegistererWith(map[string]string{"job_name": jb.Name.ValueOrZero()}, prometheus.DefaultRegisterer),
}

return ccipcommit.NewCommitServices(ctx, d.ds, srcProvider, dstProvider, d.legacyChains, jb, lggr, d.pipelineRunner, oracleArgsNoPlugin, d.isNewlyCreatedJob, int64(srcChainID), dstChainID, logError)
var priceGetter ccip.AllTokensPriceGetter
withPipeline := strings.Trim(pluginJobSpecConfig.TokenPricesUSDPipeline, "\n\t ") != ""
if withPipeline {
priceGetter, err = ccip.NewPipelineGetter(pluginJobSpecConfig.TokenPricesUSDPipeline, d.pipelineRunner, jb.ID, jb.ExternalJobID, jb.Name.ValueOrZero(), lggr)
if err != nil {
return nil, fmt.Errorf("creating pipeline price getter: %w", err)
}
} else {
// Use dynamic price getter.
if pluginJobSpecConfig.PriceGetterConfig == nil {
return nil, fmt.Errorf("priceGetterConfig is nil")
}

// Configure contract readers for all chains specified in the aggregator configurations.
// Some lanes (e.g. Wemix/Kroma) requires other clients than source and destination, since they use feeds from other chains.
aggregatorChainsToContracts := make(map[uint64][]common.Address)
for _, aggCfg := range pluginJobSpecConfig.PriceGetterConfig.AggregatorPrices {
if _, ok := aggregatorChainsToContracts[aggCfg.ChainID]; !ok {
aggregatorChainsToContracts[aggCfg.ChainID] = make([]common.Address, 0)
}

aggregatorChainsToContracts[aggCfg.ChainID] = append(aggregatorChainsToContracts[aggCfg.ChainID], aggCfg.AggregatorContractAddress)
}

contractReaders := map[uint64]types.ContractReader{}

for chainID, aggregatorContracts := range aggregatorChainsToContracts {
relayID := types.RelayID{Network: spec.Relay, ChainID: strconv.FormatUint(chainID, 10)}
relay, rerr := d.RelayGetter.Get(relayID)
if rerr != nil {
return nil, fmt.Errorf("get relay by id=%v: %w", relayID, err)
}

contractsConfig := make(map[string]evmrelaytypes.ChainContractReader, len(aggregatorContracts))
for i := range aggregatorContracts {
contractsConfig[fmt.Sprintf("%v_%v", ccip.OFFCHAIN_AGGREGATOR, i)] = evmrelaytypes.ChainContractReader{
ContractABI: ccip.OffChainAggregatorABI,
Configs: map[string]*evmrelaytypes.ChainReaderDefinition{
"decimals": { // CR consumers choose an alias
ChainSpecificName: "decimals",
},
"latestRoundData": {
ChainSpecificName: "latestRoundData",
},
},
}
}
contractReaderConfig := evmrelaytypes.ChainReaderConfig{
Contracts: contractsConfig,
}

contractReaderConfigJsonBytes, jerr := json.Marshal(contractReaderConfig)
if jerr != nil {
return nil, fmt.Errorf("marshal contract reader config: %w", jerr)
}

contractReader, cerr := relay.NewContractReader(ctx, contractReaderConfigJsonBytes)
if cerr != nil {
return nil, fmt.Errorf("new ccip commit contract reader %w", cerr)
}

contractReaders[chainID] = contractReader
}

priceGetter, err = ccip.NewDynamicPriceGetter(*pluginJobSpecConfig.PriceGetterConfig, contractReaders)
if err != nil {
return nil, fmt.Errorf("creating dynamic price getter: %w", err)
}
}

return ccipcommit.NewCommitServices(ctx, d.ds, srcProvider, dstProvider, priceGetter, jb, lggr, d.pipelineRunner, oracleArgsNoPlugin, d.isNewlyCreatedJob, int64(srcChainID), dstChainID, logError)
}

func newCCIPCommitPluginBytes(isSourceProvider bool, sourceStartBlock uint64, destStartBlock uint64) config.CommitPluginConfig {
Expand Down
47 changes: 1 addition & 46 deletions core/services/ocr2/plugins/ccip/ccipcommit/initializers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ package ccipcommit
import (
"context"
"encoding/json"
"fmt"
"math/big"
"strings"
"time"

"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"

"github.com/Masterminds/semver/v3"
"github.com/ethereum/go-ethereum/common"
libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"
Expand All @@ -27,7 +22,6 @@ import (
db "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdb"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
Expand All @@ -48,7 +42,7 @@ var defaultNewReportingPluginRetryConfig = ccipdata.RetryConfig{
MaxRetries: (6 * 4) + 10,
}

func NewCommitServices(ctx context.Context, ds sqlutil.DataSource, srcProvider commontypes.CCIPCommitProvider, dstProvider commontypes.CCIPCommitProvider, chainSet legacyevm.LegacyChainContainer, jb job.Job, lggr logger.Logger, pr pipeline.Runner, argsNoPlugin libocr2.OCR2OracleArgs, new bool, sourceChainID int64, destChainID int64, logError func(string)) ([]job.ServiceCtx, error) {
func NewCommitServices(ctx context.Context, ds sqlutil.DataSource, srcProvider commontypes.CCIPCommitProvider, dstProvider commontypes.CCIPCommitProvider, priceGetter ccip.AllTokensPriceGetter, jb job.Job, lggr logger.Logger, pr pipeline.Runner, argsNoPlugin libocr2.OCR2OracleArgs, new bool, sourceChainID int64, destChainID int64, logError func(string)) ([]job.ServiceCtx, error) {
spec := jb.OCR2OracleSpec

var pluginConfig ccipconfig.CommitPluginJobSpecConfig
Expand All @@ -75,45 +69,6 @@ func NewCommitServices(ctx context.Context, ds sqlutil.DataSource, srcProvider c
commitStoreReader = ccip.NewProviderProxyCommitStoreReader(srcCommitStore, dstCommitStore)
commitLggr := lggr.Named("CCIPCommit").With("sourceChain", sourceChainID, "destChain", destChainID)

var priceGetter pricegetter.AllTokensPriceGetter
withPipeline := strings.Trim(pluginConfig.TokenPricesUSDPipeline, "\n\t ") != ""
if withPipeline {
priceGetter, err = pricegetter.NewPipelineGetter(pluginConfig.TokenPricesUSDPipeline, pr, jb.ID, jb.ExternalJobID, jb.Name.ValueOrZero(), lggr)
if err != nil {
return nil, fmt.Errorf("creating pipeline price getter: %w", err)
}
} else {
// Use dynamic price getter.
if pluginConfig.PriceGetterConfig == nil {
return nil, fmt.Errorf("priceGetterConfig is nil")
}

// Build price getter clients for all chains specified in the aggregator configurations.
// Some lanes (e.g. Wemix/Kroma) requires other clients than source and destination, since they use feeds from other chains.
priceGetterClients := map[uint64]pricegetter.DynamicPriceGetterClient{}
for _, aggCfg := range pluginConfig.PriceGetterConfig.AggregatorPrices {
chainID := aggCfg.ChainID
// Retrieve the chain.
chain, _, err2 := ccipconfig.GetChainByChainID(chainSet, chainID)
if err2 != nil {
return nil, fmt.Errorf("retrieving chain for chainID %d: %w", chainID, err2)
}
caller := rpclib.NewDynamicLimitedBatchCaller(
lggr,
chain.Client(),
rpclib.DefaultRpcBatchSizeLimit,
rpclib.DefaultRpcBatchBackOffMultiplier,
rpclib.DefaultMaxParallelRpcCalls,
)
priceGetterClients[chainID] = pricegetter.NewDynamicPriceGetterClient(caller)
}

priceGetter, err = pricegetter.NewDynamicPriceGetter(*pluginConfig.PriceGetterConfig, priceGetterClients)
if err != nil {
return nil, fmt.Errorf("creating dynamic price getter: %w", err)
}
}

offRampReader, err := dstProvider.NewOffRampReader(ctx, pluginConfig.OffRamp)
if err != nil {
return nil, err
Expand Down
21 changes: 19 additions & 2 deletions core/services/ocr2/plugins/ccip/exportinternal.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import (
"math/big"
"time"

"github.com/smartcontractkit/chainlink-common/pkg/types"

"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
Expand All @@ -21,8 +25,13 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
)

const OFFCHAIN_AGGREGATOR = "OffchainAggregator"
const DECIMALS_METHOD_NAME = "decimals"
const LATEST_ROUND_DATA_METHOD_NAME = "latestRoundData"

func GenericAddrToEvm(addr ccip.Address) (common.Address, error) {
return ccipcalc.GenericAddrToEvm(addr)
}
Expand Down Expand Up @@ -71,12 +80,18 @@ type DynamicPriceGetterClient = pricegetter.DynamicPriceGetterClient

type DynamicPriceGetter = pricegetter.DynamicPriceGetter

type AllTokensPriceGetter = pricegetter.AllTokensPriceGetter

func NewPipelineGetter(source string, runner pipeline.Runner, jobID int32, externalJobID uuid.UUID, name string, lggr logger.Logger) (*pricegetter.PipelineGetter, error) {
return pricegetter.NewPipelineGetter(source, runner, jobID, externalJobID, name, lggr)
}

func NewDynamicPriceGetterClient(batchCaller rpclib.EvmBatchCaller) DynamicPriceGetterClient {
return pricegetter.NewDynamicPriceGetterClient(batchCaller)
}

func NewDynamicPriceGetter(cfg config.DynamicPriceGetterConfig, evmClients map[uint64]DynamicPriceGetterClient) (*DynamicPriceGetter, error) {
return pricegetter.NewDynamicPriceGetter(cfg, evmClients)
func NewDynamicPriceGetter(cfg config.DynamicPriceGetterConfig, contractReaders map[uint64]types.ContractReader) (*DynamicPriceGetter, error) {
return pricegetter.NewDynamicPriceGetter(cfg, contractReaders)
}

func NewDynamicLimitedBatchCaller(
Expand Down Expand Up @@ -133,3 +148,5 @@ func NewCommitOffchainConfig(
) ccip.CommitOffchainConfig {
return ccipdata.NewCommitOffchainConfig(gasPriceDeviationPPB, gasPriceHeartBeat, tokenPriceDeviationPPB, tokenPriceHeartBeat, inflightCacheExpiry, priceReportingDisabled)
}

const OffChainAggregatorABI = offchainaggregator.OffchainAggregatorABI
Loading

0 comments on commit 95da540

Please sign in to comment.