Commit a68f81da4a05ed146a684c1b2a2b70a196a86aa8

Authored by Marius Hanne
1 parent e9b234227d

labels for SimpleKeyStore

Showing 3 changed files with 75 additions and 31 deletions Side-by-side Diff

lib/bitcoin/wallet/keystore.rb
... ... @@ -9,55 +9,62 @@
9 9 # [config] Hash of settings ({:file => "/foo/bar.json"})
10 10 def initialize config
11 11 @config = Hash[config.map{|k,v|[k.to_sym,v]}]
12   - @keys = {}
  12 + @keys = []
13 13 load_keys
14 14 end
15 15  
16 16 # List all stored keys.
17 17 def keys
18   - @keys.values
  18 + @keys
19 19 end
20 20  
21   - # Get key for given +addr+.
22   - def key(addr)
23   - @keys[addr]
  21 + # Get key for given +label+, +addr+ or +pubkey+.
  22 + def key(name)
  23 + find_key(name)
24 24 end
25 25  
26 26 # Generate and store a new key.
27   - def new_key
  27 + def new_key(label = nil)
28 28 key = Bitcoin::Key.generate
29   - @keys[key.addr] = key
  29 + @keys << {:label => label, :addr => key.addr, :key => key}
30 30 save_keys
31 31 key
32 32 end
33 33  
34   - def delete(addr)
35   - @keys.delete(addr)
  34 + # Delete key for given +label+, +addr+ or +pubkey+.
  35 + def delete(name)
  36 + key = find_key(name)
  37 + @keys.delete(key)
36 38 save_keys
37 39 end
38 40  
39   - # Export key for given +addr+ to base58 format.
  41 + # Export key for given +name+ to base58 format.
40 42 # (See Bitcoin::Key#to_base58)
41   - def export(addr)
42   - @keys[addr].to_base58
  43 + def export(name)
  44 + find_key(name)[:key].to_base58 rescue nil
43 45 end
44 46  
45 47 # Import key from given +base58+ string.
46 48 # (See Bitcoin::Key.from_base58)
47   - def import(base58)
  49 + def import(base58, label = nil)
48 50 key = Bitcoin::Key.from_base58(base58)
49   - @keys[key.addr] = key
  51 + @keys << {:label => label, :addr => key.addr, :key => key}
50 52 save_keys
51 53 key.addr
52 54 end
53 55  
54 56 # Load keys from file.
55   - # If file is emty this will generate a new key
  57 + # If file is empty this will generate a new key
56 58 # and store it, creating the file.
57 59 def load_keys
58 60 if File.exist?(@config[:file])
59   - data = JSON.load(File.read(@config[:file]))
60   - data.map {|a, k| @keys[a] = Bitcoin::Key.from_base58(k)}
  61 + keys = JSON.load(File.read(@config[:file]))
  62 + keys.map!{|k| Hash[k.map{|k,v| [k.to_sym, v] }]}
  63 + keys.map do |key|
  64 + key[:key] = Bitcoin::Key.new(key[:priv], key[:pub])
  65 + key[:priv], key[:pub] = nil
  66 + @keys << key
  67 + end
61 68 else
62 69 new_key; save_keys
63 70 end
... ... @@ -66,7 +73,26 @@
66 73 # Save keys to file.
67 74 def save_keys
68 75 File.open(@config[:file], 'w') do |file|
69   - file.write(Hash[@keys.map {|a, k| [a, k.to_base58]}].to_json)
  76 + keys = @keys.map do |key|
  77 + key = key.dup
  78 + key[:priv] = key[:key].priv
  79 + key[:pub] = key[:key].pub
  80 + key[:key] = nil
  81 + key
  82 + end
  83 + file.write(JSON.pretty_generate(keys))
  84 + end
  85 + end
  86 +
  87 + private
  88 +
  89 + def find_key(name)
  90 + if Bitcoin.valid_address?(name)
  91 + @keys.find{|k| k[:addr] == name }
  92 + elsif name.size == 130
  93 + @keys.find{|k| k[:key].pub == name }
  94 + else
  95 + @keys.find{|k| k[:label] == name }
70 96 end
71 97 end
72 98  
spec/bitcoin/fixtures/wallet/test1.json
1   -{"1BCRMoSpZ26Wt9igQh97ZN1mUGXF2bj7ty":"5K1fW1R2jqLN6GGSgvPp2zc8LSsFBpZagTwriYczvjdhVTrotp2"}
spec/bitcoin/wallet/keystore_spec.rb
1 1 require_relative '../spec_helper'
2   -
  2 +require 'json'
3 3 include Bitcoin
4 4 include Bitcoin::Wallet
5 5  
6 6 describe "Bitcoin::Wallet::SimpleKeyStore" do
7 7  
  8 + @test1 = [{:label => "test1", :addr => "174xCfTggAovtDezgswTgfUeCp1hWJ1i7F", :pub => "040795786162a1a2fb5bb82310fc1b0da3ced5ed8fc3495bbf848b0156eca465688b0cf08d5389c026556213b7e5ccf471d259575e1756e3352ded2a3eec6a59c8", :priv => "c04ea613926036d2782d43eca89512724c9f33f3e8484adb8b952a3837564bcb"}]
  9 +
8 10 before do
9   - @filename = File.join(File.dirname(__FILE__), '../fixtures/wallet/test1.json')
  11 + spec_dir = File.join(File.dirname(__FILE__), '../fixtures/wallet')
  12 + FileUtils.mkdir_p(spec_dir)
  13 + @filename = File.join(spec_dir, 'test1.json')
  14 + File.open(@filename, 'w') {|f| f.write(@test1.to_json) }
10 15 @ks = SimpleKeyStore.new(file: @filename)
11 16 end
12 17  
  18 + after do
  19 + File.delete(@filename) rescue nil
  20 + end
  21 +
13 22 it "should create new store" do
14 23 filename = @filename.sub('test1', 'test2')
  24 + File.open(filename, 'w') {|f| f.write(@test1.to_json) }
15 25 ks = SimpleKeyStore.new(file: filename)
16 26 ks.keys.size.should == 1
17 27 File.delete(filename) rescue nil
... ... @@ -23,6 +33,7 @@
23 33  
24 34 it "should save store" do
25 35 filename = @filename.sub('test1', 'test2')
  36 + File.open(filename, 'w') {|f| f.write(@test1.to_json) }
26 37 ks = SimpleKeyStore.new(file: filename)
27 38 ks.save_keys
28 39 ks2 = SimpleKeyStore.new(file: filename)
29 40  
30 41  
31 42  
32 43  
33 44  
34 45  
... ... @@ -32,34 +43,42 @@
32 43  
33 44 it "should create new key" do
34 45 key = @ks.new_key
35   - @ks.keys.last.should == key
  46 + @ks.keys.last.should == {:label => nil, :addr => key.addr, :key => key}
36 47 end
37 48  
38 49 it "should delete key" do
39   - @ks.delete(@ks.keys.last.addr)
40   - @ks.keys.size.should == 1
  50 + @ks.delete(@ks.keys.last[:addr])
  51 + @ks.keys.size.should == 0
41 52 end
42 53  
43 54 it "should get key" do
44   - @ks.key('1BCRMoSpZ26Wt9igQh97ZN1mUGXF2bj7ty').priv.should ==
45   - '9d87f35fa07971c0ad29ada861ecf2edb8fd06540c97562d84817ea7b3416e84'
  55 + k1 = @ks.key('174xCfTggAovtDezgswTgfUeCp1hWJ1i7F')[:key]
  56 + k2 = @ks.key('test1')[:key]
  57 + k3 = @ks.key(k2.pub)[:key]
  58 + [k1,k2,k3].each{|k| k.priv.should ==
  59 + 'c04ea613926036d2782d43eca89512724c9f33f3e8484adb8b952a3837564bcb'}
46 60 end
47 61  
48 62 it "should get keys" do
49   - @ks.keys.map(&:priv).should ==
50   - ['9d87f35fa07971c0ad29ada861ecf2edb8fd06540c97562d84817ea7b3416e84']
  63 + @ks.keys.map{|k|k[:key].priv}.should ==
  64 + ['c04ea613926036d2782d43eca89512724c9f33f3e8484adb8b952a3837564bcb']
51 65 end
52 66  
53 67 it "should export key" do
54   - @ks.export('1BCRMoSpZ26Wt9igQh97ZN1mUGXF2bj7ty').should ==
55   - '5K1fW1R2jqLN6GGSgvPp2zc8LSsFBpZagTwriYczvjdhVTrotp2'
  68 + k1 = @ks.export('174xCfTggAovtDezgswTgfUeCp1hWJ1i7F')
  69 + k2 = @ks.export('test1')
  70 + k3 = @ks.export(@ks.key('test1')[:key].pub)
  71 + [k1,k2,k3].uniq.should == ['5KGyp1k36dqprA9zBuzEJzf327vw4bTkJARcW13zAKBhAfVmeT3']
56 72 end
57 73  
58 74 it "should import key" do
59 75 @ks.import('5JUw75N58166KuA4Pb9s2iJARfu6MC7VaQtFZn523VMuXVYUVSm')
60   - @ks.key('1JovdwZKSby5q3kHLMCX3cCais5YBKVA9x').priv.should ==
  76 + @ks.key('1JovdwZKSby5q3kHLMCX3cCais5YBKVA9x')[:key].priv.should ==
61 77 '57c0aea88323c96a75e461499571482ee90d98670a023213f8000047dfa3755c'
62 78 @ks.delete('1JovdwZKSby5q3kHLMCX3cCais5YBKVA9x')
  79 + @ks.import('5JUw75N58166KuA4Pb9s2iJARfu6MC7VaQtFZn523VMuXVYUVSm', "test2")
  80 + @ks.key('test2')[:key].priv.should ==
  81 + '57c0aea88323c96a75e461499571482ee90d98670a023213f8000047dfa3755c'
63 82 end
64 83  
65 84 end