Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/develop' into SHIP-…
Browse files Browse the repository at this point in the history
…1523-xlayer
  • Loading branch information
friedemannf committed Apr 26, 2024
2 parents 0ff1275 + b1c8d74 commit 69044b0
Show file tree
Hide file tree
Showing 55 changed files with 1,043 additions and 98 deletions.
7 changes: 7 additions & 0 deletions .changeset/brave-dots-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"chainlink": minor
---

Added a new CLI command, `blocks find-lca,` which finds the latest block that is available in both the database and on the chain for the specified chain.
Added a new CLI command, `node remove-blocks,` which removes all blocks and logs greater than or equal to the specified block number.
#nops #added
5 changes: 5 additions & 0 deletions .changeset/pink-schools-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#bugfix Fixed an issue where the `rebroadcast-transactions` commands did not execute config validation.
13 changes: 13 additions & 0 deletions .changeset/sour-jars-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"chainlink": patch
---

#added

Add configurability to mercury transmitter

```toml
[Mercury.Transmitter]
TransmitQueueMaxSize = 10_000 # Default
TransmitTimeout = "5s" # Default
```
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ runs:
[ChainlinkUpgradeImage]
image="$UPGRADE_IMAGE"
version="$UPGRADE_VERSION"
postgres_version="$CHAINLINK_POSTGRES_VERSION"
[Logging]
test_log_collect=$test_log_collect
Expand Down
90 changes: 39 additions & 51 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,40 +218,6 @@ jobs:
AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
dep_evm_sha: ${{ inputs.evm-ref }}

build-test-image:
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image')
environment: integration
permissions:
id-token: write
contents: read
name: Build Test Image
runs-on: ubuntu22.04-16cores-64GB
needs: [changes]
steps:
- name: Collect Metrics
if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
with:
id: ${{ env.COLLECTION_ID }}-build-test-image
org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
this-job-name: Build Test Image
continue-on-error: true
- name: Checkout the repo
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
repository: smartcontractkit/chainlink
ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }}
- name: Build Test Image
if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
uses: ./.github/actions/build-test-image
with:
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}

compare-tests:
needs: [changes]
runs-on: ubuntu-latest
Expand Down Expand Up @@ -726,7 +692,7 @@ jobs:
cache_restore_only: "true"
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
QA_KUBECONFIG: ""
should_tidy: "false"
- name: Show Otel-Collector Logs
if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins'
Expand Down Expand Up @@ -830,6 +796,7 @@ jobs:
# Run the setup if the matrix finishes but this time save the cache if we have a cache hit miss
# this will also only run if both of the matrix jobs pass
eth-smoke-go-mod-cache:

environment: integration
needs: [eth-smoke-tests]
runs-on: ubuntu-latest
Expand Down Expand Up @@ -863,7 +830,7 @@ jobs:
id-token: write
contents: read
runs-on: ubuntu-latest
needs: [build-chainlink, changes, build-test-image]
needs: [build-chainlink, changes]
# Only run migration tests on new tags
if: startsWith(github.ref, 'refs/tags/')
env:
Expand All @@ -876,6 +843,17 @@ jobs:
TEST_LOG_LEVEL: debug
TEST_SUITE: migration
steps:
- name: Collect Metrics
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
with:
id: ${{ env.COLLECTION_ID }}-migration-tests
org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
this-job-name: Version Migration Tests
test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
continue-on-error: true
- name: Checkout the repo
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
Expand All @@ -886,7 +864,12 @@ jobs:
run: |
untrimmed_ver=$(curl --header "Authorization: token ${{ secrets.GITHUB_TOKEN }}" --request GET https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r .name)
latest_version="${untrimmed_ver:1}"
echo "latest_version=${latest_version} | tee -a $GITHUB_OUTPUT"
# Check if latest_version is empty
if [ -z "$latest_version" ]; then
echo "Error: The latest_version is empty. The migration tests need a verison to run."
exit 1
fi
echo "latest_version=${latest_version}" >> "$GITHUB_OUTPUT"
- name: Name Versions
run: |
echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ inputs.evm-ref || github.sha }}'"
Expand All @@ -898,13 +881,22 @@ jobs:
chainlinkVersion: ${{ steps.get_latest_version.outputs.latest_version }}
upgradeImage: ${{ env.UPGRADE_IMAGE }}
upgradeVersion: ${{ env.UPGRADE_VERSION }}
runId: ${{ github.run_id }}
testLogCollect: ${{ vars.TEST_LOG_COLLECT }}
lokiEndpoint: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
lokiTenantId: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
lokiBasicAuth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
grafanaUrl: ${{ vars.GRAFANA_URL }}
grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- name: Run Migration Tests
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@519851800779323566b7b7c22cc21bff95dbb639 # v2.3.11
with:
test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage
test_command_to_run: cd ./integration-tests && go test -timeout 20m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage
test_download_vendor_packages_command: cd ./integration-tests && go mod download
cl_repo: ${{ env.CHAINLINK_IMAGE }}
cl_image_tag: ${{ steps.get_latest_version.outputs.latest_version }}
aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
artifacts_name: node-migration-test-logs
artifacts_location: |
./integration-tests/migration/logs
Expand All @@ -916,28 +908,24 @@ jobs:
cache_restore_only: "true"
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
QA_KUBECONFIG: ""
go_coverage_src_dir: /var/tmp/go-coverage
go_coverage_dest_dir: ${{ github.workspace }}/.covdata
should_tidy: "false"
- name: Upload Coverage Data
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: cl-node-coverage-data-migration-tests
path: .covdata
retention-days: 1

- name: Collect Metrics
if: always()
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
- name: Notify Slack
if: failure() && github.event_name != 'workflow_dispatch'
uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
env:
SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
with:
id: ${{ env.COLLECTION_ID }}-migration-tests
org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
this-job-name: Version Migration Tests
test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
continue-on-error: true
channel-id: "#team-test-tooling-internal"
slack-message: ":x: :mild-panic-intensifies: Node Migration Tests Failed: ${{ job.html_url }}\n${{ format('https://github.com/smartcontractkit/chainlink/actions/runs/{0}', github.run_id) }}"

## Solana Section
get_solana_sha:
Expand Down
8 changes: 8 additions & 0 deletions core/chains/evm/logpoller/disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,11 @@ func (d disabled) LatestBlockByEventSigsAddrsWithConfs(ctx context.Context, from
func (d disabled) LogsDataWordBetween(ctx context.Context, eventSig common.Hash, address common.Address, wordIndexMin, wordIndexMax int, wordValue common.Hash, confs Confirmations) ([]Log, error) {
return nil, ErrDisabled
}

func (d disabled) FindLCA(ctx context.Context) (*LogPollerBlock, error) {
return nil, ErrDisabled
}

func (d disabled) DeleteLogsAndBlocksAfter(ctx context.Context, start int64) error {
return ErrDisabled
}
99 changes: 99 additions & 0 deletions core/chains/evm/logpoller/log_poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type LogPoller interface {
GetFilters() map[string]Filter
LatestBlock(ctx context.Context) (LogPollerBlock, error)
GetBlocksRange(ctx context.Context, numbers []uint64) ([]LogPollerBlock, error)
FindLCA(ctx context.Context) (*LogPollerBlock, error)
DeleteLogsAndBlocksAfter(ctx context.Context, start int64) error

// General querying
Logs(ctx context.Context, start, end int64, eventSig common.Hash, address common.Address) ([]Log, error)
Expand Down Expand Up @@ -1422,6 +1424,103 @@ func (lp *logPoller) IndexedLogsWithSigsExcluding(ctx context.Context, address c
return lp.orm.SelectIndexedLogsWithSigsExcluding(ctx, eventSigA, eventSigB, topicIndex, address, fromBlock, toBlock, confs)
}

// DeleteLogsAndBlocksAfter - removes blocks and logs starting from the specified block
func (lp *logPoller) DeleteLogsAndBlocksAfter(ctx context.Context, start int64) error {
return lp.orm.DeleteLogsAndBlocksAfter(ctx, start)
}

func (lp *logPoller) FindLCA(ctx context.Context) (*LogPollerBlock, error) {
latest, err := lp.orm.SelectLatestBlock(ctx)
if err != nil {
return nil, fmt.Errorf("failed to select the latest block: %w", err)
}

oldest, err := lp.orm.SelectOldestBlock(ctx, 0)
if err != nil {
return nil, fmt.Errorf("failed to select the oldest block: %w", err)
}

if latest == nil || oldest == nil {
return nil, fmt.Errorf("expected at least one block to be present in DB")
}

lp.lggr.Debugf("Received request to find LCA. Searching in range [%d, %d]", oldest.BlockNumber, latest.BlockNumber)

// Find the largest block number for which block hash stored in the DB matches one that we get from the RPC.
// `sort.Find` expects slice of following format s = [1, 0, -1] and returns smallest index i for which s[i] = 0.
// To utilise `sort.Find` we represent range of blocks as slice [latestBlock, latestBlock-1, ..., olderBlock+1, oldestBlock]
// and return 1 if DB block was reorged or 0 if it's still present on chain.
lcaI, found := sort.Find(int(latest.BlockNumber-oldest.BlockNumber)+1, func(i int) int {
const notFound = 1
const found = 0
// if there is an error - stop the search
if err != nil {
return notFound
}

// canceled search
if ctx.Err() != nil {
err = fmt.Errorf("aborted, FindLCA request cancelled: %w", ctx.Err())
return notFound
}
iBlockNumber := latest.BlockNumber - int64(i)
var dbBlock *LogPollerBlock
// Block with specified block number might not exist in the database, to address that we check closest child
// of the iBlockNumber. If the child is present on chain, it's safe to assume that iBlockNumber is present too
dbBlock, err = lp.orm.SelectOldestBlock(ctx, iBlockNumber)
if err != nil {
err = fmt.Errorf("failed to select block %d by number: %w", iBlockNumber, err)
return notFound
}

if dbBlock == nil {
err = fmt.Errorf("expected block to exist with blockNumber >= %d as observed block with number %d", iBlockNumber, latest.BlockNumber)
return notFound
}

lp.lggr.Debugf("Looking for matching block on chain blockNumber: %d blockHash: %s",
dbBlock.BlockNumber, dbBlock.BlockHash)
var chainBlock *evmtypes.Head
chainBlock, err = lp.ec.HeadByHash(ctx, dbBlock.BlockHash)
// our block in DB does not exist on chain
if (chainBlock == nil && err == nil) || errors.Is(err, ethereum.NotFound) {
err = nil
return notFound
}
if err != nil {
err = fmt.Errorf("failed to get block %s from RPC: %w", dbBlock.BlockHash, err)
return notFound
}

if chainBlock.BlockNumber() != dbBlock.BlockNumber {
err = fmt.Errorf("expected block numbers to match (db: %d, chain: %d), if block hashes match "+
"(db: %s, chain: %s)", dbBlock.BlockNumber, chainBlock.BlockNumber(), dbBlock.BlockHash, chainBlock.Hash)
return notFound
}

return found
})
if err != nil {
return nil, fmt.Errorf("failed to find: %w", err)
}

if !found {
return nil, fmt.Errorf("failed to find LCA, this means that whole database LogPoller state was reorged out of chain or RPC/Core node is misconfigured")
}

lcaBlockNumber := latest.BlockNumber - int64(lcaI)
lca, err := lp.orm.SelectBlockByNumber(ctx, lcaBlockNumber)
if err != nil {
return nil, fmt.Errorf("failed to select lca from db: %w", err)
}

if lca == nil {
return nil, fmt.Errorf("expected lca (blockNum: %d) to exist in DB", lcaBlockNumber)
}

return lca, nil
}

func EvmWord(i uint64) common.Hash {
var b = make([]byte, 8)
binary.BigEndian.PutUint64(b, i)
Expand Down
Loading

0 comments on commit 69044b0

Please sign in to comment.