diff --git a/App.test.js b/App.test.js index 691f6fef5..2be770bd8 100644 --- a/App.test.js +++ b/App.test.js @@ -4,6 +4,7 @@ import { LegacyWallet } from './class'; import renderer from 'react-test-renderer'; import App from './App'; import Settings from './screen/settings'; +import Selftest from './screen/selftest'; import { BlueHeader } from './BlueComponents'; let assert = require('assert'); jest.mock('react-native-qrcode', () => 'Video'); @@ -35,3 +36,27 @@ it('Settings work', () => { const rendered = renderer.create().toJSON(); expect(rendered).toBeTruthy(); }); + +it('Selftest work', () => { + const component = renderer.create(); + const root = component.root; + const rendered = component.toJSON(); + expect(rendered).toBeTruthy(); + // console.log((root.findAllByType('Text')[0].props)); + + let okFound = false; + let allTests = []; + for (var v of root.findAllByType('Text')) { + let text = v.props.children; + if (text.join) { + text = text.join(''); + } + if (text === 'OK') { + okFound = true; + } + allTests.push(text); + // console.log(text); + } + + assert.ok(okFound, 'OK not found. Got: ' + allTests.join('; ')); +}); diff --git a/screen/selftest.js b/screen/selftest.js new file mode 100644 index 000000000..428cbd1eb --- /dev/null +++ b/screen/selftest.js @@ -0,0 +1,171 @@ +import React, { Component } from 'react'; +import { ScrollView, View } from 'react-native'; +import Ionicons from 'react-native-vector-icons/Ionicons'; +import { + BlueLoading, + BlueSpacing20, + SafeBlueArea, + BlueCard, + BlueText, + BlueHeader, +} from '../BlueComponents'; +import { SegwitP2SHWallet, LegacyWallet } from '../class'; +let BlueApp = require('../BlueApp'); +let BigNumber = require('bignumber.js'); + +export default class Selftest extends Component { + static navigationOptions = { + tabBarLabel: 'Self test', + tabBarIcon: ({ tintColor, focused }) => ( + + ), + }; + + constructor(props) { + super(props); + this.state = { + isLoading: true, + }; + } + + async componentDidMount() { + let errorMessage = ''; + let isOk = true; + + let uniqs = {}; + let w = new SegwitP2SHWallet(); + for (let c = 0; c < 10000; c++) { + w.generate(); + if (uniqs[w.getSecret()]) { + errorMessage += 'failed to generate unique private key; '; + isOk = false; + break; + } + uniqs[w.getSecret()] = 1; + } + + // + + let l = new LegacyWallet(); + l.setSecret('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct'); + if (l.getAddress() !== '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') { + errorMessage += 'failed to generate legacy address from WIF; '; + isOk = false; + } + + // + + l = new SegwitP2SHWallet(); + l.setSecret('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct'); + if (l.getAddress() !== '34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53') { + errorMessage += 'failed to generate segwit P2SH address from WIF; '; + isOk = false; + } + + // + + let utxo = [ + { + tx_hash: + '0f5eea78fb19e72b55bd119252ff29fc16c503d0e956a9c1b5b2ab0e95e0c323', + block_height: 514991, + tx_input_n: -1, + tx_output_n: 2, + value: 546, + ref_balance: 546, + spent: false, + confirmations: 9, + confirmed: '2018-03-24T18:13:36Z', + double_spend: false, + }, + ]; + + let tx = l.createTx( + utxo, + 0.001, + 0.0001, + '1QHf8Gp3wfmFiSdEX4FtrssCGR68diN1cj', + ); + let bitcoin = require('bitcoinjs-lib'); + let txDecoded = bitcoin.Transaction.fromHex(tx); + let txid = txDecoded.getId(); + + if ( + txid !== + '110f51d28d585e922adbf701cba802e549b8fe3a53fa5d62426ab42549c9b6de' + ) { + errorMessage += 'created txid doesnt match; '; + isOk = false; + } + if ( + tx !== + '0100000000010123c3e0950eabb2b5c1a956e9d003c516fc29ff529211bd552be719fb78ea5e0f0200000017160014597ce022baa887799951e0496c769d9cc0c759dc0000000001a0860100000000001976a914ff715fb722cb10646d80709aeac7f2f4ee00278f88ac0247304402202507d6b05ab19c7fdee217e97fddab80d481d7b2a103c00cecfc634bf897188d02205fa62ad413b6e441f99f94d7d8f9cd4ba51a1d928cbdec6873fa915236dd6d92012103aea0dfd576151cb399347aa6732f8fdf027b9ea3ea2e65fb754803f776e0a50900000000' + ) { + errorMessage += 'created tx hex doesnt match; '; + isOk = false; + } + + let feeSatoshi = new BigNumber(0.0001); + feeSatoshi = feeSatoshi.mul(100000000); + let satoshiPerByte = feeSatoshi.div(Math.round(tx.length / 2)); + satoshiPerByte = Math.round(satoshiPerByte.toString(10)); + + if (satoshiPerByte !== 46) { + errorMessage += 'created tx satoshiPerByte doesnt match; '; + isOk = false; + } + + // + + this.setState({ + isLoading: false, + isOk, + errorMessage, + }); + } + + render() { + if (this.state.isLoading) { + return ; + } + + return ( + + + + + + + {(() => { + if (this.state.isOk) { + return ( + + OK + + ); + } else { + return ( + + error: {this.state.errorMessage} + + ); + } + })()} + + + + ); + } +} + +Selftest.propTypes = {};