Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
140 changes: 140 additions & 0 deletions .github/workflows/eco-tests-indexer-notify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: on eco-tests change notification

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- 'eco-tests/**'

permissions:
contents: read
pull-requests: write
issues: write

concurrency:
group: eco-tests-indexer-notify-${{ github.ref }}
cancel-in-progress: true

env:
ECO_TESTS_REVIEWERS: "evgeny-s"

jobs:
notify:
name: Notify indexer reviewer
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: List changed files under eco-tests/
id: changes
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
changed=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- 'eco-tests/' || true)
{
echo "files<<EOF"
echo "$changed"
echo "EOF"
} >> "$GITHUB_OUTPUT"

- name: Post or update sticky review-request comment
if: steps.changes.outputs.files != ''
uses: actions/github-script@v7
env:
CHANGED_FILES: ${{ steps.changes.outputs.files }}
REVIEWERS: ${{ env.ECO_TESTS_REVIEWERS }}
with:
script: |
const marker = '<!-- eco-tests-indexer-notify -->';

const reviewers = (process.env.REVIEWERS || '')
.split(',')
.map(s => s.trim())
.filter(Boolean);
const ccLine = reviewers.length
? reviewers.map(u => `@${u}`).join(' ')
: '_(no reviewers configured — set ECO_TESTS_REVIEWERS in the workflow)_';

const changed = (process.env.CHANGED_FILES || '').trim();
const fileList = changed
.split('\n')
.filter(Boolean)
.map(f => `- \`${f}\``)
.join('\n');

const body = [
marker,
'### eco-tests changed — indexer review required',
'',
'This PR modifies files under `eco-tests/`. and may affect downstream indexing.',
`**cc ${ccLine}** — please review manually`,
'',
'<details><summary>Changed files</summary>',
'',
fileList,
'',
'</details>',
].join('\n');

const { owner, repo } = context.repo;
const issue_number = context.issue.number;

const comments = await github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number, per_page: 100 }
);
const existing = comments.find(c => c.body && c.body.includes(marker));

if (existing) {
if (existing.body !== body) {
await github.rest.issues.updateComment({
owner, repo, comment_id: existing.id, body,
});
}
} else {
await github.rest.issues.createComment({
owner, repo, issue_number, body,
});
}

- name: Request reviews from configured reviewers
if: steps.changes.outputs.files != ''
uses: actions/github-script@v7
env:
REVIEWERS: ${{ env.ECO_TESTS_REVIEWERS }}
with:
script: |
const reviewers = (process.env.REVIEWERS || '')
.split(',')
.map(s => s.trim())
.filter(Boolean);
if (reviewers.length === 0) {
core.info('ECO_TESTS_REVIEWERS is empty — skipping review request.');
return;
}

const { owner, repo } = context.repo;
const pull_number = context.issue.number;
const pr = await github.rest.pulls.get({ owner, repo, pull_number });

// GitHub rejects requesting a review from the PR author.
const author = pr.data.user && pr.data.user.login;
const filtered = reviewers.filter(u => u !== author);
if (filtered.length === 0) {
core.info(`All configured reviewers are the PR author (${author}) — skipping.`);
return;
}

try {
await github.rest.pulls.requestReviewers({
owner, repo, pull_number,
reviewers: filtered,
});
} catch (e) {
core.warning(`requestReviewers failed: ${e.message}`);
}
4 changes: 4 additions & 0 deletions eco-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ pallet-scheduler = { git = "https://github.com/opentensor/polkadot-sdk.git", rev
pallet-preimage = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "7cc54bf2d50ae3921d718736dfeb0de9468539c7", default-features = false, features = ["std"] }
pallet-drand = { path = "../pallets/drand", default-features = false, features = ["std"] }
pallet-subtensor-swap = { path = "../pallets/swap", default-features = false, features = ["std"] }
pallet-subtensor-swap-runtime-api = { path = "../pallets/swap/runtime-api", default-features = false, features = ["std"] }
subtensor-custom-rpc-runtime-api = { path = "../pallets/subtensor/runtime-api", default-features = false, features = ["std"] }
sp-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "7cc54bf2d50ae3921d718736dfeb0de9468539c7", default-features = false, features = ["std"] }
pallet-crowdloan = { path = "../pallets/crowdloan", default-features = false, features = ["std"] }
pallet-subtensor-proxy = { path = "../pallets/proxy", default-features = false, features = ["std"] }
pallet-subtensor-utility = { path = "../pallets/utility", default-features = false, features = ["std"] }
pallet-shield = { path = "../pallets/shield", default-features = false, features = ["std"] }
subtensor-runtime-common = { path = "../common", default-features = false, features = ["std"] }
subtensor-swap-interface = { path = "../pallets/swap-interface", default-features = false, features = ["std"] }
share-pool = { path = "../primitives/share-pool", default-features = false, features = ["std"] }
substrate-fixed = { git = "https://github.com/encointer/substrate-fixed.git", tag = "v0.6.0", default-features = false, features = ["std"] }
safe-math = { path = "../primitives/safe-math", default-features = false, features = ["std"] }
log = { version = "0.4.21", default-features = false, features = ["std"] }
approx = "0.5"
Expand Down
3 changes: 3 additions & 0 deletions eco-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ mod helpers;
mod mock;
#[cfg(test)]
mod tests;

#[cfg(test)]
mod tests_taocom_indexer;
81 changes: 80 additions & 1 deletion eco-tests/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ use sp_std::{cell::RefCell, cmp::Ordering, sync::OnceLock};
use sp_tracing::tracing_subscriber;
use subtensor_runtime_common::{AuthorshipInfo, NetUid, TaoBalance};
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
type Block = frame_system::mocking::MockBlock<Test>;
pub type Block = frame_system::mocking::MockBlock<Test>;
pub use api_mocks::MockApi;

// Configure a mock runtime to test the pallet.
frame_support::construct_runtime!(
Expand Down Expand Up @@ -600,3 +601,81 @@ pub fn add_balance_to_coldkey_account(coldkey: &U256, tao: TaoBalance) {
let credit = SubtensorModule::mint_tao(tao);
let _ = SubtensorModule::spend_tao(coldkey, credit, tao).unwrap();
}

mod api_mocks {
use codec::Compact;
use pallet_subtensor::rpc_info::delegate_info::DelegateInfo;
use pallet_subtensor::rpc_info::stake_info::StakeInfo;
use pallet_subtensor_swap_runtime_api::{SimSwapResult, SubnetPrice, SwapRuntimeApi};
use sp_runtime::AccountId32;
use subtensor_custom_rpc_runtime_api::{DelegateInfoRuntimeApi, StakeInfoRuntimeApi};
use subtensor_runtime_common::{AlphaBalance, NetUid, TaoBalance};

use super::Block;

pub struct MockApi;

sp_api::mock_impl_runtime_apis! {
impl DelegateInfoRuntimeApi<Block> for MockApi {
fn get_delegates() -> Vec<DelegateInfo<AccountId32>> { Vec::new() }
fn get_delegate(_delegate_account: AccountId32) -> Option<DelegateInfo<AccountId32>> { None }
fn get_delegated(
_delegatee_account: AccountId32,
) -> Vec<(DelegateInfo<AccountId32>, (Compact<NetUid>, Compact<AlphaBalance>))> {
Vec::new()
}
}

impl StakeInfoRuntimeApi<Block> for MockApi {
fn get_stake_info_for_coldkey(_coldkey_account: AccountId32) -> Vec<StakeInfo<AccountId32>> {
Vec::new()
}
fn get_stake_info_for_coldkeys(
_coldkey_accounts: Vec<AccountId32>,
) -> Vec<(AccountId32, Vec<StakeInfo<AccountId32>>)> {
Vec::new()
}
fn get_stake_info_for_hotkey_coldkey_netuid(
_hotkey_account: AccountId32,
_coldkey_account: AccountId32,
_netuid: NetUid,
) -> Option<StakeInfo<AccountId32>> {
None
}
fn get_stake_fee(
_origin: Option<(AccountId32, NetUid)>,
_origin_coldkey_account: AccountId32,
_destination: Option<(AccountId32, NetUid)>,
_destination_coldkey_account: AccountId32,
_amount: u64,
) -> u64 {
0
}
}

impl SwapRuntimeApi<Block> for MockApi {
fn current_alpha_price(_netuid: NetUid) -> u64 { 0 }
fn current_alpha_price_all() -> Vec<SubnetPrice> { Vec::new() }
fn sim_swap_tao_for_alpha(_netuid: NetUid, _tao: TaoBalance) -> SimSwapResult {
SimSwapResult {
tao_amount: 0u64.into(),
alpha_amount: 0u64.into(),
tao_fee: 0u64.into(),
alpha_fee: 0u64.into(),
tao_slippage: 0u64.into(),
alpha_slippage: 0u64.into(),
}
}
fn sim_swap_alpha_for_tao(_netuid: NetUid, _alpha: AlphaBalance) -> SimSwapResult {
SimSwapResult {
tao_amount: 0u64.into(),
alpha_amount: 0u64.into(),
tao_fee: 0u64.into(),
alpha_fee: 0u64.into(),
tao_slippage: 0u64.into(),
alpha_slippage: 0u64.into(),
}
}
}
}
}
Loading
Loading