Skip to content

Commit

Permalink
feat: add upgrade-15 (proposal 74)
Browse files Browse the repository at this point in the history
- see https://github.com/Agoric/agoric-sdk/tree/dev-upgrade-15/a3p-integration/proposals/a%3Aupgrade-15

Co-Authored-By: 0xPatrick <patrick@0xpatrick.dev>
Co-Authored-By: Richard Gibson <1199584+gibson042@users.noreply.github.com>
  • Loading branch information
2 people authored and turadg committed May 24, 2024
1 parent 7646a5c commit 8a5cb08
Show file tree
Hide file tree
Showing 10 changed files with 2,515 additions and 0 deletions.
1 change: 1 addition & 0 deletions proposals/74:upgrade-15/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
5 changes: 5 additions & 0 deletions proposals/74:upgrade-15/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Proposal to upgrade the chain software to upgrade-15

This software upgrade executes core proposals during the upgrade block, as
defined by the `agoric-upgrade-15` upgrade handler. See `upgrade15Handler` in
`agoric-sdk/golang/cosmos/app/app.go`.
38 changes: 38 additions & 0 deletions proposals/74:upgrade-15/exit-reclaim.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import test from 'ava';
import { $ } from 'execa';
import { execFileSync } from 'node:child_process';
import { makeAgd, waitForBlock } from '@agoric/synthetic-chain';

const offerId = 'bad-invitation-15'; // cf. prepare.sh
const from = 'gov1';

test('exitOffer tool reclaims stuck payment', async t => {
const showAndExec = (file, args, opts) => {
console.log('$', file, ...args);
return execFileSync(file, args, opts);
};

// @ts-expect-error string is not assignable to Buffer
const agd = makeAgd({ execFileSync: showAndExec }).withOpts({
keyringBackend: 'test',
});

const addr = await agd.lookup(from);
t.log(from, 'addr', addr);

const getBalance = async target => {
const { balances } = await agd.query(['bank', 'balances', addr]);
const { amount } = balances.find(({ denom }) => denom === target);
return Number(amount);
};

const before = await getBalance('uist');
t.log('uist balance before:', before);

await $`node ./exitOffer.js --id ${offerId} --from ${from}`;

await waitForBlock(2);
const after = await getBalance('uist');
t.log('uist balance after:', after);
t.true(after > before);
});
97 changes: 97 additions & 0 deletions proposals/74:upgrade-15/exitOffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Note: limit imports to node modules for portability
import { parseArgs, promisify } from 'node:util';
import { execFile } from 'node:child_process';
import { writeFile, mkdtemp, rm } from 'node:fs/promises';
import { join } from 'node:path';

const options = /** @type {const} */ ({
id: { type: 'string' },
from: { type: 'string' },
bin: { type: 'string', default: '/usr/src/agoric-sdk/node_modules/.bin' },
});

const Usage = `
Try to exit an offer, reclaiming any associated payments.
node exitOffer.js --id ID --from FROM [--bin PATH]
Options:
--id <offer id>
--from <address or key name>
--bin <path to agoric and agd> default: ${options.bin.default}
`;

const badUsage = () => {
const reason = new Error(Usage);
reason.name = 'USAGE';
throw reason;
};

const { stringify: q } = JSON;
// limited to JSON data: no remotables/promises; no undefined.
const toCapData = data => ({ body: `#${q(data)}`, slots: [] });

const { entries } = Object;
/**
* @param {Record<string, string>} obj - e.g. { color: 'blue' }
* @returns {string[]} - e.g. ['--color', 'blue']
*/
const flags = obj =>
entries(obj)
.map(([k, v]) => [`--${k}`, v])
.flat();

const execP = promisify(execFile);

const showAndRun = (file, args) => {
console.log('$', file, ...args);
return execP(file, args);
};

const withTempFile = async (tail, fn) => {
const tmpDir = await mkdtemp('offers-');
const tmpFile = join(tmpDir, tail);
try {
const result = await fn(tmpFile);
return result;
} finally {
await rm(tmpDir, { recursive: true, force: true }).catch(err =>
console.error(err),
);
}
};

const doAction = async (action, from) => {
await withTempFile('offer.json', async tmpOffer => {
await writeFile(tmpOffer, q(toCapData(action)));

const out = await showAndRun('agoric', [
'wallet',
...flags({ 'keyring-backend': 'test' }),
'send',
...flags({ offer: tmpOffer, from }),
]);
return out.stdout;
});
};

const main = async (argv, env) => {
const { values } = parseArgs({ args: argv.slice(2), options });
const { id: offerId, from, bin } = values;
(offerId && from) || badUsage();

env.PATH = `${bin}:${env.PATH}`;
const action = { method: 'tryExitOffer', offerId };
const out = await doAction(action, from);
console.log(out);
};

main(process.argv, process.env).catch(e => {
if (e.name === 'USAGE' || e.code === 'ERR_PARSE_ARGS_UNKNOWN_OPTION') {
console.error(e.message);
} else {
console.error(e);
}
process.exit(1);
});
16 changes: 16 additions & 0 deletions proposals/74:upgrade-15/initial.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import test from 'ava';

import { getVatDetails } from '@agoric/synthetic-chain';

const vats = {
walletFactory: { incarnation: 3 },
zoe: { incarnation: 1 },
};

test(`vat details`, async t => {
await null;
for (const [vatName, expected] of Object.entries(vats)) {
const actual = await getVatDetails(vatName);
t.like(actual, expected, `${vatName} details mismatch`);
}
});
28 changes: 28 additions & 0 deletions proposals/74:upgrade-15/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"agoricProposal": {
"releaseNotes": "https://github.com/Agoric/agoric-sdk/releases/tag/agoric-upgrade-15",
"sdkImageTag": "43",
"planName": "agoric-upgrade-15",
"upgradeInfo": {
"binaries": {
"any": "https://github.com/Agoric/agoric-sdk/archive/734e8635002e01b3e27477e93998dda942c7fae8.zip//agoric-sdk-734e8635002e01b3e27477e93998dda942c7fae8?checksum=sha256:a329dbf9bcaf3a220c262783b0f35c7a15c8f2684151c626f3e0a769f41679bf"
},
"source": "https://github.com/Agoric/agoric-sdk/archive/734e8635002e01b3e27477e93998dda942c7fae8.zip?checksum=sha256:a329dbf9bcaf3a220c262783b0f35c7a15c8f2684151c626f3e0a769f41679bf"
},
"type": "Software Upgrade Proposal"
},
"type": "module",
"license": "Apache-2.0",
"dependencies": {
"@agoric/synthetic-chain": "^0.1.0",
"ava": "^5.3.1"
},
"ava": {
"concurrency": 1,
"serial": true
},
"scripts": {
"agops": "yarn --cwd /usr/src/agoric-sdk/ --silent agops"
},
"packageManager": "yarn@4.1.1"
}
29 changes: 29 additions & 0 deletions proposals/74:upgrade-15/prepare.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

# Exit when any command fails
set -uxeo pipefail

# Place here any actions that should happen before the upgrade is proposed. The
# actions are executed in the previous chain software, and the effects are
# persisted so they can be used in the steps after the upgrade is complete,
# such as in the "use" or "test" steps, or further proposal layers.

printISTBalance() {
addr=$(agd keys show -a "$1" --keyring-backend=test)
agd query bank balances "$addr" -o json \
| jq -c '.balances[] | select(.denom=="uist")'

}

echo TEST: Offer with bad invitation
printISTBalance gov1

badInvitationOffer=$(mktemp)
cat > "$badInvitationOffer" << 'EOF'
{"body":"#{\"method\":\"executeOffer\",\"offer\":{\"id\":\"bad-invitation-15\",\"invitationSpec\":{\"callPipe\":[[\"badMethodName\"]],\"instancePath\":[\"reserve\"],\"source\":\"agoricContract\"},\"proposal\":{\"give\":{\"Collateral\":{\"brand\":\"$0.Alleged: IST brand\",\"value\":\"+15000\"}}}}}","slots":["board0257"]}
EOF

PATH=/usr/src/agoric-sdk/node_modules/.bin:$PATH
agops perf satisfaction --keyring-backend=test send --executeOffer "$badInvitationOffer" --from gov1 || true

printISTBalance gov1
6 changes: 6 additions & 0 deletions proposals/74:upgrade-15/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

# Place here any test that should be executed using the executed proposal.
# The effects of this step are not persisted in further proposal layers.

yarn ava
12 changes: 12 additions & 0 deletions proposals/74:upgrade-15/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"allowJs": true,
"checkJs": true,
"strict": false,
"strictNullChecks": true,
"noImplicitThis": true
}
}
Loading

0 comments on commit 8a5cb08

Please sign in to comment.