dump.mjs 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #!/usr/bin/env zx
  2. import 'zx/globals';
  3. import {
  4. getExternalAccountAddresses,
  5. getExternalProgramAddresses,
  6. getExternalProgramOutputDir,
  7. } from '../utils.mjs';
  8. // Get input from environment variables.
  9. const rpc = process.env.RPC ?? 'https://api.mainnet-beta.solana.com';
  10. const outputDir = getExternalProgramOutputDir();
  11. await dump();
  12. /** Dump external programs binaries and accounts if needed. */
  13. async function dump() {
  14. // Ensure we have some external accounts to dump.
  15. const programs = getExternalProgramAddresses();
  16. const accounts = getExternalAccountAddresses();
  17. const external = [
  18. ...programs.map((program) => [program, 'so']),
  19. ...accounts.map((account) => [account, 'json']),
  20. ];
  21. if (external.length === 0) return;
  22. echo(`Dumping external accounts to '${outputDir}':`);
  23. // Create the output directory if needed.
  24. $`mkdir -p ${outputDir}`.quiet();
  25. // Copy the binaries from the chain or warn if they are different.
  26. await Promise.all(
  27. external.map(async (address, extension) => {
  28. const binary = `${address}.${extension}`;
  29. const hasBinary = await fs.exists(`${outputDir}/${binary}`);
  30. if (!hasBinary) {
  31. await copyFromChain(address, extension);
  32. echo(`Wrote account data to ${outputDir}/${binary}`);
  33. return;
  34. }
  35. let sha = 'sha256sum';
  36. let options = [];
  37. let hasShaChecksum = await which('sha256sum', { nothrow: true });
  38. // We might not have sha256sum on some systems, so we try shasum as well.
  39. if (!hasShaChecksum) {
  40. hasShaChecksum = await which('shasum', { nothrow: true });
  41. if (hasShaChecksum) {
  42. sha = 'shasum';
  43. options = ['-a', '256'];
  44. }
  45. }
  46. if (hasShaChecksum) {
  47. await copyFromChain(address, extension, 'onchain-');
  48. const [onChainHash, localHash] = await Promise.all([
  49. $`${sha} ${options} -b ${outputDir}/onchain-${binary} | cut -d ' ' -f 1`.quiet(),
  50. $`${sha} ${options} -b ${outputDir}/${binary} | cut -d ' ' -f 1`.quiet(),
  51. ]);
  52. if (onChainHash.toString() !== localHash.toString()) {
  53. echo(
  54. chalk.yellow('[ WARNING ]'),
  55. `on-chain and local binaries are different for '${binary}'`
  56. );
  57. } else {
  58. echo(
  59. chalk.green('[ SKIPPED ]'),
  60. `on-chain and local binaries are the same for '${binary}'`
  61. );
  62. }
  63. await $`rm ${outputDir}/onchain-${binary}`.quiet();
  64. } else {
  65. echo(
  66. chalk.yellow('[ WARNING ]'),
  67. `skipped check for '${binary}' (missing 'sha256sum' command)`
  68. );
  69. }
  70. })
  71. );
  72. }
  73. /** Helper function to copy external programs or accounts binaries from the chain. */
  74. async function copyFromChain(address, extension, prefix = '') {
  75. const binary = `${prefix}${address}.${extension}`;
  76. switch (extension) {
  77. case 'json':
  78. return $`solana account -u ${rpc} ${address} -o ${outputDir}/${binary} --output json >/dev/null`.quiet();
  79. case 'so':
  80. return $`solana program dump -u ${rpc} ${address} ${outputDir}/${binary} >/dev/null`.quiet();
  81. default:
  82. echo(chalk.red(`[ ERROR ] unknown account type for '${binary}'`));
  83. await $`exit 1`;
  84. }
  85. }