Skip to content

Commit

Permalink
Merge branch 'master' into 9404-reinstateWalletupgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Oct 29, 2024
2 parents 9fbe223 + 745d557 commit 63393c8
Show file tree
Hide file tree
Showing 13 changed files with 851 additions and 58 deletions.
30 changes: 19 additions & 11 deletions a3p-integration/proposals/n:upgrade-next/priceFeedUpdate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import {
getVaultPrices,
getVatDetails,
openVault,
pushPrices,
registerOraclesForBrand,
USER1ADDR,
} from '@agoric/synthetic-chain';
import {
getPriceFeedRoundId,
verifyPushedPrice,
} from './test-lib/price-feed.js';

import { BID_OFFER_ID } from './agd-tools.js';

Expand All @@ -37,12 +39,17 @@ const checkPriceFeedVatsUpdated = async t => {
await checkForOracle(t, 'stATOM');
};

console.log('adding oracle for each brand');
const oraclesByBrand = generateOracleMap('f-priceFeeds', ['ATOM', 'stATOM']);
await registerOraclesForBrand('ATOM', oraclesByBrand);
await registerOraclesForBrand('stATOM', oraclesByBrand);
/*
* The Oracle for ATOM and stATOM brands are being registered in the offer made at file:
* a3p-integration/proposals/n:upgrade-next/verifyPushedPrice.js
* which is being executed during the use phase of upgrade-next proposal
*/
const oraclesByBrand = generateOracleMap('n-upgrade', ['ATOM', 'stATOM']);

let roundId = 1;
const latestAtomRoundId = await getPriceFeedRoundId('ATOM');
const latestStAtomRoundId = await getPriceFeedRoundId('stATOM');
let atomRoundId = latestAtomRoundId + 1;
let stAtomRoundId = latestStAtomRoundId + 1;

const tryPushPrices = async t => {
// There are no old prices for the other currencies.
Expand All @@ -52,9 +59,10 @@ const tryPushPrices = async t => {
// t.is(stAtomOutPre, '+12010000');

t.log('pushing new prices');
await pushPrices(13.4, 'ATOM', oraclesByBrand, roundId);
await pushPrices(13.7, 'stATOM', oraclesByBrand, roundId);
roundId += 1;
await verifyPushedPrice(13.4, 'ATOM', oraclesByBrand, atomRoundId);
await verifyPushedPrice(13.7, 'stATOM', oraclesByBrand, stAtomRoundId);
atomRoundId += 1;
stAtomRoundId += 1;

t.log('awaiting new quotes');
const atomOut = await getPriceQuote('ATOM');
Expand Down Expand Up @@ -89,7 +97,7 @@ const openMarginalVault = async t => {
};

const triggerAuction = async t => {
await pushPrices(5.2, 'ATOM', oraclesByBrand, roundId);
await verifyPushedPrice(5.2, 'ATOM', oraclesByBrand, atomRoundId);

const atomOut = await getPriceQuote('ATOM');
t.is(atomOut, '+5200000');
Expand Down
62 changes: 62 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/test-lib/price-feed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* eslint-env node */

import {
agoric,
getContractInfo,
pushPrices,
getPriceQuote,
} from '@agoric/synthetic-chain';
import { retryUntilCondition } from './sync-tools.js';

export const scale6 = x => BigInt(x * 1_000_000);

/**
*
* @param {number} price
* @param {string} brand
* @param {Map<any, any>} oraclesByBrand
* @param {number} roundId
* @returns {Promise<void>}
*/
export const verifyPushedPrice = async (
price,
brand,
oraclesByBrand,
roundId,
) => {
const pushPriceRetryOpts = {
maxRetries: 5, // arbitrary
retryIntervalMs: 5000, // in ms
};

await pushPrices(price, brand, oraclesByBrand, roundId);
console.log(`Pushing price ${price} for ${brand}`);

await retryUntilCondition(
() => getPriceQuote(brand),
res => res === `+${scale6(price).toString()}`,
'price not pushed yet',
{
log: console.log,
setTimeout: global.setTimeout,
...pushPriceRetryOpts,
},
);
console.log(`Price ${price} pushed for ${brand}`);
};

/**
*
* @param {string} brand
* @returns {Promise<number>}
*/
export const getPriceFeedRoundId = async brand => {
const latestRoundPath = `published.priceFeed.${brand}-USD_price_feed.latestRound`;
const latestRound = await getContractInfo(latestRoundPath, {
agoric,
prefix: '',
});

console.log('latestRound: ', latestRound);
return Number(latestRound.roundId);
};
72 changes: 72 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/test-lib/sync-tools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* eslint-env node */

/**
* @file These tools mostly duplicate code that will be added in other PRs
* and eventually migrated to synthetic-chain. Sorry for the duplication.
*/

/**
* @typedef {object} RetryOptions
* @property {number} [maxRetries]
* @property {number} [retryIntervalMs]
* @property {(...arg0: string[]) => void} log
* @property {(object) => void} [setTimeout]
* @property {string} [errorMessage=Error]
*/

const ambientSetTimeout = global.setTimeout;

/**
* From https://github.com/Agoric/agoric-sdk/blob/442f07c8f0af03281b52b90e90c27131eef6f331/multichain-testing/tools/sleep.ts#L10
*
* @param {number} ms
* @param {*} sleepOptions
*/
const sleep = (ms, { log = () => {}, setTimeout = ambientSetTimeout }) =>
new Promise(resolve => {
log(`Sleeping for ${ms}ms...`);
setTimeout(resolve, ms);
});

/**
* From https://github.com/Agoric/agoric-sdk/blob/442f07c8f0af03281b52b90e90c27131eef6f331/multichain-testing/tools/sleep.ts#L24
*
* @param {() => Promise} operation
* @param {(result: any) => boolean} condition
* @param {string} message
* @param {RetryOptions} options
*/
export const retryUntilCondition = async (
operation,
condition,
message,
{ maxRetries = 6, retryIntervalMs = 3500, log, setTimeout },
) => {
console.log({ maxRetries, retryIntervalMs, message });
let retries = 0;

await null;
while (retries < maxRetries) {
try {
const result = await operation();
log('RESULT', result);
if (condition(result)) {
return result;
}
} catch (error) {
if (error instanceof Error) {
log(`Error: ${error.message}`);
} else {
log(`Unknown error: ${String(error)}`);
}
}

retries += 1;
console.log(
`Retry ${retries}/${maxRetries} - Waiting for ${retryIntervalMs}ms for ${message}...`,
);
await sleep(retryIntervalMs, { log, setTimeout });
}

throw Error(`${message} condition failed after ${maxRetries} retries.`);
};
3 changes: 3 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/use.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ set -uxeo pipefail

node ./addGov4
./acceptInvites.js

./verifyPushedPrice.js 'ATOM' 12.01
./verifyPushedPrice.js 'stATOM' 12.01
21 changes: 21 additions & 0 deletions a3p-integration/proposals/n:upgrade-next/verifyPushedPrice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env node

import {
registerOraclesForBrand,
generateOracleMap,
} from '@agoric/synthetic-chain';
import { argv } from 'node:process';
import { verifyPushedPrice } from './test-lib/price-feed.js';

const brand = argv[2];
const price = Number(argv[3]);

const BASE_ID = 'n-upgrade';
const ROUND_ID = 1;

const oraclesByBrand = generateOracleMap(BASE_ID, [brand]);
await registerOraclesForBrand(brand, oraclesByBrand);
console.log(`Registering Oracle for ${brand}`);

await verifyPushedPrice(price, brand, oraclesByBrand, ROUND_ID);
console.log(`Price pushed for ${brand}`);
38 changes: 0 additions & 38 deletions a3p-integration/proposals/z:acceptance/vaults.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,15 @@ import {
adjustVault,
closeVault,
getISTBalance,
getPriceQuote,
pushPrices,
getContractInfo,
ATOM_DENOM,
USER1ADDR,
waitForBlock,
registerOraclesForBrand,
generateOracleMap,
} from '@agoric/synthetic-chain';
import { getBalances, agopsVaults } from './test-lib/utils.js';
import { retryUntilCondition } from './test-lib/sync-tools.js';

export const scale6 = x => BigInt(x * 1_000_000);

// There may be a new vaultFactory that doesn't have prices yet, so we publish
// prices now
test.before(async t => {
const pushPriceRetryOpts = {
maxRetries: 5, // arbitrary
retryIntervalMs: 5000, // in ms
};
t.context = {
roundId: 1,
retryOpts: {
pushPriceRetryOpts,
},
};
const oraclesByBrand = generateOracleMap('z-acc', ['ATOM']);
await registerOraclesForBrand('ATOM', oraclesByBrand);

const price = 15.2;
// @ts-expect-error t.context is fine
await pushPrices(price, 'ATOM', oraclesByBrand, t.context.roundId);

await retryUntilCondition(
() => getPriceQuote('ATOM'),
res => res === `+${scale6(price).toString()}`,
'price not pushed yet',
{
log: t.log,
setTimeout: global.setTimeout,
// @ts-expect-error t.context is fine
...t.context.pushPriceRetryOpts,
},
);
});

test.serial('attempt to open vaults under the minimum amount', async t => {
const activeVaultsBefore = await agopsVaults(USER1ADDR);
await bankSend(USER1ADDR, `20000000${ATOM_DENOM}`);
Expand Down
20 changes: 18 additions & 2 deletions packages/cosmic-swingset/src/launch-chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ export async function launch({
inboundNum,
sender,
count: messages.length,
messages,
ack,
});
if (!mb.deliverInbound(sender, messages, ack)) {
return;
Expand All @@ -539,6 +541,7 @@ export async function launch({
type: 'cosmic-swingset-bridge-inbound',
inboundNum,
source,
body,
});
if (!bridgeInbound) throw Fail`bridgeInbound undefined`;
// console.log(`doBridgeInbound`);
Expand All @@ -547,7 +550,7 @@ export async function launch({
bridgeInbound(source, body);
}

async function installBundle(bundleJson) {
async function installBundle(bundleJson, inboundNum) {
let bundle;
try {
bundle = JSON.parse(bundleJson);
Expand All @@ -564,6 +567,13 @@ export async function launch({

const { endoZipBase64Sha512 } = bundle;

controller.writeSlogObject({
type: 'cosmic-swingset-install-bundle',
inboundNum,
endoZipBase64Sha512,
error,
});

if (installationPublisher === undefined) {
return;
}
Expand Down Expand Up @@ -645,7 +655,7 @@ export async function launch({
}

case ActionType.INSTALL_BUNDLE: {
p = installBundle(action.bundle);
p = installBundle(action.bundle, inboundNum);
break;
}

Expand Down Expand Up @@ -714,6 +724,12 @@ export async function launch({
// Then, update the timer device with the new external time, which might
// push work onto the kernel run-queue (if any timers were ready to wake).
const addedToQueue = timer.poll(blockTime);
controller.writeSlogObject({
type: 'cosmic-swingset-timer-poll',
blockHeight,
blockTime,
added: addedToQueue,
});
console.debug(
`polled; blockTime:${blockTime}, h:${blockHeight}; ADDED =`,
addedToQueue,
Expand Down
3 changes: 3 additions & 0 deletions packages/telemetry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@
"@endo/marshal": "^1.6.1",
"@endo/stream": "^1.2.7",
"@opentelemetry/api": "~1.3.0",
"@opentelemetry/api-logs": "0.53.0",
"@opentelemetry/exporter-prometheus": "~0.35.0",
"@opentelemetry/exporter-logs-otlp-http": "0.53.0",
"@opentelemetry/exporter-trace-otlp-http": "~0.35.0",
"@opentelemetry/resources": "~1.9.0",
"@opentelemetry/sdk-logs": "0.53.0",
"@opentelemetry/sdk-metrics": "~1.9.0",
"@opentelemetry/sdk-trace-base": "~1.9.0",
"@opentelemetry/semantic-conventions": "~1.27.0",
Expand Down
42 changes: 42 additions & 0 deletions packages/telemetry/src/context-aware-slog-file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-env node */

import { makeFsStreamWriter } from '@agoric/internal/src/node/fs-stream.js';
import { makeContextualSlogProcessor } from './context-aware-slog.js';
import { serializeSlogObj } from './serialize-slog-obj.js';

/**
* @param {import('./index.js').MakeSlogSenderOptions} options
*/
export const makeSlogSender = async options => {
const { CHAIN_ID, CONTEXTUAL_SLOGFILE } = options.env || {};
if (!CONTEXTUAL_SLOGFILE)
return console.warn(
'Ignoring invocation of slogger "context-aware-slog-file" without the presence of "CONTEXTUAL_SLOGFILE"',
);

const stream = await makeFsStreamWriter(CONTEXTUAL_SLOGFILE);

if (!stream)
return console.error(
`Couldn't create a write stream on file "${CONTEXTUAL_SLOGFILE}"`,
);

const contextualSlogProcessor = makeContextualSlogProcessor({
'chain-id': CHAIN_ID,
});

/**
* @param {import('./context-aware-slog.js').Slog} slog
*/
const slogSender = slog => {
const contextualizedSlog = contextualSlogProcessor(slog);

// eslint-disable-next-line prefer-template
stream.write(serializeSlogObj(contextualizedSlog) + '\n').catch(() => {});
};

return Object.assign(slogSender, {
forceFlush: () => stream.flush(),
shutdown: () => stream.close(),
});
};
Loading

0 comments on commit 63393c8

Please sign in to comment.