From e6f6aeb6ed64ccf5608cbe6e26fd429283ab8a2e Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Tue, 28 Jul 2020 15:34:04 -0600 Subject: [PATCH] feat(cosmic-swingset): add attenuated vattp to fake chain clients --- packages/cosmic-swingset/Makefile | 9 +- .../cosmic-swingset/lib/ag-solo/fake-chain.js | 6 +- .../lib/ag-solo/vats/bootstrap.js | 153 ++++++++---------- 3 files changed, 78 insertions(+), 90 deletions(-) diff --git a/packages/cosmic-swingset/Makefile b/packages/cosmic-swingset/Makefile index 692bc6dfd61..29de954369c 100644 --- a/packages/cosmic-swingset/Makefile +++ b/packages/cosmic-swingset/Makefile @@ -94,9 +94,16 @@ scenario2-run-chain: $(AGC) `$(BREAK_CHAIN) && echo --inspect-brk` --home=t1/n0 start --pruning=nothing # Provision and start a client. -scenario2-run-client: t1-provision-one t1-start-ag-solo +scenario2-run-client: t1-provision-one-with-powers t1-start-ag-solo # Provision the ag-solo from an provisionpass-holding address (idempotent). +t1-provision-one-with-powers: + addr=$$(cat t1/$(BASE_PORT)/ag-cosmos-helper-address); \ + $(AGCH) --home=t1/bootstrap query swingset egress $$addr --chain-id=$(CHAIN_ID) || \ + $(AGCH) --home=t1/bootstrap tx swingset provision-one --keyring-backend=test --from=bootstrap \ + --gas=auto --gas-adjustment=1.3 --broadcast-mode=block --yes --chain-id=$(CHAIN_ID) \ + t1/$(BASE_PORT) $$addr agoric.vattp.makeNetworkHost | tee /dev/stderr | grep -q 'code: 0' + t1-provision-one: addr=$$(cat t1/$(BASE_PORT)/ag-cosmos-helper-address); \ $(AGCH) --home=t1/bootstrap query swingset egress $$addr --chain-id=$(CHAIN_ID) || \ diff --git a/packages/cosmic-swingset/lib/ag-solo/fake-chain.js b/packages/cosmic-swingset/lib/ag-solo/fake-chain.js index 25f2446480e..18f35705431 100644 --- a/packages/cosmic-swingset/lib/ag-solo/fake-chain.js +++ b/packages/cosmic-swingset/lib/ag-solo/fake-chain.js @@ -40,7 +40,11 @@ export async function connectToFakeChain(basedir, GCI, role, delay, inbound) { const mailboxStorage = await readMap(mailboxFile); const vatsdir = path.join(basedir, 'vats'); - const argv = [`--role=${role}`, bootAddress]; + const argv = [ + `--role=${role}`, + `--give-me-all-the-agoric-powers`, + bootAddress, + ]; const stateDBdir = path.join(basedir, `fake-chain-${GCI}-state`); function doOutboundBridge(dstID, _obj) { // console.error('received', dstID, obj); diff --git a/packages/cosmic-swingset/lib/ag-solo/vats/bootstrap.js b/packages/cosmic-swingset/lib/ag-solo/vats/bootstrap.js index c4ad22be932..2daa5aee17c 100644 --- a/packages/cosmic-swingset/lib/ag-solo/vats/bootstrap.js +++ b/packages/cosmic-swingset/lib/ag-solo/vats/bootstrap.js @@ -14,19 +14,13 @@ import { makeBridgeManager } from './bridge'; const NUM_IBC_PORTS = 3; -// The old way of provisioning used an environment variable that -// was an account ACL. The new way uses "provisionpass", a -// "bearer token" that is checked in handler.go before a provision -// transaction is even sent to the JS side. -const FIXME_DEPRECATED_BOOT_ADDRESS = true; - console.debug(`loading bootstrap.js`); function parseArgs(argv) { let ROLE; let gotRoles = false; - let bootAddress; - const additionalAddresses = []; + const hardcodedClientAddresses = []; + let giveMeAllTheAgoricPowers = false; argv.forEach(arg => { const match = arg.match(/^--role=(.*)$/); if (match) { @@ -35,24 +29,22 @@ function parseArgs(argv) { } [, ROLE] = match; gotRoles = true; - } else if (!arg.match(/^-/)) { - if (!bootAddress) { - bootAddress = arg; - } else { - additionalAddresses.push(arg); - } + } else if (arg === `--give-me-all-the-agoric-powers`) { + console.warn(`Giving all the Agoric powers to the client!`); + giveMeAllTheAgoricPowers = true; + } else if (arg.match(/^-/)) { + throw Error(`Unrecognized option ${arg}`); + } else { + hardcodedClientAddresses.push(arg); } }); if (!gotRoles) { ROLE = 'three_client'; } - return [ROLE, bootAddress, additionalAddresses]; + return { ROLE, giveMeAllTheAgoricPowers, hardcodedClientAddresses }; } -// Used in scenario 1 for coordinating on an index for registering public keys -// while requesting provisioning. -const KEY_REG_INDEX = 1; // Used for coordinating on an index in comms for the provisioning service const PROVISIONER_INDEX = 1; @@ -75,7 +67,12 @@ export function buildRootObject(vatPowers) { } // Make services that are provided on the real or virtual chain side - async function makeChainBundler(vats, timerDevice, vatAdminSvc) { + async function makeChainBundler( + vats, + timerDevice, + vatAdminSvc, + giveMeAllTheAgoricPowers = false, + ) { // Create singleton instances. const [ sharingService, @@ -112,7 +109,7 @@ export function buildRootObject(vatPowers) { ); return harden({ - async createUserBundle(_nickname) { + async createUserBundle(_nickname, powerFlags = []) { // Bind to some fresh ports (unspecified name) on the IBC implementation // and provide them for the user to have. const ibcport = []; @@ -120,7 +117,23 @@ export function buildRootObject(vatPowers) { // eslint-disable-next-line no-await-in-loop ibcport.push(await E(vats.network).bind('/ibc-port/')); } + + const additionalPowers = {}; + const { vattp, comms } = vats; + if ( + giveMeAllTheAgoricPowers || + powerFlags.includes('agoric.vattp.makeNetworkHost') + ) { + // Give the authority to create a new host for vattp to share objects with. + additionalPowers.vattp = { + makeNetworkHost(allegedName) { + return E(vattp).makeNetworkHost(allegedName, comms); + }, + }; + } + const bundle = harden({ + ...additionalPowers, chainTimerService, sharingService, contractHost, @@ -287,7 +300,11 @@ export function buildRootObject(vatPowers) { async bootstrap(argv, vats, devices) { const bridgeManager = devices.bridge && makeBridgeManager(E, D, devices.bridge); - const [ROLE, bootAddress, additionalAddresses] = parseArgs(argv); + const { + ROLE, + giveMeAllTheAgoricPowers, + hardcodedClientAddresses, + } = parseArgs(argv); async function addRemote(addr) { const { transmitter, setReceiver } = await E(vats.vattp).addRemote( @@ -298,12 +315,6 @@ export function buildRootObject(vatPowers) { D(devices.mailbox).registerInboundHandler(vats.vattp); await E(vats.vattp).registerMailboxDevice(devices.mailbox); - if (FIXME_DEPRECATED_BOOT_ADDRESS && bootAddress) { - // FIXME: The old way: register egresses for the addresses. - await Promise.all( - [bootAddress, ...additionalAddresses].map(addr => addRemote(addr)), - ); - } const vatAdminSvc = await E(vats.vatAdmin).createVatAdminService( devices.vatAdmin, @@ -315,6 +326,7 @@ export function buildRootObject(vatPowers) { // client (python) on localhost, which creates client solo node on // localhost, with HTML frontend. Multi-player mode. switch (ROLE) { + // REAL VALIDATORS run this. case 'chain': case 'one_chain': { // provisioning vat can ask the demo server for bundles, and can @@ -327,56 +339,9 @@ export function buildRootObject(vatPowers) { // Must occur after makeChainBundler. await registerNetworkProtocols(vats, bridgeManager); - - if (FIXME_DEPRECATED_BOOT_ADDRESS && bootAddress) { - // accept provisioning requests from the controller - const provisioner = harden({ - pleaseProvision(nickname, pubkey) { - console.debug('Provisioning', nickname, pubkey); - return E(vats.provisioning).pleaseProvision( - nickname, - pubkey, - PROVISIONER_INDEX, - ); - }, - }); - // bootAddress holds the pubkey of controller - await E(vats.comms).addEgress( - bootAddress, - KEY_REG_INDEX, - provisioner, - ); - } - break; - } - case 'controller': - case 'one_controller': { - if (!GCI) { - throw new Error(`controller must be given GCI`); - } - - await registerNetworkProtocols(vats, bridgeManager); - - // Wire up the http server. - await setupCommandDevice(vats.http, devices.command, { - controller: true, - }); - // Create a presence for the on-chain provisioner. - await addRemote(GCI); - const chainProvisioner = await E(vats.comms).addIngress( - GCI, - KEY_REG_INDEX, - ); - // Allow web requests from the provisioning server to call our - // provisioner object. - const provisioner = harden({ - pleaseProvision(nickname, pubkey) { - return E(chainProvisioner).pleaseProvision(nickname, pubkey); - }, - }); - await E(vats.http).setProvisioner(provisioner); break; } + // ag-setup-solo runs this. case 'client': case 'one_client': { if (!GCI) { @@ -421,6 +386,7 @@ export function buildRootObject(vatPowers) { vats, devices.timer, vatAdminSvc, + giveMeAllTheAgoricPowers, ); // Allow manual provisioning requests via `agoric cosmos`. @@ -431,19 +397,30 @@ export function buildRootObject(vatPowers) { ); await registerNetworkProtocols(vats, bridgeManager); - if (FIXME_DEPRECATED_BOOT_ADDRESS && bootAddress) { - const demoProvider = harden({ - // build a chain-side bundle for a client. - async getDemoBundle(nickname) { - return chainBundler.createUserBundle(nickname); - }, - }); - await Promise.all( - [bootAddress, ...additionalAddresses].map(addr => - E(vats.comms).addEgress(addr, PROVISIONER_INDEX, demoProvider), - ), - ); - } + + // Allow some hardcoded client address connections into the chain. + // This is necessary for fake-chain, which does not have Cosmos SDK + // transactions to provision its client. + const demoProvider = harden({ + // build a chain-side bundle for a client. + async getDemoBundle(nickname) { + return chainBundler.createUserBundle(nickname); + }, + }); + await Promise.all( + hardcodedClientAddresses.map(async addr => { + const { transmitter, setReceiver } = await E( + vats.vattp, + ).addRemote(addr); + await E(vats.comms).addRemote(addr, transmitter, setReceiver); + await E(vats.comms).addEgress( + addr, + PROVISIONER_INDEX, + demoProvider, + ); + }), + ); + break; } case 'two_client': {