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

feat: upgrade walletFactory to go beyond vbank assets #8147

Merged
merged 1 commit into from
Aug 24, 2023
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
5 changes: 3 additions & 2 deletions packages/builders/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@
"@agoric/internal": "^0.3.2",
"@agoric/network": "^0.1.0",
"@agoric/notifier": "^0.6.2",
"@agoric/smart-wallet": "^0.5.3",
"@agoric/swingset-vat": "^0.32.2",
"@agoric/vat-data": "^0.5.2",
"@agoric/vats": "^0.15.1",
"@agoric/zoe": "^0.26.2",
"@endo/marshal": "^0.8.6",
"@endo/bundle-source": "^2.5.2",
"@endo/captp": "^3.1.2",
"@endo/eventual-send": "^0.17.3",
"@endo/init": "^0.5.57",
"@endo/far": "^0.2.19",
"@endo/init": "^0.5.57",
"@endo/marshal": "^0.8.6",
"@endo/promise-kit": "^0.2.57",
"@endo/stream": "^0.3.26",
"import-meta-resolve": "^2.2.1"
Expand Down
34 changes: 34 additions & 0 deletions packages/builders/scripts/smart-wallet/build-game1-start.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @file Proposal Builder: Start Game with non-vbank Place NFT asset
*
* Usage:
* agoric run build-game1-start.js
*/

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').ProposalBuilder} */
export const game1ProposalBuilder = async ({ publishRef, install }) => {
return harden({
sourceSpec: '@agoric/smart-wallet/test/start-game1-proposal.js',
getManifestCall: [
getManifestForGame1.name,
{
game1Ref: publishRef(
install(
'@agoric/smart-wallet/test/gameAssetContract.js',
'../bundles/bundle-game1.js',
{ persist: true },
),
),
},
],
});
};

/** @type {DeployScriptFunction} */
export default async (homeP, endowments) => {
const { writeCoreProposal } = await makeHelpers(homeP, endowments);
await writeCoreProposal('start-game1', game1ProposalBuilder);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @file Proposal Builder: Upgrade walletFactory
*
* Usage:
* agoric run build-walletFactory-upgrade.js
*/

import { makeHelpers } from '@agoric/deploy-script-support';
import { getManifestForUpgrade } from '@agoric/smart-wallet/src/proposals/upgrade-walletFactory-proposal.js';

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').ProposalBuilder} */
export const defaultProposalBuilder = async ({ publishRef, install }) => {
return harden({
sourceSpec:
'@agoric/smart-wallet/src/proposals/upgrade-walletFactory-proposal.js',
getManifestCall: [
getManifestForUpgrade.name,
{
walletFactoryRef: publishRef(
install(
'@agoric/smart-wallet/src/walletFactory.js',
'../bundles/bundle-walletFactory.js',
{ persist: true },
),
),
},
],
});
};

/** @type {DeployScriptFunction} */
export default async (homeP, endowments) => {
const { writeCoreProposal } = await makeHelpers(homeP, endowments);
await writeCoreProposal('upgrade-walletFactory', defaultProposalBuilder);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
upgrade-walletFactory-permit.json
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should we have a global gitignore on -permit.json? if so, should we name them .permit.json to hint that it's a kind of thing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a kind of thing. (There's a static type and could be a pattern). So I'd support renaming all of them together in a separate PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#8249, draft until this one lands

upgrade-walletFactory.js
29 changes: 25 additions & 4 deletions packages/deployment/upgrade-test/upgrade-test-scripts/agoric-upgrade-11/actions.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/bin/bash

. ./upgrade-test-scripts/env_setup.sh
# Dockerfile in upgrade-test sets:
# WORKDIR /usr/src/agoric-sdk/
# Overriding it during development has occasionally been useful.
SDK=${SDK:-/usr/src/agoric-sdk}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please comment what environment provides that source path. Docker? and what wants to override it

. $SDK/upgrade-test-scripts/env_setup.sh

# Enable debugging
set -x

# CWD is agoric-sdk
upgrade11=./upgrade-test-scripts/agoric-upgrade-11

# hacky restore of pruned artifacts
killAgd
EXPORT_DIR=$(mktemp -t -d swing-store-export-upgrade-11-XXX)
Expand Down Expand Up @@ -46,6 +47,26 @@ test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.
test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault3 -o jsonlines | jq -r '.locked.value') "0" "vault3 contains no collateral"
test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault3 -o jsonlines | jq -r '.debtSnapshot.debt.value') "0" "vault3 has no debt"

upgrade11=$SDK/upgrade-test-scripts/agoric-upgrade-11
cd $upgrade11

## build proposal and install bundles
waitForBlock 2
./tools/mint-ist.sh
./wallet-all-ertp/wf-install-bundles.sh

## upgrade wallet factory
./wallet-all-ertp/wf-propose.sh

## start game1
./wallet-all-ertp/wf-game-propose.sh

# Pay 0.25IST join the game and get some places
node ./wallet-all-ertp/gen-game-offer.mjs Shire Mordor >/tmp/,join.json
agops perf satisfaction --from $GOV1ADDR --executeOffer /tmp/,join.json --keyring-backend=test

cd $SDK

######################################################################
# FIXME: remove this line when these tests don't hardcode bundle hashes.
echo 1>&2 "FIXME: skipping zoe-full-upgrade tests"; return 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ waitForBlock 5
# CWD is agoric-sdk
upgrade11=./upgrade-test-scripts/agoric-upgrade-11

test_val "$(agd query vstorage children published.boardAux -o json | jq .children)" "[]" "no boardAux children yet"

# zoe vat is at incarnation 0
test_val "$(yarn --silent node $upgrade11/vat-status.mjs zoe)" "0" "zoe vat incarnation"
test_val "$(yarn --silent node $upgrade11/tools/vat-status.mjs zoe)" "0" "zoe vat incarnation"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remark: probably useful outside upgrade11, but we will refactor in the JS port


# validate agoric-upgrade-10 metrics after update

Expand All @@ -30,4 +32,3 @@ test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.
test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault2 -o jsonlines | jq -r '.vaultState') "closed" "vault2 is closed"
test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault2 -o jsonlines | jq -r '.locked.value') "0" "vault2 contains no collateral"
test_val $(agoric follow -l -F :published.vaultFactory.managers.manager0.vaults.vault2 -o jsonlines | jq -r '.debtSnapshot.debt.value') "0" "vault2 has no debt"

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,48 @@ mv $TMP_GENESIS_DIR/* $HOME/.agoric/config/
startAgd
rm -rf $EXPORT_DIR

testMinChildren() {
path=$1
min=$2
line="$(agd query vstorage children $path -o jsonlines)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What dictates when to use -o json vs. -o jsonlines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dunno. jsonlines is what I saw everywhere else.

ok=$(echo $line | jq ".children | length | . > $min")
test_val "$ok" "true" "$path: more than $min children"
}

# Check brand aux data for more than just vbank assets
testMinChildren published.boardAux 3

testDisplayInfo() {
name=$1
expected=$2

line="$(agoric follow -lF :published.agoricNames.brand -o text)"
# find brand by name, then corresponding slot
id=$(echo $line | jq --arg name "$name" -r '.slots as $slots | .body | gsub("^#";"") | fromjson | .[] | select(.[0] == $name) | .[1] | capture("^[$](?<slot>0|[1-9][0-9]*)") | .slot | $slots[. | tonumber]')
echo $name Id: $id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this intentionally left in without some kind of debugging condition?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All over this PR I waffle about how much logging to do. This is one of the reasons I asked to discuss this with you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it's test code in a framework that hasn't stabilized and everyone is still learning, I think we should bias towards verbosity


line="$(agoric follow -lF :published.boardAux.$id -o jsonlines)"
displayInfo="$(echo $line | jq -c .displayInfo)"
test_val "$displayInfo" "$expected" "$name displayInfo from boardAux"
}

testDisplayInfo IST '{"assetKind":"nat","decimalPlaces":6}'

testPurseValuePayload() {
addr=$1
wkAsset=$2
expected=$3

line="$(agoric follow -lF :published.wallet.$addr.current -o jsonlines)"
# HACK: selecting brand by allegedName
payload=$(echo $line | jq --arg name "$wkAsset" -c '.purses[] | select(.brand | contains($name)) | .balance.value.payload')
test_val "$payload" "$expected" "$wkAsset purse for $addr"
}

# Smart wallet handles game Place assets?
testDisplayInfo Place '{"assetKind":"copyBag"}'
testPurseValuePayload $GOV1ADDR Place '[["Shire","1"],["Mordor","1"]]'

# zoe vat is at incarnation 1
echo "FIXME: bypassed zoe-full-upgrade validation"; return 0
test_val "$(yarn --silent node $upgrade11/vat-status.mjs zoe)" "1" "zoe vat incarnation"
test_val "$(yarn --silent node $upgrade11/tools/vat-status.mjs zoe)" "1" "zoe vat incarnation"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

if [ -z "$GOV1ADDR" ]; then
echo run env_setup.sh to set GOV1ADDR
exit 1
fi

micro=000000

# send some collateral to gov1
agd tx bank send validator $GOV1ADDR 20123$micro${ATOM_DENOM} \
--keyring-backend=test --chain-id=agoriclocal --yes -bblock -o json

export PATH=/usr/src/agoric-sdk/packages/agoric-cli/bin:$PATH
agops vaults open --giveCollateral 5000 --wantMinted 20000 > /tmp/offer.json
agops perf satisfaction --executeOffer /tmp/offer.json --from gov1 --keyring-backend=test
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env node

import fs from 'fs';

const Fail = (template, ...args) => {
throw Error(String.raw(template, ...args.map(val => String(val))));
};

/**
* Parse output of `agoric run proposal-builder.js`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative is to teach agoric run to produce parseable output. This is the 2nd time I didn't opt to do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe someday. For testing purposes I think we'd just add a parse-smart version to upgradeHelper.js once that's available

*
* @param {string} txt
*
* adapted from packages/boot/test/bootstrapTests/supports.js
*/
const parseProposalParts = txt => {
const evals = [
...txt.matchAll(/swingset-core-eval (?<permit>\S+) (?<script>\S+)/g),
].map(m => {
if (!m.groups) throw Fail`Invalid proposal output ${m[0]}`;
const { permit, script } = m.groups;
return { permit, script };
});
evals.length || Fail`No swingset-core-eval found in proposal output: ${txt}`;

const bundles = [...txt.matchAll(/swingset install-bundle @([^\n]+)/gm)].map(
([, bundle]) => bundle,
);
bundles.length || Fail`No bundles found in proposal output: ${txt}`;

return { evals, bundles };
};

const main = (stdin, readFileSync) => {
const input = readFileSync(stdin.fd).toString();
const parts = parseProposalParts(input);
// relies on console.log printing to stdout unmodified
console.log(JSON.stringify(parts));
};

main(process.stdin, fs.readFileSync);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remark: will be totally refactored after #8237

Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/* eslint-disable @jessie.js/safe-await-separator */
/* global process */
import assert from 'assert';
import { execFile } from 'child_process';

const ISTunit = 1_000_000n; // aka displayInfo: { decimalPlaces: 6 }
const CENT = ISTunit / 100n;

const [_node, _script, ...choices] = process.argv;

const toSec = ms => BigInt(Math.round(ms / 1000));

const id = `join-${Date.now()}`;

// look up boardIDs for brands, instances in agoricNames

// poor-man's zx
const $ = cmd => {
console.error(cmd);
const [file, ...args] = cmd.split(' ');

return new Promise((resolve, reject) => {
execFile(file, args, { encoding: 'utf8' }, (err, out) => {
if (err) return reject(err);
resolve(out);
});
});
};

const zip = (xs, ys) => xs.map((x, i) => [x, ys[i]]);
const fromSmallCapsEntries = txt => {
const { body, slots } = JSON.parse(txt);
const theEntries = zip(JSON.parse(body.slice(1)), slots).map(
([[name, ref], boardID]) => {
const iface = ref.replace(/^\$\d+\./, '');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has got poor-man's-smallcaps-decoding mixed in. The smallcaps-related hacks could at least be moved into the const smallCaps = {...} widget.

return [name, { iface, boardID }];
},
);
return Object.fromEntries(theEntries);
};

const wkInstance = fromSmallCapsEntries(
await $('agoric follow -lF :published.agoricNames.instance -o text'),
);
assert(wkInstance.VaultFactory);

const wkBrand = fromSmallCapsEntries(
await $('agoric follow -lF :published.agoricNames.brand -o text'),
);
assert(wkBrand.IST);
assert(wkBrand.Place);

const slots = []; // XXX global mutable state

// XXX should use @endo/marshal
const smallCaps = {
Nat: n => `+${n}`,
replacer: (k, v) =>
typeof v === 'bigint'
? `+${v}`
: typeof v === 'symbol'
? `%${v.description}`
: v,
// XXX mutates obj
ref: obj => {
if (obj.ix) return obj.ix;
const ix = slots.length;
slots.push(obj.boardID);
obj.ix = `$${ix}.Alleged: ${obj.iface}`;
return obj.ix;
},
};

const AmountMath = {
make: (brand, value) => ({
brand: smallCaps.ref(brand),
value: typeof value === 'bigint' ? smallCaps.Nat(value) : value,
}),
};

const makeTagged = (tag, payload) => ({
'#tag': tag,
payload,
});

const makeCopyBag = entries => makeTagged('copyBag', entries);
const want = {
Places: AmountMath.make(
wkBrand.Place,
makeCopyBag(choices.map(name => [name, 1n])),
),
};

const give = { Price: AmountMath.make(wkBrand.IST, 25n * CENT) };
const body = {
method: 'executeOffer',
offer: {
id,
invitationSpec: {
source: 'contract',
instance: smallCaps.ref(wkInstance.game1),
publicInvitationMaker: 'makeJoinInvitation',
},
proposal: { give, want },
},
};

console.error(JSON.stringify(body.offer, smallCaps.replacer, 1));

const capData = {
body: `#${JSON.stringify(body, smallCaps.replacer)}`,
slots,
};
const action = JSON.stringify(capData);

console.log(action);
Loading