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

test of revising chain info #9552

Merged
merged 4 commits into from
Jun 21, 2024
Merged
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
45 changes: 39 additions & 6 deletions packages/boot/test/bootstrapTests/orchestration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import { Fail } from '@agoric/assert';
import { AmountMath } from '@agoric/ertp';
import { documentStorageSchema } from '@agoric/internal/src/storage-test-utils.js';
import type { CosmosValidatorAddress } from '@agoric/orchestration';
import type { start as startStakeIca } from '@agoric/orchestration/src/examples/stakeIca.contract.js';
import type { Instance } from '@agoric/zoe/src/zoeService/utils.js';
import { M, matches } from '@endo/patterns';
import type { TestFn } from 'ava';
import { documentStorageSchema } from '@agoric/internal/src/storage-test-utils.js';
import {
makeWalletFactoryContext,
type WalletFactoryTestContext,
Expand Down Expand Up @@ -56,13 +56,14 @@ test.serial('config', async t => {
'chainConnection',
'cosmoshub-4_juno-1',
);
t.like(connection, {
state: 3,
transferChannel: { portId: 'transfer', state: 3 },
});

t.like(
t.deepEqual(
readLatest(`published.agoricNames.chainConnection.cosmoshub-4_juno-1`),
{
state: 3,
transferChannel: { portId: 'transfer', state: 3 },
},
connection,
);

await documentStorageSchema(t, storage, {
Expand Down Expand Up @@ -230,3 +231,35 @@ test.serial('stakeAtom - smart wallet', async t => {
'delegate fails with invalid validator',
);
});

// XXX rely on .serial to be in sequence, and keep this one last
test.serial('revise chain info', async t => {
const {
buildProposal,
evalProposal,
runUtils: { EV },
} = t.context;

const agoricNames = await EV.vat('bootstrap').consumeItem('agoricNames');

await t.throwsAsync(EV(agoricNames).lookup('chain', 'hot'), {
message: '"nameKey" not found: "hot"',
});

// Revise chain info in agoricNames with the fixture in this script
await evalProposal(
buildProposal('@agoric/builders/scripts/testing/append-chain-info.js'),
);

const hotchain = await EV(agoricNames).lookup('chain', 'hot');
t.deepEqual(hotchain, { allegedName: 'Hot New Chain', chainId: 'hot-1' });

const connection = await EV(agoricNames).lookup(
'chainConnection',
'cosmoshub-4_hot-1',
);
t.like(connection, {
id: 'connection-99',
client_id: '07-tendermint-3',
});
});
4 changes: 2 additions & 2 deletions packages/builders/scripts/inter-protocol/add-STARS.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defaultProposalBuilder as vaultProposalBuilder } from './add-collateral
import { defaultProposalBuilder as oraclesProposalBuilder } from './price-feed-core.js';

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const starsVaultProposalBuilder = async powers => {
const starsVaultProposalBuilder = async powers => {
return vaultProposalBuilder(powers, {
interchainAssetOptions: {
// Values for the Stargaze token on Osmosis
Expand All @@ -18,7 +18,7 @@ export const starsVaultProposalBuilder = async powers => {
};

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const starsOraclesProposalBuilder = async powers => {
const starsOraclesProposalBuilder = async powers => {
return oraclesProposalBuilder(powers, {
AGORIC_INSTANCE_NAME: `STARS-USD price feed`,
IN_BRAND_LOOKUP: ['agoricNames', 'oracleBrand', 'STARS'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { makeHelpers } from '@agoric/deploy-script-support';
import { getManifestForGame1 } from '@agoric/smart-wallet/test/start-game1-proposal.js';

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const game1ProposalBuilder = async ({ publishRef, install }) => {
const game1ProposalBuilder = async ({ publishRef, install }) => {
return harden({
sourceSpec: '@agoric/smart-wallet/test/start-game1-proposal.js',
getManifestCall: [
Expand Down
2 changes: 1 addition & 1 deletion packages/builders/scripts/testing/add-LEMONS.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { defaultProposalBuilder as vaultProposalBuilder } from '../inter-protoco
/** @file This is for use in tests in a3p-integration */

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const starsVaultProposalBuilder = async powers => {
const starsVaultProposalBuilder = async powers => {
return vaultProposalBuilder(powers, {
interchainAssetOptions: {
denom: 'ibc/000C0FFEECAFE000',
Expand Down
2 changes: 1 addition & 1 deletion packages/builders/scripts/testing/add-OLIVES.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { defaultProposalBuilder as vaultProposalBuilder } from '../inter-protoco
/** @file This is for use in tests in a3p-integration */

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const stars2VaultProposalBuilder = async powers => {
const stars2VaultProposalBuilder = async powers => {
return vaultProposalBuilder(powers, {
interchainAssetOptions: {
denom: 'ibc/111C0FFEECAFE111',
Expand Down
50 changes: 50 additions & 0 deletions packages/builders/scripts/testing/append-chain-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/// <reference types="ses" />
import { makeHelpers } from '@agoric/deploy-script-support';

/** @type {Record<string, import('@agoric/orchestration/src/chain-info.js').ChainInfo>} */
const chainInfo = {
hot: {
allegedName: 'Hot New Chain',
chainId: 'hot-1',
connections: {
'cosmoshub-4': {
id: 'connection-99',
client_id: '07-tendermint-3',
counterparty: {
client_id: '07-tendermint-2',
connection_id: 'connection-1',
prefix: {
key_prefix: '',
},
},
state: 3 /* IBCConnectionState.STATE_OPEN */,
transferChannel: {
portId: 'transfer',
channelId: 'channel-1',
counterPartyChannelId: 'channel-1',
counterPartyPortId: 'transfer',
ordering: 1 /* Order.ORDER_UNORDERED */,
state: 3 /* IBCConnectionState.STATE_OPEN */,
version: 'ics20-1',
},
},
},
},
};

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const defaultProposalBuilder = async () =>
harden({
sourceSpec: '@agoric/orchestration/src/proposals/revise-chain-info.js',
getManifestCall: [
'getManifestForReviseChains',
{
chainInfo,
},
],
});

export default async (homeP, endowments) => {
const { writeCoreEval } = await makeHelpers(homeP, endowments);
await writeCoreEval('revise-chain-info', defaultProposalBuilder);
};
53 changes: 53 additions & 0 deletions packages/builders/scripts/testing/tweak-chain-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// <reference types="ses" />
import { makeHelpers } from '@agoric/deploy-script-support';

/** @type {Record<string, import('@agoric/orchestration/src/chain-info.js').ChainInfo>} */
const chainInfo = {
agoric: {
chainId: 'agoric-4',
},
hot: {
allegedName: 'Hot New Chain',
chainId: 'hot-1',
connections: {
'cosmoshub-4': {
id: 'connection-99',
client_id: '07-tendermint-3',
counterparty: {
client_id: '07-tendermint-2',
connection_id: 'connection-1',
prefix: {
key_prefix: '',
},
},
state: 3 /* IBCConnectionState.STATE_OPEN */,
transferChannel: {
portId: 'transfer',
channelId: 'channel-1',
counterPartyChannelId: 'channel-1',
counterPartyPortId: 'transfer',
ordering: 1 /* Order.ORDER_UNORDERED */,
state: 3 /* IBCConnectionState.STATE_OPEN */,
version: 'ics20-1',
},
},
},
},
};

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
export const defaultProposalBuilder = async () =>
harden({
sourceSpec: '@agoric/orchestration/src/proposals/revise-chain-info.js',
getManifestCall: [
'getManifestForReviseChains',
{
chainInfo,
},
],
});

export default async (homeP, endowments) => {
const { writeCoreEval } = await makeHelpers(homeP, endowments);
await writeCoreEval('revise-chain-info', defaultProposalBuilder);
};
101 changes: 2 additions & 99 deletions packages/orchestration/scripts/fetch-chain-info.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
#!/usr/bin/env tsx
/** @file Fetch canonical chain info to generate the minimum needed for agoricNames */
import {
State as IBCChannelState,
Order,
} from '@agoric/cosmic-proto/ibc/core/channel/v1/channel.js';
import { State as IBCConnectionState } from '@agoric/cosmic-proto/ibc/core/connection/v1/connection.js';
import type { IBCChannelID, IBCConnectionID } from '@agoric/vats';
import { ChainRegistryClient } from '@chain-registry/client';
import type { IBCInfo } from '@chain-registry/types';
import assert from 'node:assert';
import fsp from 'node:fs/promises';
import prettier from 'prettier';
import type { CosmosChainInfo, IBCConnectionInfo } from '../src/cosmos-api.js';
import { convertChainInfo } from '../src/utils/registry.js';

// XXX script assumes it's run from the package path
// XXX .json would be more apt; UNTIL https://github.com/endojs/endo/issues/2110
Expand Down Expand Up @@ -43,96 +35,7 @@ const client = new ChainRegistryClient({
// chain info, assets and ibc data will be downloaded dynamically by invoking fetchUrls method
await client.fetchUrls();

const chainInfo = {} as Record<string, CosmosChainInfo>;

function toConnectionEntry(ibcInfo: IBCInfo, name: string) {
// IbcInfo encodes the undirected edge as a tuple of (chain_1, chain_2) in alphabetical order
const fromChain1 = ibcInfo.chain_1.chain_name === name;
const [from, to] = fromChain1
? [ibcInfo.chain_1, ibcInfo.chain_2]
: [ibcInfo.chain_2, ibcInfo.chain_1];
assert.equal(from.chain_name, name);
const transferChannels = ibcInfo.channels.filter(
c =>
c.chain_1.port_id === 'transfer' &&
// @ts-expect-error tags does not specify keys
c.tags?.preferred,
);
if (transferChannels.length === 0) {
console.warn(
'no transfer channel for [',
from.chain_name,
to.chain_name,
']',
'(skipping)',
);
return [];
}
if (transferChannels.length > 1) {
console.warn(
'multiple preferred transfer channels [',
from.chain_name,
to.chain_name,
']:',
transferChannels,
'(choosing first)',
);
}
const [channel] = transferChannels;
const [channelFrom, channelTo] = fromChain1
? [channel.chain_2, channel.chain_1]
: [channel.chain_1, channel.chain_2];
const record = {
id: from.connection_id as IBCConnectionID,
client_id: from.client_id,
counterparty: {
client_id: to.client_id,
connection_id: to.connection_id as IBCConnectionID,
prefix: {
key_prefix: 'FIXME',
},
},
state: IBCConnectionState.STATE_OPEN, // XXX presumably
transferChannel: {
channelId: channelFrom.channel_id as IBCChannelID,
portId: channelFrom.port_id,
counterPartyChannelId: channelTo.channel_id as IBCChannelID,
counterPartyPortId: channelTo.port_id,
// FIXME mapping, our guard expects a numerical enum
ordering: Order.ORDER_NONE_UNSPECIFIED,
state: IBCChannelState.STATE_OPEN, // XXX presumably
version: channel.version,
},
} as IBCConnectionInfo;
const destChainId = chainInfo[to.chain_name].chainId;
return [destChainId, record] as const;
}

for (const name of chainNames) {
console.log('processing info', name);

const chain = client.getChain(name);
chainInfo[name] = {
chainId: chain.chain_id,
stakingTokens: chain.staking?.staking_tokens,
// UNTIL https://github.com/Agoric/agoric-sdk/issues/9326
icqEnabled: name === 'osmosis',
};
}

// iterate this after chainInfo is filled out
for (const name of chainNames) {
console.log('processing connections', name);

const ibcData = client.getChainIbcData(name);
const connections = Object.fromEntries(
ibcData
.map(datum => toConnectionEntry(datum, name))
// sort alphabetically for consistency
.sort(([a], [b]) => a?.localeCompare(b)),
);
chainInfo[name] = { ...chainInfo[name], connections };
}
const chainInfo = await convertChainInfo(client);

const record = JSON.stringify(chainInfo, null, 2);
const src = `/** @file Generated by fetch-chain-info.ts */\nexport default /** @type {const} } */ (${record});`;
Expand Down
44 changes: 44 additions & 0 deletions packages/orchestration/src/proposals/revise-chain-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { makeTracer } from '@agoric/internal';
import { registerChain } from '../chain-info.js';

const trace = makeTracer('ReviseChainInfo', true);

/** @import {CosmosChainInfo} from '../types.js'; */

/**
* This will add news values AND overwrite any existing values. Voters on a
* proposal of core-eval must be careful not to overwrite any values operating
* in production.
*
* @param {BootstrapPowers} powers
* @param {{ options: { chainInfo: Record<string, CosmosChainInfo> } }} opt
*/
export const reviseChainInfo = async (
{ consume: { agoricNamesAdmin } },
{ options: { chainInfo } },
) => {
trace('init-chainInfo');

assert(chainInfo, 'chainInfo is required');

trace(chainInfo);

// Now register the names
for await (const [name, info] of Object.entries(chainInfo)) {
await registerChain(agoricNamesAdmin, name, info, trace);
}
};
harden(reviseChainInfo);

export const getManifestForReviseChains = (_powers, { chainInfo }) => ({
manifest: {
[reviseChainInfo.name]: {
consume: {
agoricNamesAdmin: true,
},
},
},
options: {
chainInfo,
},
});
Loading
Loading