Skip to content

Commit

Permalink
Merge pull request #1628 from spacemeshos/fix-cli-tools
Browse files Browse the repository at this point in the history
Fix CLI tools
  • Loading branch information
brusherru authored Jan 5, 2024
2 parents af71c39 + c5a56d3 commit 97c6f3e
Show file tree
Hide file tree
Showing 15 changed files with 125 additions and 63 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,24 @@ Additionally:
Where `{GENESIS_ID}` is first 8 chars from the HexString. Eg `7c8cef2b`

- Check if the incoming connections aren’t blocked for go-spacemesh

## CLI-tools
These tools are created for debugging and development purposes.
They are not supposed to be used in the production (on real and valuable data).
So use it at your own risk.

### `yarn script:composeTx`
Compose the transaction (and sign if needed).

### `yarn script:decomposeTx`
Decompose the transaction (byte array) to the human-readable structure (JSON)

### `yarn script:readSecrets`
Read secrets from the wallet file.
For example, if you need to export private keys or mnemonics.

### `yarn script:addViewAccount`
Add a public key to the wallet file.
It makes it possible to track someone else transactions and rewards.
Pay attention that Smapp does not fully support such kinds of accounts.
So in case you try to sign a message or publish a transaction — unhandled exceptions will occur.
3 changes: 2 additions & 1 deletion desktop/NodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import NodeService, {
StatusStreamHandler,
} from './NodeService';
import SmesherManager from './SmesherManager';
import { createDebouncePool, getSpawnErrorReason, isEmptyDir } from './utils';
import { createDebouncePool, getSpawnErrorReason } from './utils';
import { isEmptyDir } from './fsUtils';
import { NODE_CONFIG_FILE } from './main/constants';
import {
DEFAULT_GRPC_PRIVATE_PORT,
Expand Down
2 changes: 1 addition & 1 deletion desktop/SmesherMetadataUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
isFileExists,
readFileAsync,
writeFileAsync,
} from './utils';
} from './fsUtils';

interface SmesherMetadata {
smeshingStart?: number;
Expand Down
26 changes: 26 additions & 0 deletions desktop/fsUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import util from 'util';
import fs from 'fs';
import { F_OK } from 'constants';

export const readFileAsync = util.promisify(fs.readFile);

export const writeFileAsync = util.promisify(fs.writeFile);
export const deleteFileAsync = util.promisify(fs.unlink);

export const isFileExists = (filePath: string) =>
fs.promises
.access(filePath, F_OK)
.then(() => true)
.catch(() => false);

export const isEmptyDir = async (path: string) => {
try {
const fsp = fs.promises;
const directory = await fsp.opendir(path);
const entry = await directory.read();
await directory.close();
return entry === null;
} catch (error) {
return false;
}
};
11 changes: 1 addition & 10 deletions desktop/main/Networks.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import { hash } from '@spacemesh/sm-codec';
import { app } from 'electron';
import { Network, NodeConfig, PublicService } from '../../shared/types';
import { toHexString } from '../../shared/utils';
import { generateGenesisID } from '../../shared/utils';
import { getStandaloneNetwork, isTestMode } from '../testMode';
import { fetchJSON, patchQueryString } from '../utils';
import { getEnvInfo } from '../envinfo';
import { isDevNet } from '../envModes';
import { toPublicService } from './utils';

//
// Assertions
//

export const generateGenesisID = (genesisTime: string, extraData: string) => {
return `${toHexString(hash(genesisTime + extraData)).substring(0, 40)}`;
};

export const generateGenesisIDFromConfig = (nodeConfig: NodeConfig) => {
if (
nodeConfig?.genesis?.['genesis-time'] ||
Expand Down
3 changes: 2 additions & 1 deletion desktop/main/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ import {
listWallets,
loadRawWallet,
loadRawWallets,
getWalletFileName,
} from './walletFile';
import { getLocalNodeConnectionConfig, getWalletFileName } from './utils';
import { getLocalNodeConnectionConfig } from './utils';
import sendPromptToRenderer from './sendPromptToRenderer';

const list = async () => {
Expand Down
6 changes: 1 addition & 5 deletions desktop/main/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import readFromBottom from 'fs-reverse';
import { app, BrowserWindow, Notification } from 'electron';
import { isFileExists } from '../utils';
import { isFileExists } from '../fsUtils';
import { PublicService, SocketAddress } from '../../shared/types';
import { USERDATA_DIR } from './constants';

Expand Down Expand Up @@ -114,7 +114,3 @@ export const toPublicService = (
name: netName,
...toSocketAddress(url),
});

// to lower case and replace spaces with underscores
export const getWalletFileName = (walletName: string) =>
walletName.toLowerCase().replaceAll(/\s/g, '_');
7 changes: 5 additions & 2 deletions desktop/main/walletFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ import {
KDF_ITERATIONS,
} from '../aes-gcm';
import FileEncryptionService from '../fileEncryptionService'; // TODO: Remove it in next release
import { isFileExists } from '../utils';
import { isFileExists } from '../fsUtils';
import { getISODate } from '../../shared/datetime';
import { getWalletFileName } from './utils';

export const WRONG_PASSWORD_MESSAGE = 'Wrong password';

Expand All @@ -65,6 +64,9 @@ export const defaultizeWalletSecrets = (
...secrets,
});

export const getWalletFileName = (walletName: string) =>
walletName.toLowerCase().replaceAll(/\s/g, '_');

//
// Encryption
//
Expand Down Expand Up @@ -319,3 +321,4 @@ export const listWallets = async (
...(await listWalletsInDirectory(walletsDir)),
]);
};
// to lower case and replace spaces with underscores
30 changes: 0 additions & 30 deletions desktop/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import util from 'util';
import fs from 'fs';
import { F_OK } from 'constants';
import cs from 'checksum';
import electronFetch, { RequestInit } from 'electron-fetch';
import { NodeConfig } from '../shared/types';
Expand Down Expand Up @@ -73,33 +70,6 @@ export const isNetError = (error: Error) => error.message.startsWith('net::');

export const isByteArray = (a: any): a is Uint8Array => a instanceof Uint8Array;

// --------------------------------------------------------
// FS Utils
// --------------------------------------------------------

export const readFileAsync = util.promisify(fs.readFile);

export const writeFileAsync = util.promisify(fs.writeFile);
export const deleteFileAsync = util.promisify(fs.unlink);

export const isFileExists = (filePath: string) =>
fs.promises
.access(filePath, F_OK)
.then(() => true)
.catch(() => false);

export const isEmptyDir = async (path: string) => {
try {
const fsp = fs.promises;
const directory = await fsp.opendir(path);
const entry = await directory.read();
await directory.close();
return entry === null;
} catch (error) {
return false;
}
};

/**
* Creates a pool of objects T which will be collected
* until some delay passed since the last object added to the pool.
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
"test": "jest",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"debug:tx": "ts-node ./scripts/composeTx.ts",
"debug:wallet": "ts-node ./scripts/readSecrets.ts",
"debug:addViewAccount": "ts-node ./scripts/addViewOnlyAccount.ts"
"script:composeTx": "ts-node ./scripts/composeTx.ts",
"script:decomposeTx": "ts-node ./scripts/decomposeTx.ts",
"script:readSecrets": "ts-node ./scripts/readSecrets.ts",
"script:addViewAccount": "ts-node ./scripts/addViewOnlyAccount.ts"
},
"repository": {
"type": "git",
Expand Down
3 changes: 1 addition & 2 deletions scripts/composeTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import Bech32 from '@spacemesh/address-wasm';
import prompts from 'prompts';

import { sign } from '../desktop/ed25519';
import { fromHexString } from '../shared/utils';
import { fromHexString, generateGenesisID } from '../shared/utils';
import { SingleSigMethods } from '../shared/templateConsts';
import { generateGenesisID } from "../desktop/main/Networks";

(async () => {
// Inputs
Expand Down
46 changes: 46 additions & 0 deletions scripts/decomposeTx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as sm from '@spacemesh/sm-codec';
import prompts from 'prompts';
import { SingleSigMethods } from '../shared/templateConsts';

(async () => {
// Inputs
const inputs = await prompts([
{
type: 'select',
name: 'templateAddress',
message: 'Choose the template',
choices: [
{ title: 'SingleSig', value: sm.SingleSigTemplate.key },
],
},
{
type: prev => prev === sm.SingleSigTemplate.key ? 'select' : null,
name: 'method',
message: 'Choose the method',
choices: [
{ title: 'SelfSpawn', value: SingleSigMethods.Spawn },
{ title: 'Spend', value: SingleSigMethods.Spend },
],
},
{
type: 'text',
name: 'rawTx',
message: 'Put here raw transaction (in format `0, 0, 0, 0, 0, 0, 227, ..., 23`)',
},
], {
onCancel: () => {
console.log('Composing transaction cancelled');
process.exit(0);
}
});

// SCRIPT
const tpl = sm.TemplateRegistry.get(inputs.templateAddress, inputs.method);
const bytes = Uint8Array.from(
JSON.parse(
`[${inputs.rawTx.replace('[', '').replace(']', '')}]`
)
);

console.dir(tpl.decode(bytes), { depth: null, colors: true });
})();
2 changes: 1 addition & 1 deletion scripts/readSecrets.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import prompts from 'prompts';
import fs from 'fs';
import { decryptWallet } from '../desktop/main/walletFile';
import { WalletFile } from '../shared/types';
import { decryptWallet } from '../desktop/main/walletFile';

(async () => {
console.log('Attention!');
Expand Down
8 changes: 8 additions & 0 deletions shared/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os from 'os';
import { hash } from '@spacemesh/sm-codec';
import { Timestamp } from '@grpc/grpc-js/build/src/generated/google/protobuf/Timestamp';
import { Event } from '../proto/spacemesh/v1/Event';
import { Duration } from '../proto/google/protobuf/Duration';
Expand Down Expand Up @@ -138,6 +139,10 @@ export const getEventType = (event: NodeEvent): Event['details'] => {
return eventType;
};

export const generateGenesisID = (genesisTime: string, extraData: string) => {
return `${toHexString(hash(genesisTime + extraData)).substring(0, 40)}`;
};

export const getShortGenesisId = (genesisID: HexString) =>
genesisID.substring(0, 8);

Expand All @@ -149,3 +154,6 @@ export const isDebPackage = () =>

export const isLinuxAppImage = () =>
os.platform() === 'linux' && !!process.env.APPIMAGE;
//
// Assertions
//
13 changes: 6 additions & 7 deletions tests/desktop/Network.spec.ts → tests/shared/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { generateGenesisID } from '../../desktop/main/Networks';
import { generateGenesisID } from '../../shared/utils';

describe('test Network util functions', () => {
describe('generateGenesisID', () => {
const genesisTime = '2022-11-20T20:00:00.498Z';
const extraData = 'unique-testnet-identifier';

const expectedGenesisId = 'b92736fb23dfe78efe03c2c45fb638b9fe3afa70';

it('test for generateGenesisID', () => {
it('is pure & determenistic', () => {
expect(generateGenesisID(genesisTime, extraData)).toEqual(
generateGenesisID(genesisTime, extraData)
);

});
it('works as expected', () => {
expect(generateGenesisID(genesisTime, extraData)).toEqual(
expectedGenesisId
'b92736fb23dfe78efe03c2c45fb638b9fe3afa70'
);
});
});

0 comments on commit 97c6f3e

Please sign in to comment.