on master help sign in
fix: handle infinite loop from networking reset and consider transaction pending until keyfile available
commit072c6eb01034c98ac40426f479e1f3ae4553089d authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateThu 18 Jul 2019, 13:13 (7 years ago) parentb87ca5c
8 files changed+61−44
src/components/DownloadKeyfileButton.js+7−7 src/indigo-react/components/IconButton.js+1−1 src/indigo-react/components/Input.js+2−2 src/lib/useEthereumTransaction.js+4−6 src/lib/useKeyfileGenerator.js+11−3 src/lib/useSetState.js+3−3 src/views/Admin/AdminHome.js+8−4 src/views/Admin/AdminNetworkingKeys.js+25−18
src/components/DownloadKeyfileButton.js+7−7
@@ -1,19 +1,19 @@
11import React from 'react';
22import { B } from 'indigo-react';
33
4−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
5−
64import { DownloadButton } from 'components/Buttons';
75
86export default function DownloadKeyfileButton({
9− networkSeed,
7+ // useKeyfileGenerator.bind
8+ generating,
9+ available,
10+ downloaded,
11+ download,
12+
13+ // from caller
1014 className,
1115 ...rest
1216}) {
13− const { generating, available, downloaded, download } = useKeyfileGenerator(
14− networkSeed
15− );
16−
1717 const showHelp = !generating && !available;
1818
1919 return (
src/indigo-react/components/IconButton.js+1−1
@@ -10,7 +10,7 @@ export default function IconButton({
1010 disabled = false,
1111 secondary = false,
1212 solid = false,
13− flush = false, // whether or not the icon should include horizontal padding
13+ flush = false, // if true, remove horizontal padding
1414 ...rest
1515}) {
1616 return (
src/indigo-react/components/Input.js+2−2
@@ -4,7 +4,7 @@ import cn from 'classnames';
44import Flex from './Flex';
55import { ErrorText } from './Typography';
66
7−export default function Input({
7+export default React.memo(function Input({
88 // visuals
99 name,
1010 label,
@@ -115,4 +115,4 @@ export default function Input({
115115 )}
116116 </Flex>
117117 );
118−}
118+});
src/lib/useEthereumTransaction.js+4−6
@@ -16,6 +16,7 @@ import {
1616import * as need from './need';
1717import useLifecycle from './useLifecycle';
1818import { ensureFundsFor } from './tank';
19+import useDeepEqualReference from './useDeepEqualReference';
1920
2021const STATE = {
2122 NONE: 'NONE',
@@ -199,7 +200,7 @@ export default function useEthereumTransaction(
199200 })();
200201 });
201202
202− const values = {
203+ const values = useDeepEqualReference({
203204 isDefaultState,
204205 initializing,
205206 construct,
@@ -223,10 +224,7 @@ export default function useEthereumTransaction(
223224 nonce,
224225 chainId,
225226 needFunds,
226− };
227+ });
227228
228− return {
229− ...values,
230− bind: values,
231− };
229+ return { ...values, bind: values };
232230}
src/lib/useKeyfileGenerator.js+11−3
@@ -5,6 +5,7 @@ import * as ob from 'urbit-ob';
55
66import { usePointCache } from 'store/pointCache';
77import { useWallet } from 'store/wallet';
8+import { usePointCursor } from 'store/pointCursor';
89
910import * as need from 'lib/need';
1011
@@ -15,7 +16,6 @@ import {
1516 compileNetworkingKey,
1617} from './keys';
1718import useCurrentPermissions from './useCurrentPermissions';
18−import { usePointCursor } from 'store/pointCursor';
1919
2020export default function useKeyfileGenerator(manualNetworkSeed) {
2121 const { getDetails } = usePointCache();
@@ -34,7 +34,11 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
3434
3535 const hasNetworkingKeys = networkRevision > 0;
3636 const available =
37− (isOwner || isManagementProxy) && hasNetworkingKeys && keyfile;
37+ (isOwner || isManagementProxy) && hasNetworkingKeys && !!keyfile;
38+
39+ console.log(
40+ `keyfile available (${available}) for revision ${networkRevision}`
41+ );
3842
3943 const generate = useCallback(async () => {
4044 console.log('generating for network revision', networkRevision);
@@ -51,6 +55,7 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
5155
5256 if (Nothing.hasInstance(networkSeed)) {
5357 setGenerating(false);
58+ console.log('manual network seed not provided and key not derivable');
5459 return;
5560 }
5661
@@ -60,6 +65,7 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
6065
6166 if (!keysMatchChain(pair, _details)) {
6267 setGenerating(false);
68+ console.log('derived network keys do not match on-chain details');
6369 return;
6470 }
6571
@@ -90,10 +96,12 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
9096 generate();
9197 }, [generate]);
9298
93− return {
99+ const values = {
94100 generating,
95101 available,
96102 downloaded,
97103 download,
98104 };
105+
106+ return { ...values, bind: values };
99107}
src/lib/useSetState.js+3−3
@@ -1,15 +1,15 @@
1−import { useCallback, useState } from 'react';
1+import { useCallback, useRef, useState } from 'react';
22
33export default function useSetState(initialState = {}) {
4+ const initialStateRef = useRef(initialState);
45 const [state, _setState] = useState(initialState);
56 const setState = useCallback(
67 items => _setState(state => ({ ...state, ...items })),
78 [_setState]
89 );
910
10− const reset = useCallback(() => _setState(initialState), [
11+ const reset = useCallback(() => _setState(initialStateRef.current), [
1112 _setState,
12− initialState,
1313 ]);
1414
1515 return [state, setState, reset];
src/views/Admin/AdminHome.js+8−4
@@ -2,20 +2,23 @@ import React, { useCallback } from 'react';
22import { Just } from 'folktale/maybe';
33import { Grid, B } from 'indigo-react';
44
5−import { ForwardButton } from 'components/Buttons';
6−
75import { useWallet } from 'store/wallet';
86
9−import ViewHeader from 'components/ViewHeader';
107import { useLocalRouter } from 'lib/LocalRouter';
8+import useCurrentPermissions from 'lib/useCurrentPermissions';
9+import useKeyfileGenerator from 'lib/useKeyfileGenerator';
10+
11+import { ForwardButton } from 'components/Buttons';
12+import ViewHeader from 'components/ViewHeader';
1113import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
1214import MiniBackButton from 'components/MiniBackButton';
13−import useCurrentPermissions from 'lib/useCurrentPermissions';
1415
1516export default function AdminHome() {
1617 const { push, names, pop } = useLocalRouter();
1718 const { urbitWallet } = useWallet();
1819
20+ const { bind: keyfileBind } = useKeyfileGenerator();
21+
1922 const { isOwner, canTransfer, isTransferProxySet } = useCurrentPermissions();
2023
2124 const goRedownload = useCallback(() => push(names.REDOWNLOAD), [push, names]);
@@ -57,6 +60,7 @@ export default function AdminHome() {
5760 <Grid.Item
5861 full
5962 as={DownloadKeyfileButton}
63+ {...keyfileBind}
6064 detail="Download your Arvo Keyfile"
6165 />
6266 <Grid.Divider />
src/views/Admin/AdminNetworkingKeys.js+25−18
@@ -1,4 +1,4 @@
1−import React, { useCallback, useEffect, useState } from 'react';
1+import React, { useCallback, useEffect, useRef, useState } from 'react';
22import { Just, Nothing } from 'folktale/maybe';
33import {
44 Grid,
@@ -39,6 +39,7 @@ import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
3939import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
4040import NoticeBox from 'components/NoticeBox';
4141import { useHexInput, useCheckboxInput } from 'lib/useInputs';
42+import useKeyfileGenerator from 'lib/useKeyfileGenerator';
4243
4344const chainKeyProp = name => d =>
4445 d[name] === CURVE_ZERO_ADDR ? Nothing() : Just(d[name]);
@@ -61,19 +62,29 @@ function useSetKeys() {
6162 const _point = need.point(pointCursor);
6263 const _contracts = need.contracts(contracts);
6364
65+ const randomSeed = useRef();
66+
6467 // NOTE: nd = 'nondeterministic' (can also be a 'manual' seed)
6568 const [ndNetworkSeed, setNdNetworkSeed] = useState();
6669
70+ const {
71+ available: keyfileAvailable,
72+ bind: keyfileBind,
73+ } = useKeyfileGenerator(ndNetworkSeed);
74+
6775 const {
6876 isDefaultState,
6977 construct: _construct,
7078 unconstruct,
7179 broadcasting,
72− confirmed,
80+ confirmed: _confirmed,
7381 inputsLocked,
7482 bind,
7583 } = useEthereumTransaction(GAS_LIMITS.CONFIGURE_KEYS);
7684
85+ // only treat the transaction as confirmed once we also have keys to download
86+ const confirmed = _confirmed && keyfileAvailable;
87+
7788 // sync point details after success
7889 useEffect(() => {
7990 if (confirmed) {
@@ -98,14 +109,14 @@ function useSetKeys() {
98109 revision: networkRevision + 1,
99110 });
100111
101− return networkSeed.matchWith({
102− Nothing: () => {
103− const ndSeed = randomHex(64);
104− setNdNetworkSeed(ndSeed);
105− return ndSeed;
106− },
107− Just: p => p.value,
108− });
112+ if (Just.hasInstance(networkSeed)) {
113+ return networkSeed.value;
114+ }
115+
116+ randomSeed.current = randomSeed.current || randomHex(64);
117+ setNdNetworkSeed(randomSeed.current);
118+
119+ return randomSeed.current;
109120 }
110121 },
111122 [_point, authMnemonic, getDetails, urbitWallet, wallet]
@@ -139,6 +150,7 @@ function useSetKeys() {
139150 ndNetworkSeed,
140151 inputsLocked,
141152 bind,
153+ keyfileBind,
142154 };
143155}
144156
@@ -162,8 +174,8 @@ export default function AdminNetworkingKeys() {
162174 broadcasting,
163175 confirmed,
164176 inputsLocked,
165− ndNetworkSeed,
166177 bind,
178+ keyfileBind,
167179 } = useSetKeys();
168180
169181 const [showNetworkSeedInput, { data: showNetworkSeed }] = useCheckboxInput({
@@ -205,10 +217,10 @@ export default function AdminNetworkingKeys() {
205217 }
206218 }, [
207219 construct,
220+ unconstruct,
208221 isDiscontinuity,
209222 networkSeed,
210223 showNetworkSeed,
211− unconstruct,
212224 validDiscontinuity,
213225 validNetworkSeed,
214226 ]);
@@ -334,12 +346,7 @@ export default function AdminNetworkingKeys() {
334346 <Grid.Item full as={NoticeBox} className="mb3">
335347 You need this keyfile to authenticate with Arvo.
336348 </Grid.Item>
337− <Grid.Item
338− full
339− as={DownloadKeyfileButton}
340− solid
341− networkSeed={ndNetworkSeed}
342− />
349+ <Grid.Item full as={DownloadKeyfileButton} solid {...keyfileBind} />
343350 </>
344351 )}
345352