Skip to content

Commit

Permalink
boot script (#429)
Browse files Browse the repository at this point in the history
This adds a sort of "boot script" to the `dev` dir. It will jump start
and deploy and fund faucets
it also fixs a bug with registering where we were getting "stale" events
for a previous registration attempt found while writing this script
includes this doc add in the `dev/README.md`:

## sdk "boot script"

For convince at [./deploy-faucets.mjs](./deploy-facuets.mjs ) is a
script we use to "deploy" and fund the faucets for our entropy network
you can refer to this section and the script itself to deploy your own
faucets! Here is it running with a dev environment setup from the root
of this project:

```bash
dev/bin/spin-up.sh four-nodes
```
I would take a deep breath here to allow for the 4 nodes to connect
before running the next command bellow. On that note the deploy faucet
script takes 3 arguments as you can see right now this script assumes
you know what your doing if you are running it. So not a lot of bells
and whitelist here.

the first argument is the `endpoint` to target, the second is the
`fundingSeed` and the third `faucetLookUpSeed` <!--yes seeds()! not
mnemonic go play alone this script will never take a mnemonic maybe one
day i'll make it preterite to use like asci fireworks or something else
integrated with the cli-->

```bash
node dev/deploy-facuets.mjs ws://127.0.0.1:9944 0x786ad0e2df456fe43dd1f91ebca22e235bc162e0bb8d53c633e8c85b2af68b7a 0x20423b5ff4984bcb8922483c98afb7eaa056c40fc431f8a314211e3d94a4222f

```
this example above should run in a dev enviroment the funding seed is
eve and the report looks something like this and will log to your
console:

```
{
  'jump start status at start': 'Ready',
  'using faucet program pointer': '0x3a1d45fecdee990925286ccce71f78693ff2bb27eae62adf8cfb7d3d61e142aa',
  'faucet program pointer from deployment': '0x3a1d45fecdee990925286ccce71f78693ff2bb27eae62adf8cfb7d3d61e142aa',
  'faucet config': {
    max_transfer_amount: 20000000000,
    genesis_hash: 'a4b29c6895ae775fd291377fde31882f66244eaecbdc81e017ebb64d13b27b72'
  },
  'initial balance for funding account': 99999880954644628n,
  'initial funding faucet amount': 24999970238661157n,
  'modifiableKeys on chain': [
    '0x03cd98af667e48b4912c66576f5cdf18aee3764c7aad1c40b9c61d5ac012acf1f6',
    '0x0228aba3e529d3b78b0cd7454a5f694eb09a648ec488b0b4b8ce7cd9abedd96c28',
    '0x03b7c87542f57895d37f1a37a3460e27ec74de7216e6ed48609ffd2fac976ea94a'
  ],
  'faucet look up address': '5EqZMUYz7jjaG2baQWJRzUzM7YhBP4E8TAj6GgqDqWdXriTn',
  faucets: [
    {
      vk: '0x03cd98af667e48b4912c66576f5cdf18aee3764c7aad1c40b9c61d5ac012acf1f6',
      address: '5Gm6JA2ikMK1FfNn3MRmUPLWfi4p6eBzcFtKE1dnJvQpJgpg',
      balance: '24,999,970,238,661,157'
    },
    {
      vk: '0x0228aba3e529d3b78b0cd7454a5f694eb09a648ec488b0b4b8ce7cd9abedd96c28',
      address: '5FqourMb6c3z4rogDnaBb36Ku53ndy3eCiSdjRg2TUAztJ3X',
      balance: '24,999,970,238,661,157'
    },
    {
      vk: '0x03b7c87542f57895d37f1a37a3460e27ec74de7216e6ed48609ffd2fac976ea94a',
      address: '5CUQuSMxTzx74Zb8gsDobhaYSte9vt9a3Db5X6oio4X1pSX1',
      balance: '24,999,970,238,661,157'
    }
  ],
  endpoint: 'ws://127.0.0.1:9944'
}
```
  • Loading branch information
frankiebee authored Nov 6, 2024
2 parents 55ce49a + 2ea1561 commit 5cfbb7c
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 54 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ Version header format: `[version] Name - year-month-day (entropy-core compatibil
### Added

### Fixed

- format error when getting a program not on chain [#429](https://github.com/entropyxyz/sdk/pull/429)
### Changed

### Broke
- registration parmas now matches core language `programDeployer` -> `programModAddress` when [#429](https://github.com/entropyxyz/sdk/pull/429)

### Dev

Expand Down
65 changes: 65 additions & 0 deletions dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,68 @@ yarn
yarn version --patch # patch|minor|major
npm publish
```

## sdk "boot script"


When a new network of nodes is turned on, we need some actions to be taken before this new Entropy network is ready to use for tests.

1. Give the nodes a moment to establish connections
2. run "jump start", which establishes who the initial signing nodes are (the network automatically "reshares" these roles periodically after jump start)
3. set up faucet program
- a) deploy faucet program to network
- b) install the faucet program for some faucet accounts
- c) fund the faucet accounts

For convenience, at [./deploy-faucets.mjs](./deploy-faucets.mjs ) is a script we use to "deploy" and fund the faucets for our entropy network. You can refer to this section of the README and the script itself to deploy your own faucets! Here it is running with a dev environment setup from the root of this project:

```bash
dev/bin/spin-up.sh four-nodes
```
I would take a deep breath here to allow for the 4 nodes to connect before running the next command bellow. On that note the deploy faucet script takes 3 arguments as you can see right now this script assumes you know what your doing if you are running it. So not a lot of bells and whitelist here.

the first argument is the `endpoint` to target, the second is the `fundingSeed` and the third `faucetLookUpSeed` <!--yes seeds()! not mnemonic go play alone this script will never take a mnemonic maybe one day i'll make it preterite to use like asci fireworks or something else integrated with the cli-->

```bash
node dev/deploy-faucets.mjs ws://127.0.0.1:9944 0x786ad0e2df456fe43dd1f91ebca22e235bc162e0bb8d53c633e8c85b2af68b7a 0x20423b5ff4984bcb8922483c98afb7eaa056c40fc431f8a314211e3d94a4222f

```
this example above should run in a dev enviroment the funding seed is eve and the report looks something like this and will log to your console:

```
{
'jump start status at start': 'Ready',
'using faucet program pointer': '0x3a1d45fecdee990925286ccce71f78693ff2bb27eae62adf8cfb7d3d61e142aa',
'faucet program pointer from deployment': '0x3a1d45fecdee990925286ccce71f78693ff2bb27eae62adf8cfb7d3d61e142aa',
'faucet config': {
max_transfer_amount: 20000000000,
genesis_hash: 'a4b29c6895ae775fd291377fde31882f66244eaecbdc81e017ebb64d13b27b72'
},
'initial balance for funding account': 99999880954644628n,
'initial funding faucet amount': 24999970238661157n,
'modifiableKeys on chain': [
'0x03cd98af667e48b4912c66576f5cdf18aee3764c7aad1c40b9c61d5ac012acf1f6',
'0x0228aba3e529d3b78b0cd7454a5f694eb09a648ec488b0b4b8ce7cd9abedd96c28',
'0x03b7c87542f57895d37f1a37a3460e27ec74de7216e6ed48609ffd2fac976ea94a'
],
'faucet look up address': '5EqZMUYz7jjaG2baQWJRzUzM7YhBP4E8TAj6GgqDqWdXriTn',
faucets: [
{
vk: '0x03cd98af667e48b4912c66576f5cdf18aee3764c7aad1c40b9c61d5ac012acf1f6',
address: '5Gm6JA2ikMK1FfNn3MRmUPLWfi4p6eBzcFtKE1dnJvQpJgpg',
balance: '24,999,970,238,661,157'
},
{
vk: '0x0228aba3e529d3b78b0cd7454a5f694eb09a648ec488b0b4b8ce7cd9abedd96c28',
address: '5FqourMb6c3z4rogDnaBb36Ku53ndy3eCiSdjRg2TUAztJ3X',
balance: '24,999,970,238,661,157'
},
{
vk: '0x03b7c87542f57895d37f1a37a3460e27ec74de7216e6ed48609ffd2fac976ea94a',
address: '5CUQuSMxTzx74Zb8gsDobhaYSte9vt9a3Db5X6oio4X1pSX1',
balance: '24,999,970,238,661,157'
}
],
endpoint: 'ws://127.0.0.1:9944'
}
```
204 changes: 204 additions & 0 deletions dev/deploy-faucets.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import { readFileSync } from 'fs'
import { blake2AsHex, encodeAddress } from "@polkadot/util-crypto";
import Keyring from '@entropyxyz/sdk/keys'
import Entropy, { wasmGlobalsReady } from '@entropyxyz/sdk'
import { jumpStartNetwork, createTimeLogProxy } from '@entropyxyz/sdk/testing'
import { evilMonkeyAnimation } from './fun-bucket.mjs'

const endpoint = process.argv[2]
const fundingSeed = process.argv[3]
const faucetLookUpSeed = process.argv[4]



// change this number to deploy more faucets
const FAUCET_COUNT = 3
const BITS_PER_TOKEN = 1e10
// change me if you change the schemas!
const POINTER = '0x3a1d45fecdee990925286ccce71f78693ff2bb27eae62adf8cfb7d3d61e142aa'


if (!endpoint) throw new Error('please provide arguments for endpoint, fundingSeed, faucetLookUpSeed')
if (!fundingSeed) throw new Error('please provide arguments for fundingSeed, faucetLookUpSeed')
if (!faucetLookUpSeed) throw new Error('please provide arguments for faucetLookUpSeed')
// this is just a novel reporter object that gets logged
const report = createTimeLogProxy({ endpoint })
// run checks
checkEndpoint(endpoint)
checkSeed(faucetLookUpSeed)
checkSeed(fundingSeed)

const faucetAddresses = []
// actually run the function!
deployAndFundFaucet().then(() => process.exit(0)).catch((e) => {
console.warn(report)
console.error(e)
process.exit(1)
})
// function defined
async function deployAndFundFaucet () {
let monkeyAnimationStop = evilMonkeyAnimation()
report.step = 'about to wait wasmGlobalsReady'
await wasmGlobalsReady()
report.step = 'completed waiting for wasmGlobalsReady'
report.step = 'creating fundingSeed keyring'
const moneyRing = new Keyring({
seed: fundingSeed
})
report.step = 'created keyring for fundingSeed'
report.step = 'creating faucetLookUpSeed keyring'
const faucetRing = new Keyring({
seed: faucetLookUpSeed
})
report.step = 'creating entropy for fundingSeed'
const moneyBags = new Entropy({
endpoint,
keyring: moneyRing
})
report.step = 'created entropy for fundingSeed'
report.step = 'creating entropy for faucetRing'
const faucetEntropy = new Entropy({
endpoint,
keyring: faucetRing
})
report.step = 'created entropy for faucetRing'
report.step = 'awaiting readys'
await faucetEntropy.ready
await moneyBags.ready
report.step = 'entropys ready'
report.step = 'getting jump start status'
const jumpStartStatus = (await moneyBags.substrate.query.stakingExtension.jumpStartProgress()).toHuman().jumpStartStatus
report.step = 'jump start status retrieved'
report['jump start status at start'] = jumpStartStatus
// deploy faucet program to chain if not already up
if (jumpStartStatus === 'Ready') {
report.step = 'starting jump start'
await jumpStartNetwork(moneyBags, true)
report.step = 'finished jump start'
monkeyAnimationStop()
monkeyAnimationStop = evilMonkeyAnimation()
}
report.step = 'getting faucet program on chain'
const faucetProgramInfo = await moneyBags.programs.dev.get(POINTER)
report.step = 'got faucet program on chain'
report['using faucet program POINTER'] = POINTER
if (faucetProgramInfo === null) {
const faucetProgram = readFileSync(new URL('./faucet_program.wasm', import.meta.url))
const configurationSchema = {
type: 'object',
properties: {
max_transfer_amount: { type: "number" },
genesis_hash: { type: "string" }
}
}
const auxDataSchema = {
type: 'object',
properties: {
amount: { type: "number" },
string_account_id: { type: "string" },
spec_version: { type: "number" },
transaction_version: { type: "number" },
}
}
report.step = 'deploying faucet program'
report['faucet program POINTER from deployment'] = await moneyBags.programs.dev.deploy(faucetProgram, configurationSchema, auxDataSchema)
report.step = 'deployed faucet program'
}
// transfer funds to faucet account "enough" to register (5 whole tokens)
report.step = 'transferring funds to faucet look up address from funding account'
await sendMoney(moneyBags, faucetRing.accounts.registration.address, BigInt(FAUCET_COUNT * BITS_PER_TOKEN))
report.step = 'finish transfer'
let faucetCountDown = FAUCET_COUNT
const genesisHash = await moneyBags.substrate.rpc.chain.getBlockHash(0)
const userConfig = {
max_transfer_amount: 20_000_000_000,
genesis_hash: genesisHash.toString().split('0x')[1]
}
report['faucet config'] = userConfig
const faucets = []
report.step = 'retrieving balance for funding account'
const funderBalance = BigInt((await faucetEntropy.substrate.query.system.account(
moneyRing.accounts.registration.address)).data.free)
report.step = 'balance for funding account'
report['initial balance for funding account'] = funderBalance.toLocaleString()
// dont transfer all funds ¯\_(ツ)_/¯ so if we run out of faucet funds you still have a small nest egg
const fundingAmount = funderBalance / BigInt(FAUCET_COUNT + 1)
report['initial funding faucet amount'] = fundingAmount.toLocaleString()

while (!!faucetCountDown) {
report.step = 'registering a faucet'
const vk = await faucetEntropy.register({
programModAddress: faucetEntropy.keyring.accounts.registration.address,
programData: [{
program_pointer: POINTER,
program_config: userConfig,
}]
})
report.step = 'registration complete'
const hashedKey = blake2AsHex(vk)
const faucetAddress = encodeAddress(hashedKey, 42).toString()
report.step = 'transferring funds to faucet address from funding account'
await sendMoney(moneyBags, faucetAddress, fundingAmount)
report.step = 'transfer complete'
report.step = 'retrieving balance for new faucet'
const balance = (await faucetEntropy.substrate.query.system.account(
faucetAddress)).data.toHuman()
report.step = 'balance for new faucet retrieved'

faucets.push({
'verification key': vk,
address: faucetAddress,
balance: balance.free.toLocaleString()
})
report['faucets'] = faucets
--faucetCountDown
}
report.step = 'getting modifiableKeys from chain for sanity check'
// These should be the same as faucets.map(faucet => faucet['verification key'])
const modifiableKeys = await moneyBags.substrate.query.registry.modifiableKeys(faucetRing.accounts.registration.address)
report.step = 'retrieved modifiableKeys from chain for sanity check'
report['modifiableKeys on chain'] = modifiableKeys.toHuman()
report['faucet look up address'] = faucetRing.accounts.registration.address
report.finished = true
monkeyAnimationStop()
console.log(report)
}

function sendMoney(entropy, recipientAddress, amount) {
return new Promise(async (resolve, reject) => {
// WARN: await signAndSend is dangerous as it does not resolve
// after transaction is complete :melt:
const sender = entropy.keyring.accounts.registration.pair
entropy.substrate.tx.balances
.transferAllowDeath(recipientAddress, amount)
.signAndSend(sender, ({ status, events, dispatchError }) => {
if (dispatchError) {
let msg
if (dispatchError.isModule) {
// for module errors, we have the section indexed, lookup
const decoded = entropy.substrate.registry.findMetaError(
dispatchError.asModule
)
const { docs, name, section } = decoded

msg = `${section}.${name}: ${docs.join(' ')}`
} else {
// Other, CannotLookup, BadOrigin, no extra info
msg = dispatchError.toString()
}
return reject(Error(msg))
}

if (status.isFinalized) resolve(status)
})
})
}


function checkSeed(seed) {
if (seed.length !== 66) throw new Error('incompatible seed')
}

function checkEndpoint (endpoint) {
if (!endpoint.startsWith('ws')) throw new Error('Please provide a ws endpoint')
}
Binary file added dev/faucet_program.wasm
Binary file not shown.
20 changes: 20 additions & 0 deletions dev/fun-bucket.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const monkeys = ['🙉 - pandemonium', '🙈 - chaos', '🙊 - anarchy', '🐵 - entropy']
/**
* starts a monkey animation
* @returns {function} to stop animation
**/
export function evilMonkeyAnimation () {
const clear = () => process.stdout.write("\r\x1b[K")
let frame = 0
process.stdout.write(monkeys[frame])
++frame
const animate = setInterval(() => {
clear()
process.stdout.write(monkeys[frame])
if (frame === 3) frame = 0
else ++frame
}, 1000)
return () => {
clearInterval(animate)
}
}
17 changes: 17 additions & 0 deletions dev/testing-utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,20 @@ export async function spinNetworkDown (networkType = 'four-nodes') {
return Promise.reject(err)
}
}

export function createTimeLogProxy (extraStartData={}) {
let lastStepTime
let steps = 0
return new Proxy({ time: { start: (lastStepTime = Date.now()) }, ...extraStartData }, {
set: (o, k, v) => {
const now = Date.now()
if (k === 'finished') o.time['total time in seconds'] = (Date.now() - o.time.start)/1000
else if (k === 'step') {
o.time[`${steps} - ${v}`] = `${(now - lastStepTime)/1000}s`
++steps
lastStepTime = now
}
return o[k] = v
}
})
}
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ export default class Entropy {
* Registers a new account with the provided parameters.
*
* @param {RegistrationParams} params - The registration parameters.
* @param {SS58Address} [params.programDeployer] - The account authorized to modify programs on behalf of the user.
* @param {SS58Address} [params.programModAddress] - The account authorized to modify programs on behalf of the user.
* @param {ProgramInstance[]} [params.programData] - Optional initial programs associated with the user.
* @returns {Promise<HexString>} A promise that resolves to the verifying key for the new account when the registration is complete.
* @throws {Error} If the address is already registered or if there's a problem during registration.
*/
async register (params?: RegistrationParams): Promise<HexString> {
params = params || this.#getRegisterParamsDefault()
if (params.programDeployer && !isDeployer(params.programDeployer)) {
if (params.programModAddress && !isDeployer(params.programModAddress)) {
throw new TypeError('Incompatible address type')
}

Expand Down Expand Up @@ -165,7 +165,7 @@ export default class Entropy {

return {
programData: [defaultProgram],
programDeployer: this.keyring.accounts.registration.address,
programModAddress: this.keyring.accounts.registration.address,
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/programs/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default class ProgramDev extends ExtrinsicBaseClass {
const responseOption = await this.substrate.query.programs.programs(pointer)

const programInfo = responseOption.toJSON()

if (programInfo === null) return null
return this.#formatProgramInterface(programInfo)
}

Expand Down
Loading

0 comments on commit 5cfbb7c

Please sign in to comment.