forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
HD wallet #1405
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
HD wallet #1405
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
c731d72
HD wallet
UdjinM6 48ad3a0
minimal bip44 (hardcoded account and change)
UdjinM6 267e9c5
Do not recreate HD wallet on encryption
UdjinM6 300e10c
Do not store any private keys for hd wallet besides the master one
UdjinM6 7e3d2e3
minimal bip39
UdjinM6 e670ee0
actually use bip39
UdjinM6 26d568e
pbkdf2 test
UdjinM6 d19f74c
backport wallet-hd.py test
UdjinM6 7386b82
Allow specifying hd seed, add dumphdseed rpc, fix bugs
UdjinM6 912946c
top up keypool on HD wallet encryption
UdjinM6 ef2aec7
split HD chain: external/internal
UdjinM6 7f0c74e
add missing cs_wallet lock in init.cpp
UdjinM6 a17ad86
fix `const char *` issues (use strings)
UdjinM6 35381df
default mnemonic passphrase is an empty string in all cases
UdjinM6 75670d8
store mnemonic/mnemonicpassphrase
UdjinM6 9db0bd3
Add fCrypted flag to CHDChain
UdjinM6 24c750e
prepare internal structures for multiple HD accounts
UdjinM6 35ab907
use secure allocator for storing sensitive HD data
UdjinM6 72d4c45
use secure strings for mnemonic(passphrase)
UdjinM6 9e1bcb1
small fix in GenerateNewHDChain
UdjinM6 3961558
use 24 words for mnemonic by default
UdjinM6 448751c
make sure mnemonic passphrase provided by user does not exceed 256 sy…
UdjinM6 87308fe
more usage of secure allocators and memory_cleanse
UdjinM6 1890734
code cleanup
UdjinM6 df6009e
rename: CSecureVector -> SecureVector
UdjinM6 6aad86e
add missing include
UdjinM6 8bd7913
fix warning in rpcdump.cpp
UdjinM6 a44db94
refactor mnemonic_check (also fix a bug)
UdjinM6 20746f0
move bip39 functions to CMnemonic
UdjinM6 4301b36
Few fixes for CMnemonic:
UdjinM6 c209dc8
init vectors with desired size where possible
UdjinM6 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| #!/usr/bin/env python2 | ||
| # coding=utf-8 | ||
| # ^^^^^^^^^^^^ TODO remove when supporting only Python3 | ||
| # Copyright (c) 2016 The Bitcoin Core developers | ||
| # Distributed under the MIT software license, see the accompanying | ||
| # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
| """Test Hierarchical Deterministic wallet function.""" | ||
|
|
||
| from test_framework.test_framework import BitcoinTestFramework | ||
| from test_framework.util import * | ||
|
|
||
| class WalletHDTest(BitcoinTestFramework): | ||
|
|
||
| def setup_chain(self): | ||
| print("Initializing test directory "+self.options.tmpdir) | ||
| initialize_chain_clean(self.options.tmpdir, 2) | ||
|
|
||
| def setup_network(self): | ||
| self.nodes = start_nodes(2, self.options.tmpdir, [['-usehd=0'], ['-usehd=1', '-keypool=0']]) | ||
| self.is_network_split = False | ||
| connect_nodes_bi(self.nodes, 0, 1) | ||
| self.is_network_split=False | ||
| self.sync_all() | ||
|
|
||
| def run_test (self): | ||
| tmpdir = self.options.tmpdir | ||
|
|
||
| # Make sure can't switch off usehd after wallet creation | ||
| stop_node(self.nodes[1],1) | ||
| try: | ||
| start_node(1, self.options.tmpdir, ['-usehd=0']) | ||
| raise AssertionError("Must not allow to turn off HD on an already existing HD wallet") | ||
| except Exception as e: | ||
| assert("dashd exited with status 1 during initialization" in str(e)) | ||
| # assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet') | ||
| # self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1]) | ||
| self.nodes[1] = start_node(1, self.options.tmpdir, ['-usehd=1', '-keypool=0']) | ||
| connect_nodes_bi(self.nodes, 0, 1) | ||
|
|
||
| # Make sure we use hd, keep chainid | ||
| chainid = self.nodes[1].getwalletinfo()['hdchainid'] | ||
| assert_equal(len(chainid), 64) | ||
|
|
||
| # create an internal key | ||
| change_addr = self.nodes[1].getrawchangeaddress() | ||
| change_addrV= self.nodes[1].validateaddress(change_addr); | ||
| assert_equal(change_addrV["hdkeypath"], "m/44'/1'/0'/1/0") #first internal child key | ||
|
|
||
| # Import a non-HD private key in the HD wallet | ||
| non_hd_add = self.nodes[0].getnewaddress() | ||
| self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add)) | ||
|
|
||
| # This should be enough to keep the master key and the non-HD key | ||
| self.nodes[1].backupwallet(tmpdir + "/hd.bak") | ||
| #self.nodes[1].dumpwallet(tmpdir + "/hd.dump") | ||
|
|
||
| # Derive some HD addresses and remember the last | ||
| # Also send funds to each add | ||
| self.nodes[0].generate(101) | ||
| hd_add = None | ||
| num_hd_adds = 300 | ||
| for i in range(num_hd_adds): | ||
| hd_add = self.nodes[1].getnewaddress() | ||
| hd_info = self.nodes[1].validateaddress(hd_add) | ||
| assert_equal(hd_info["hdkeypath"], "m/44'/1'/0'/0/"+str(i+1)) | ||
| assert_equal(hd_info["hdchainid"], chainid) | ||
| self.nodes[0].sendtoaddress(hd_add, 1) | ||
| self.nodes[0].generate(1) | ||
| self.nodes[0].sendtoaddress(non_hd_add, 1) | ||
| self.nodes[0].generate(1) | ||
|
|
||
| # create an internal key (again) | ||
| change_addr = self.nodes[1].getrawchangeaddress() | ||
| change_addrV= self.nodes[1].validateaddress(change_addr); | ||
| assert_equal(change_addrV["hdkeypath"], "m/44'/1'/0'/1/1") #second internal child key | ||
|
|
||
| self.sync_all() | ||
| assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) | ||
|
|
||
| print("Restore backup ...") | ||
| stop_node(self.nodes[1],1) | ||
| os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat") | ||
| shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat") | ||
| self.nodes[1] = start_node(1, self.options.tmpdir, ['-usehd=1', '-keypool=0']) | ||
| #connect_nodes_bi(self.nodes, 0, 1) | ||
|
|
||
| # Assert that derivation is deterministic | ||
| hd_add_2 = None | ||
| for _ in range(num_hd_adds): | ||
| hd_add_2 = self.nodes[1].getnewaddress() | ||
| hd_info_2 = self.nodes[1].validateaddress(hd_add_2) | ||
| assert_equal(hd_info_2["hdkeypath"], "m/44'/1'/0'/0/"+str(_+1)) | ||
| assert_equal(hd_info_2["hdchainid"], chainid) | ||
| assert_equal(hd_add, hd_add_2) | ||
|
|
||
| # Needs rescan | ||
| stop_node(self.nodes[1],1) | ||
| self.nodes[1] = start_node(1, self.options.tmpdir, ['-usehd=1', '-keypool=0', '-rescan']) | ||
| #connect_nodes_bi(self.nodes, 0, 1) | ||
| assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) | ||
|
|
||
| # send a tx and make sure its using the internal chain for the changeoutput | ||
| txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) | ||
| outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']; | ||
| keypath = "" | ||
| for out in outs: | ||
| if out['value'] != 1: | ||
| keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath'] | ||
|
|
||
| assert_equal(keypath[0:13], "m/44'/1'/0'/1") | ||
|
|
||
| if __name__ == '__main__': | ||
| WalletHDTest().main () |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.