Skip to content

Commit

Permalink
[DDW-254] Address validation upgrade to use cardano-addresses CLI via…
Browse files Browse the repository at this point in the history
… IPC (#2041)

* WIP address introspection via IPC, using cardano-addresses CLI tool executued as a child process

* Address introspection via IPC, using cardano-addresses CLI tool executed in a child process

* Hoist stake_reference to AddressBase

* [DDW-254] Integrate latest cardano js and update address validation logic - updates

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* cardano-address: add to daedalus bridge

(cherry picked from commit e6efdae)

* add cardanoAddressBin and autocompletions to shell

(cherry picked from commit f47fa50)

* daedalus-bridge: fix errors copying files that exist

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW] Bump cardano-wallet revision

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - updates

* cardano-wallet: bump for new cardano-address fix

* Reject non validation errors from introspect-address onReceieve. This does not include client-side handling

* Bump cardano-wallet rev

* Bump cardano-wallet rev via nix-shell -A devops --run "niv update cardano-wallet

* Wallet row fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* fix(address-introspection): refactor to spawning a child process

Rather than the single line `exec`, this uses Node.js cross-platform API
to pass stdin

* fix(address-introspection): bump cardano-wallet

* fix(address-introspection): bump cardano-wallet, switch to spawnSync

removes the async complexity to produce a reliable and easy to reason about implementation.
Given the nature of the operation, this is a fair use of the subprocess executor. Also adds
renderer error handler to catch and log non-validation errors

* fix(address-introspection): Check for empty buffer to detect error, generalise to user error matching

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* Bump cardano-wallet

* Add cardano-address to the Jormungandr bridge

* fix(address-introspection): Shelley testnet address network discrimination removal

* [DDW-254] Integrate latest cardano js and update address validation logic - changelog

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes for Shelley

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes for Shelley testnet

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes for Shelley testnet

* Apply valid mainnet_candidate_4 network ID to "Shelley Testnet"

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes for Shelley testnet

* Bump cardano-wallet

* DDW-296 Deadalus review fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Integrate latest cardano js and update address validation logic - fixes

* [DDW-254] Prevent connecting issue report while blokchaing verification is is progress

* DDW-296 Deadalus review fixes

* Run translation manager

* Fix flow error

* Fix flow issues

* Fix explorer URLs on Mainnet

* BUmp Daedalus version

* [DDW-254] Fix flow issue

Co-authored-by: Aleksandar Djordjevic <aca_eliminator@hotmail.com>
Co-authored-by: Samuel Leathers <samuel.leathers@iohk.io>
Co-authored-by: Nikola Glumac <niglumac@gmail.com>
Co-authored-by: Tomislav Horaček <tomislav.horacek@thespian.hr>
  • Loading branch information
5 people committed Jul 29, 2020
1 parent aba9f98 commit b267153
Show file tree
Hide file tree
Showing 20 changed files with 208 additions and 40 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
@@ -1,10 +1,11 @@
Changelog
=========

## vNext
## 2.0.0

### Features

- Implemented address validation ([PR 2041](https://github.com/input-output-hk/daedalus/pull/2041))
- Show block replay progress ([PR 2110](https://github.com/input-output-hk/daedalus/pull/2110))

### Fixes
Expand Down
3 changes: 2 additions & 1 deletion nix/jormungandr-bridge.nix
@@ -1,4 +1,4 @@
{ target, pkgs, cardano-wallet, cardano-shell, sources, jormungandrLib }:
{ target, pkgs, cardano-wallet, cardano-shell, sources, jormungandrLib, cardano-address }:

let
commonLib = import ../lib.nix {};
Expand All @@ -14,6 +14,7 @@ in pkgs.runCommandCC "daedalus-bridge" {
cp -f ${cardano-wallet.haskellPackages.cardano-wallet-jormungandr.components.exes.cardano-wallet-jormungandr}/bin/* .
cp -f ${cardano-shell.haskellPackages.cardano-launcher.components.exes.cardano-launcher}/bin/cardano-launcher* .
cp -f ${cardano-wallet.jormungandr}/bin/* .
cp -f ${cardano-address}/bin/cardano-address* .
echo ${cardano-wallet.version} > $out/version
Expand Down
6 changes: 3 additions & 3 deletions nix/sources.json
Expand Up @@ -29,10 +29,10 @@
"homepage": null,
"owner": "input-output-hk",
"repo": "cardano-wallet",
"rev": "ca96c435df4ea4f2aefc98a75ae668d5f709da56",
"sha256": "1mnnlg1x3y9cf3sqmxpqjdiwlay58pdci4cjxfvlwlyqqlsy5d1i",
"rev": "1c7041e5d396dad6871d3fb9d9989cdb2fb32b1a",
"sha256": "144iyq4nlsbvbbaaajqaz6gz96xmmmvmz1qbjirbxih3jmfyyqny",
"type": "tarball",
"url": "https://github.com/input-output-hk/cardano-wallet/archive/ca96c435df4ea4f2aefc98a75ae668d5f709da56.tar.gz",
"url": "https://github.com/input-output-hk/cardano-wallet/archive/1c7041e5d396dad6871d3fb9d9989cdb2fb32b1a.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
"version": "v2020-04-28"
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,7 +1,7 @@
{
"name": "daedalus",
"productName": "Daedalus",
"version": "2.0.0-RC1",
"version": "2.0.0",
"description": "Cryptocurrency Wallet",
"main": "./dist/main/index.js",
"scripts": {
Expand Down
11 changes: 11 additions & 0 deletions source/common/ipc/api.js
Expand Up @@ -38,6 +38,10 @@ import type {
ResumeDownloadResponse,
} from '../types/downloadManager.types';
import type { StoreMessage } from '../types/electron-store.types';
import type {
IntrospectAddressRequest,
IntrospectAddressResponse,
} from '../types/address-introspection.types';

/**
* ======================= IPC CHANNELS API =========================
Expand Down Expand Up @@ -321,6 +325,13 @@ export const RESUME_DOWNLOAD = 'RESUME_DOWNLOAD';
export type ResumeDownloadRendererRequest = ResumeDownloadRequest;
export type ResumeDownloadMainResponse = ResumeDownloadResponse | void;

/**
* Channel for introspecting an address
*/
export const INTROSPECT_ADDRESS_CHANNEL = 'INTROSPECT_ADDRESS_CHANNEL';
export type IntrospectAddressRendererRequest = IntrospectAddressRequest;
export type IntrospectAddressMainResponse = IntrospectAddressResponse;

/**
* Channel for checking block replay progress
*/
Expand Down
54 changes: 54 additions & 0 deletions source/common/types/address-introspection.types.js
@@ -0,0 +1,54 @@
// @flow

export type IntrospectAddressRequest = {
input: string,
};

export type AddressStyle = 'Byron' | 'Icarus' | 'Jormungandr' | 'Shelley';

export type ChainPointer = {
slot_num: number,
transaction_index: number,
output_index: number,
};

export type AddressBase = {
address_style: AddressStyle,
network_tag: number | null,
stake_reference: 'none' | 'by pointer' | 'by value',
};

export type ByronAddress = AddressBase & {
address_root: string,
derivation_path: string,
};

export type IcarusAddress = AddressBase & {
address_root: string,
};

export type JormungandrAddress = AddressBase & {
address_type: 'single' | 'group' | 'account' | 'multisig',
account_key?: string,
merkle_root?: string,
spending_key?: string,
stake_key?: string,
};

export type ShelleyAddress = AddressBase & {
pointer?: ChainPointer,
script_hash?: string,
spending_key_hash?: string,
stake_key_hash?: string,
stake_script_hash?: string,
};

export type IntrospectAddressResponse =
| {
introspection:
| ByronAddress
| IcarusAddress
| JormungandrAddress
| ShelleyAddress,
}
| 'Invalid';
18 changes: 18 additions & 0 deletions source/common/types/cardano-node.types.js
Expand Up @@ -134,3 +134,21 @@ export type CardanoStatus = {
cardanoNodePID: number,
cardanoWalletPID: number,
};

// Cardano Mainet network magic
export const MAINNET_MAGIC = [1, null];

// Cardano Byron Testnet network magic
export const TESTNET_MAGIC = [1097911063, 0];

// Cardano Byron Testnet network magic
export const ITN_MAGIC = 1;

// Cardano Mainnet Candidate during the Shelley HF
export const SHELLEY_TESTNET_NETWORK_ID = [1, null];

// Cardano Staging network magic
export const STAGING_MAGIC = 633343913;

// Cardano Selfnode network magic
export const SELFNODE_MAGIC = 459045235;
4 changes: 2 additions & 2 deletions source/main/cardano/utils.js
Expand Up @@ -4,7 +4,6 @@ import path from 'path';
import { BrowserWindow, dialog } from 'electron';
import { spawnSync } from 'child_process';
import { logger } from '../utils/logging';
import { TESTNET_MAGIC } from '../config';
import { getTranslation } from '../utils/getTranslation';
import ensureDirectoryExists from '../utils/ensureDirectoryExists';
import type { LauncherConfig } from '../config';
Expand All @@ -20,6 +19,7 @@ import {
CardanoProcessNameOptions,
CardanoNodeImplementationOptions,
NetworkNameOptions,
TESTNET_MAGIC,
} from '../../common/types/cardano-node.types';

export type Process = {
Expand Down Expand Up @@ -231,7 +231,7 @@ export const exportWallets = async (

// Cluster flags
if (cluster === 'testnet') {
exportWalletsBinFlags.push('--testnet', TESTNET_MAGIC);
exportWalletsBinFlags.push('--testnet', TESTNET_MAGIC.toString());
} else {
exportWalletsBinFlags.push('--mainnet');
}
Expand Down
3 changes: 0 additions & 3 deletions source/main/config.js
Expand Up @@ -172,6 +172,3 @@ export const STAKE_POOL_REGISTRY_URL = {
qa:
'https://explorer.qa.jormungandr-testnet.iohkdev.io/stakepool-registry/registry.zip',
};

// Cardano Byron Testnet network magic
export const TESTNET_MAGIC = '1097911063';
2 changes: 2 additions & 0 deletions source/main/ipc/index.js
Expand Up @@ -15,6 +15,7 @@ import { handlePaperWalletRequests } from './generatePaperWalletChannel';
import { handleAddressPDFRequests } from './generateAddressPDFChannel';
import { handleRewardsCsvRequests } from './generateRewardsCsvChannel';
import { handleFileDialogRequests } from './show-file-dialog-channels';
import { handleAddressIntrospectionRequests } from './introspect-address';
import { openExternalUrlChannel } from './open-external-url';
import { openLocalDirectoryChannel } from './open-local-directory';

Expand All @@ -31,6 +32,7 @@ export default (window: BrowserWindow) => {
handleAddressPDFRequests();
handleRewardsCsvRequests();
handleFileDialogRequests(window);
handleAddressIntrospectionRequests();
// eslint-disable-next-line no-unused-expressions
openExternalUrlChannel;
// eslint-disable-next-line no-unused-expressions
Expand Down
35 changes: 35 additions & 0 deletions source/main/ipc/introspect-address.js
@@ -0,0 +1,35 @@
// @flow
import { spawnSync } from 'child_process';
import { MainIpcChannel } from './lib/MainIpcChannel';
import { INTROSPECT_ADDRESS_CHANNEL } from '../../common/ipc/api';
import type {
IntrospectAddressRendererRequest,
IntrospectAddressMainResponse,
} from '../../common/ipc/api';

// IpcChannel<Incoming, Outgoing>

export const introspectAddressChannel: MainIpcChannel<
IntrospectAddressRendererRequest,
IntrospectAddressMainResponse
> = new MainIpcChannel(INTROSPECT_ADDRESS_CHANNEL);

export const handleAddressIntrospectionRequests = () => {
introspectAddressChannel.onReceive(
({ input }: IntrospectAddressRendererRequest) =>
new Promise((resolve, reject) => {
const { stdout, stderr } = spawnSync(
'cardano-address',
['address', 'inspect'],
{ input }
);
if (stderr.toString() !== '') {
if (stderr.toString().match(/user error/g) !== null) {
return resolve('Invalid');
}
return reject(new Error(stderr.toString()));
}
return resolve({ introspection: JSON.parse(stdout.toString()) });
})
);
};
Expand Up @@ -145,14 +145,17 @@ export default class SyncingConnecting extends Component<Props, State> {
isNewAppVersionAvailable,
isIncentivizedTestnet,
forceConnectivityIssue,
isVerifyingBlockchain,
} = this.props;
const { connectingTime } = this.state;
const canReportConnectingIssue =
isSyncProgressStalling ||
forceConnectivityIssue ||
(!isConnected &&
(connectingTime >= REPORT_ISSUE_TIME_TRIGGER ||
cardanoNodeState === CardanoNodeStates.UNRECOVERABLE));
!isVerifyingBlockchain &&
(isSyncProgressStalling ||
forceConnectivityIssue ||
(!isConnected &&
(connectingTime >= REPORT_ISSUE_TIME_TRIGGER ||
cardanoNodeState === CardanoNodeStates.UNRECOVERABLE)));

if (isFlight || isIncentivizedTestnet || global.isShelleyTestnet) {
return canReportConnectingIssue;
}
Expand Down
2 changes: 1 addition & 1 deletion source/renderer/app/components/wallet/WalletSendForm.js
Expand Up @@ -190,7 +190,7 @@ export default class WalletSendForm extends Component<Props, State> {
const amountField = form.$('amount');
const amountValue = amountField.value.toString();
const isAmountValid = amountField.isValid;
const isValidAddress = this.props.addressValidator(value);
const isValidAddress = await this.props.addressValidator(value);
if (isValidAddress && isAmountValid) {
await this._calculateTransactionFee(value, amountValue);
} else {
Expand Down
6 changes: 3 additions & 3 deletions source/renderer/app/i18n/locales/defaultMessages.json
Expand Up @@ -1082,7 +1082,7 @@
"description": "Message \"Verifying the blockchain (65% complete) ...\" on the loading screen.",
"end": {
"column": 3,
"line": 73
"line": 74
},
"file": "source/renderer/app/components/loading/syncing-connecting/SyncingConnectingStatus.js",
"id": "loading.screen.verifyingBlockchainMessage",
Expand Down Expand Up @@ -8368,7 +8368,7 @@
}
},
{
"defaultMessage": "!!!Please enter your {expectedWordCount}-word wallet recovery phrase. Make sure you enter the words in the correct order.",
"defaultMessage": "!!!Please enter your wallet recovery phrase. Make sure you enter the words in the correct order.",
"description": "Label for the recoveryPhraseStep2Description on wallet settings.",
"end": {
"column": 3,
Expand Down Expand Up @@ -13912,7 +13912,7 @@
"line": 78
},
"file": "storybook/stories/common/Widgets.stories.js",
"id": "appUpdate.manualUpdateOverlay.button.label",
"id": "manualUpdate.button.label",
"start": {
"column": 22,
"line": 74
Expand Down
1 change: 0 additions & 1 deletion source/renderer/app/i18n/locales/en-US.json
Expand Up @@ -17,7 +17,6 @@
"api.errors.invalidAddress": "Please enter a valid address.",
"api.errors.nothingToMigrate": "Funds cannot be transferred from this wallet because it contains some unspent transaction outputs (UTXOs), with amounts of ada that are too small to be migrated.",
"api.errors.utxoTooSmall": "Invalid transaction.",
"appUpdate.manualUpdateOverlay.button.label": "!!!Follow instructions and manually update",
"automaticUpdate.accept.button.label": "Restart Daedalus and Update",
"automaticUpdate.description1": "You are currently running Daedalus <b>{currentAppVersion}</b> and <b>{nextUpdateVersion}</b> is available.",
"automaticUpdate.description2": "Would you like to install the update? If choose to postpone, the update will be installed automatically on the next Daedalus launch.",
Expand Down
1 change: 0 additions & 1 deletion source/renderer/app/i18n/locales/ja-JP.json
Expand Up @@ -17,7 +17,6 @@
"api.errors.invalidAddress": "有効なアドレスを入力してください。",
"api.errors.nothingToMigrate": "このウォレットに保有されている未使用トランザクションアウトプット(UTXO)の一部に、移行するために十分なADAが入っていないため、このウォレットから資金を移すことはできません。",
"api.errors.utxoTooSmall": "無効なトランザクションです。",
"appUpdate.manualUpdateOverlay.button.label": "!!!Follow instructions and manually update",
"automaticUpdate.accept.button.label": "Daedalusを再起動して更新する",
"automaticUpdate.description1": "現在実行中のDaedalus <b>{currentAppVersion}</b>は<b>{nextUpdateVersion}</b>に更新できます。",
"automaticUpdate.description2": "今すぐ最新版をインストールしますか。更新を保留すると、Daedalusを次回起動する時に自動的にインストールされます。",
Expand Down
13 changes: 13 additions & 0 deletions source/renderer/app/ipc/introspect-address.js
@@ -0,0 +1,13 @@
// @flow
import { RendererIpcChannel } from './lib/RendererIpcChannel';
import { INTROSPECT_ADDRESS_CHANNEL } from '../../../common/ipc/api';
import type {
IntrospectAddressRendererRequest,
IntrospectAddressMainResponse,
} from '../../../common/ipc/api';

// IpcChannel<Incoming, Outgoing>
export const introspectAddressChannel: RendererIpcChannel<
IntrospectAddressMainResponse,
IntrospectAddressRendererRequest
> = new RendererIpcChannel(INTROSPECT_ADDRESS_CHANNEL);

0 comments on commit b267153

Please sign in to comment.