dump.mjs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 binaries = [
  18. ...programs.map((program) => `${program}.so`),
  19. ...accounts.map((account) => `${account}.json`),
  20. ].flat();
  21. if (binaries.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. binaries.map(async (binary) => {
  28. const address = binaries.split('.')[0];
  29. const hasBinary = await fs.exists(`${outputDir}/${binary}`);
  30. if (!hasBinary) {
  31. await copyFromChain(address, binary);
  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, `onchain-${binary}`);
  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, binary) {
  75. switch (binary.split('.').pop()) {
  76. case 'json':
  77. return $`solana account -u ${rpc} ${address} -o ${outputDir}/${binary} --output json >/dev/null`.quiet();
  78. case 'so':
  79. return $`solana program dump -u ${rpc} ${address} ${outputDir}/${binary} >/dev/null`.quiet();
  80. default:
  81. echo(chalk.red(`[ ERROR ] unknown account type for '${binary}'`));
  82. await $`exit 1`;
  83. }
  84. }