From c16932344a948b38708ae379cc5a928d73335592 Mon Sep 17 00:00:00 2001 From: JoeGruffins <34998433+JoeGruffins@users.noreply.github.com> Date: Fri, 17 May 2024 22:30:52 +0900 Subject: [PATCH] trezor: Add trezord-go to bin. (#3913) If a user opens a trezor wallet, also start the trezor bridge that is needed for communications. --- app/actions/TrezorActions.js | 7 +- app/main.development.js | 6 ++ app/main_dev/constants.js | 2 +- app/main_dev/ipc.js | 23 +++++++ app/main_dev/launch.js | 99 ++++++++++++++++++++++++++++- app/main_dev/logging.js | 8 +++ app/wallet-preload-shim.js | 1 + app/wallet-preload.js | 4 +- app/wallet/trezord/index.js | 4 ++ appveyor.yml | 5 ++ package.json | 1 + test/mocks/trezordMock.js | 4 ++ test/mocks/walletPreloadShimMock.js | 1 + 13 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 app/wallet/trezord/index.js create mode 100644 test/mocks/trezordMock.js diff --git a/app/actions/TrezorActions.js b/app/actions/TrezorActions.js index 96e1175897..453b3ea113 100644 --- a/app/actions/TrezorActions.js +++ b/app/actions/TrezorActions.js @@ -1,4 +1,5 @@ import { wallet, fs } from "wallet-preload-shim"; +import { trezord } from "wallet-preload-shim"; import * as selectors from "selectors"; import { hexToBytes, str2utf8hex, rawToHex } from "helpers"; import { @@ -47,13 +48,14 @@ export const TRZ_TREZOR_ENABLED = "TRZ_TREZOR_ENABLED"; // enableTrezor attepts to start a connection with connect if none exist and // connect to a trezor device. -export const enableTrezor = () => (dispatch, getState) => { +export const enableTrezor = () => async (dispatch, getState) => { dispatch({ type: TRZ_TREZOR_ENABLED }); if (!setListeners) { setDeviceListeners(dispatch, getState); setListeners = true; } + await trezord.start(); connect()(dispatch, getState); }; @@ -104,7 +106,8 @@ export const TRZ_TREZOR_DISABLED = "TRZ_TREZOR_DISABLED"; // disableTrezor disables trezor integration for the current wallet. Note // that it does **not** disable in the config, so the wallet will restart as a // trezor wallet next time it's opened. -export const disableTrezor = () => (dispatch) => { +export const disableTrezor = () => async (dispatch) => { + await trezord.stop(); dispatch({ type: TRZ_TREZOR_DISABLED }); }; diff --git a/app/main.development.js b/app/main.development.js index 7060ef2e48..809b52dd07 100644 --- a/app/main.development.js +++ b/app/main.development.js @@ -62,6 +62,8 @@ import { startDcrlnd, stopDcrlnd, removeDcrlnd, + startTrezord, + stopTrezord, lnScbInfo, startDex, stopDex, @@ -410,6 +412,10 @@ handle("start-dex", startDex); handle("stop-dex", stopDex); +handle("start-trezord", startTrezord); + +handle("stop-trezord", stopTrezord); + handle("launch-dex-window", createDexWindow); handle("set-wallet-password-dex", setWalletPasswordDex); diff --git a/app/main_dev/constants.js b/app/main_dev/constants.js index 1ec5f55238..b72553d9b8 100644 --- a/app/main_dev/constants.js +++ b/app/main_dev/constants.js @@ -18,7 +18,7 @@ Options --rpccert Specify RPC Certificate --rpcconnect Specify RPC connection in 'host:port' or 'host' format (latter uses the default RPC port). Note that different ports are used for RPC and SPV connections. --extrawalletargs Pass extra arguments to dcrwallet. - --custombinpath Custom path for dcrd/dcrwallet/dcrctl binaries. + --custombinpath Custom path for dcrd/dcrwallet/dcrctl/trezord-go binaries. `; export const VERSION_MESSAGE = `${app.name} version ${app.getVersion()}`; diff --git a/app/main_dev/ipc.js b/app/main_dev/ipc.js index 7f0c5f1b5b..26f6d0b7bf 100644 --- a/app/main_dev/ipc.js +++ b/app/main_dev/ipc.js @@ -18,6 +18,9 @@ import { launchDCRLnd, GetDcrlndPID, GetDcrlndCreds, + launchTrezord, + GetTrezordPID, + closeTrezord, launchDex, initCheckDex, initDexCall, @@ -248,6 +251,26 @@ export const startDcrlnd = async ( } }; +export const startTrezord = async () => { + if (GetTrezordPID() && GetTrezordPID() !== -1) { + logger.log( + "info", + `Skipping restart of trezord-go as it is already running ${GetTrezordPID()}` + ); + return { wasRunning: true }; + } + + try { + const started = await launchTrezord(); + return started; + } catch (e) { + logger.log("error", `error launching trezord-go: ${e}`); + return e; + } +}; + +export const stopTrezord = () => closeTrezord(); + export const startDex = async (walletPath, testnet, locale) => { if (GetDexPID()) { logger.log( diff --git a/app/main_dev/launch.js b/app/main_dev/launch.js index 5d7ce7c7e3..d3be524aa6 100644 --- a/app/main_dev/launch.js +++ b/app/main_dev/launch.js @@ -14,6 +14,7 @@ import { AddToDcrdLog, AddToDcrwalletLog, AddToDcrlndLog, + AddToTrezordLog, GetDcrdLogs, GetDcrwalletLogs, lastErrorLine, @@ -52,10 +53,15 @@ const logger = createLogger(debug); let dex = null; -let dcrdPID, dcrwPID, dcrlndPID; +let dcrdPID, dcrwPID, dcrlndPID, trezordPID; // windows-only stuff -let dcrwPipeRx, dcrwPipeTx, dcrwTxStream, dcrdPipeRx, dcrlndPipeRx; +let dcrwPipeRx, + dcrwPipeTx, + dcrwTxStream, + dcrdPipeRx, + dcrlndPipeRx, + trezordPipeRx; // general data that needs to keep consistency while decrediton is running. let dcrwPort; @@ -131,6 +137,7 @@ function closeClis() { if (dcrdPID && dcrdPID !== -1) closeDCRD(); if (dcrwPID && dcrwPID !== -1) closeDCRW(); if (dcrlndPID && dcrlndPID !== -1) closeDcrlnd(); + if (trezordPID && trezordPID !== -1) closeTrezord(); if (dex) closeDex(); } @@ -265,6 +272,28 @@ export const closeDcrlnd = () => { return true; }; +export function closeTrezord() { + if (trezordPID === -1) { + // process is not started by decrediton + return true; + } + if (isRunning(trezordPID) && os.platform() != "win32") { + logger.log("info", "Sending SIGINT to trezord at pid:" + trezordPID); + process.kill(trezordPID, "SIGINT"); + trezordPID = null; + } else if (isRunning(trezordPID)) { + try { + const dcrwin32ipc = require("dcrwin32ipc/build/Release/dcrwin32ipc.node"); + dcrwin32ipc.closePipe(trezordPipeRx); + trezordPID = null; + } catch (e) { + logger.log("error", "Error closing trezord piperx: " + e); + return false; + } + } + return true; +} + export const closeDex = () => { logger.log("info", "closing dex " + dex); if (!dex) { @@ -930,6 +959,68 @@ export const launchDCRLnd = ( return resolve(dcrlndCreds); }); +export const launchTrezord = () => + new Promise((resolve, reject) => { + if (trezordPID === -1) { + resolve(); + } + + const trezordExe = getExecutablePath("trezord-go", argv.custombinpath); + if (!fs.existsSync(trezordExe)) { + logger.log( + "error", + "The trezord-go executable does not exist. Expected to find it at " + + trezordExe + ); + reject("The trezord-go executable does not exist at " + trezordExe); + } + + const args = []; + if (os.platform() == "win32") { + try { + const dcrwin32ipc = require("dcrwin32ipc/build/Release/dcrwin32ipc.node"); + trezordPipeRx = dcrwin32ipc.createPipe("out"); + args.push(format("--piperx=%d", trezordPipeRx.readEnd)); + } catch (e) { + logger.log( + "error", + "can't find proper module to launch trezord-go: " + e + ); + } + } + + logger.log("info", `Starting ${trezordExe}`); + + const trezord = spawn(trezordExe, args, { + detached: os.platform() === "win32", + stdio: ["ignore", "pipe", "pipe"] + }); + + trezord.on("error", function (err) { + reject(err); + }); + + trezord.on("close", (code) => { + logger.log("info", `trezord-go exited with code ${code}`); + }); + + trezord.stdout.on("data", (data) => { + AddToTrezordLog(process.stdout, data, debug); + resolve(data.toString("utf-8")); + }); + + trezord.stderr.on("data", (data) => { + AddToTrezordLog(process.stderr, data, debug); + resolve(data.toString("utf-8")); + }); + + trezordPID = trezord.pid; + logger.log("info", "trezord-go started with pid:" + trezordPID); + + trezord.unref(); + return; + }); + const Mainnet = 0; const Testnet = 1; @@ -1066,9 +1157,11 @@ export const GetDcrlndCreds = () => dcrlndCreds; export const GetDexPID = () => dex; export const GetDexCreds = () => dexCreds; +export const GetTrezordPID = () => trezordPID; + export const readExesVersion = (app, grpcVersions) => { const args = ["--version"]; - const exes = ["dcrd", "dcrwallet", "dcrctl"]; + const exes = ["dcrd", "dcrwallet", "dcrctl", "trezord-go"]; const versions = { grpc: grpcVersions, decrediton: app.getVersion() diff --git a/app/main_dev/logging.js b/app/main_dev/logging.js index 237f07c276..0296226b18 100644 --- a/app/main_dev/logging.js +++ b/app/main_dev/logging.js @@ -8,6 +8,7 @@ let dcrdLogs = Buffer.from(""); let dcrwalletLogs = Buffer.from(""); let dcrlndLogs = Buffer.from(""); let dexcLogs = Buffer.from(""); +let trezordLogs = Buffer.from(""); let privacyLogs = Buffer.from(""); let logger; @@ -163,6 +164,10 @@ export const AddToDexcLog = (destIO, data, debug) => { dexcLogs = AddToLog(destIO, dexcLogs, data, debug); }; +export const AddToTrezordLog = (destIO, data, debug) => { + trezordLogs = AddToLog(destIO, trezordLogs, data, debug); +}; + export const AddToPrivacyLog = (destIO, data, debug) => { // if log contains any of those messages we consider it a privacy log. const privacyLogsArray = [ @@ -187,6 +192,8 @@ export const GetDcrwalletLogs = () => dcrwalletLogs; export const GetDcrlndLogs = () => dcrlndLogs; +export const GetTrezordLogs = () => trezordLogs; + export const GetDexcLogs = () => dexcLogs; export const getPrivacyLogs = () => privacyLogs.toString("utf-8"); @@ -221,6 +228,7 @@ export function ClearDcrwalletLogs() { dcrwalletLogs = Buffer.from(""); dcrlndLogs = Buffer.from(""); dexcLogs = Buffer.from(""); + trezordLogs = Buffer.from(""); } // dcrd upgrades warning. diff --git a/app/wallet-preload-shim.js b/app/wallet-preload-shim.js index 43808b9313..b71349da04 100644 --- a/app/wallet-preload-shim.js +++ b/app/wallet-preload-shim.js @@ -4,3 +4,4 @@ export const walletCrypto = window.walletCrypto; export const dex = window.dex; export const ln = window.ln; export const politeia = window.politeia; +export const trezord = window.trezord; diff --git a/app/wallet-preload.js b/app/wallet-preload.js index 9d780452bc..4b9db08b39 100644 --- a/app/wallet-preload.js +++ b/app/wallet-preload.js @@ -3,6 +3,7 @@ import * as wallet from "wallet"; import * as walletCrypto from "wallet/crypto"; import * as dex from "wallet/dex"; import * as ln from "wallet/ln"; +import * as trezord from "wallet/trezord"; import * as politeia from "wallet/politeia"; import { contextBridge } from "electron"; @@ -13,7 +14,8 @@ const api = { walletCrypto: walletCrypto, dex: dex, ln: ln, - politeia: politeia + politeia: politeia, + trezord: trezord }; try { diff --git a/app/wallet/trezord/index.js b/app/wallet/trezord/index.js new file mode 100644 index 0000000000..89db500946 --- /dev/null +++ b/app/wallet/trezord/index.js @@ -0,0 +1,4 @@ +import { invocable } from "helpers/electronRenderer"; + +export const start = invocable("start-trezord"); +export const stop = invocable("stop-trezord"); diff --git a/appveyor.yml b/appveyor.yml index f7f8e559e4..3c32dbce2d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,6 +22,7 @@ install: - go get -u -v github.com/decred/dcrd - go get -u -v github.com/decred/dcrwallet - go get -u -v github.com/Masterminds/glide + - go get -u -v github.com/trezor/trezord-go - go get -u github.com/golang/dep/cmd/dep - cd %GOPATH%\\src\\github.com\\decred\\dcrd - glide i @@ -29,11 +30,15 @@ install: - cd ../dcrwallet - dep ensure - go install + - cd ../trezord-go + - dep ensure + - go install - cd %APPVEYOR_BUILD_FOLDER% - mkdir bin - cp %GOPATH%\\bin\\dcrd.exe bin/ - cp %GOPATH%\\bin\\dcrctl.exe bin/ - cp %GOPATH%\\bin\\dcrwallet.exe bin/ + - cp %GOPATH%\\bin\\trezord-go.exe bin/ - npm install build_script: diff --git a/package.json b/package.json index c704ad2949..3e771824d6 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "^electron-store$": "/test/mocks/electronStore.js", "wallet$": "/test/mocks/walletMock.js", "^dex$": "/test/mocks/dexMock.js", + "^trezord$": "/test/mocks/trezordMock.js", "^walletCrypto$": "/app/wallet/crypto.js", "^fetchModule$": "/app/helpers/fetchModule.js", "wallet-preload-shim$": "/test/mocks/walletPreloadShimMock.js" diff --git a/test/mocks/trezordMock.js b/test/mocks/trezordMock.js new file mode 100644 index 0000000000..508d35a6f8 --- /dev/null +++ b/test/mocks/trezordMock.js @@ -0,0 +1,4 @@ +export default {}; + +export const start = () => {}; +export const stop = () => {}; diff --git a/test/mocks/walletPreloadShimMock.js b/test/mocks/walletPreloadShimMock.js index 5d8e88001f..57322bbcf8 100644 --- a/test/mocks/walletPreloadShimMock.js +++ b/test/mocks/walletPreloadShimMock.js @@ -1,4 +1,5 @@ export * as dex from "./dexMock.js"; export * as wallet from "./walletMock.js"; export * as fs from "./fsMock.js"; +export * as trezord from "./trezordMock.js"; export const politeia = {};