bitcoinrb 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f25b7f5ff1de3882b880e49e858f3b49bf8c13a
4
- data.tar.gz: 2a04f3a090503ffdc15d337b351c839d68b33929
3
+ metadata.gz: 3af358507bac7836acb65b028e77391acc664890
4
+ data.tar.gz: a9bcb5f19f17b9a2ecd1e5c0a43b3aa29c0329ec
5
5
  SHA512:
6
- metadata.gz: abbfff02611cb216dc843414bc7e8e9f4e9799a72314ebc3f165f6b100fa2e2d77843975b77bca8ccce3d23d7fb749eb12c62f881ac7f3635840bb68eedb9791
7
- data.tar.gz: a0a3fd06f7120bdff5c04375e1ab4214d3e962256d96f4c5f9a48811eeb5227ad602bd7ff2283c117219d3bb4d880dd529a9b0fde1567cc2ef03d2a9b2106cfd
6
+ metadata.gz: 32e8a8c8d0a1a80ec3ffcfa373f41a5d0987d83da9616a568acb5f9982bcc25a91b406f2163242e6e45d43c0f956e47913d4a280c821cc7f724da7836192b235
7
+ data.tar.gz: b476e81be5caff178b14161f0873d770c91795d59b0e0b518fcc68b8f138b525c023002b3ab3846e5ae24a9b46d61eff3ff0a32fb1b37aea4386c08ade25296e
data/exe/bitcoinrbd CHANGED
@@ -1,30 +1,36 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'thor'
3
3
  require 'bitcoin'
4
- require 'bitcoin/node/spv'
4
+ require 'daemon_spawn'
5
+
6
+ class BitcoinDaemon < DaemonSpawn::Base
7
+
8
+ def start(args)
9
+ puts "Bitcoinrb daemon start : #{Time.now}"
10
+ conf = Bitcoin::Node::Configuration.new(network: args.first[:network])
11
+ node = Bitcoin::Node::SPV.new(conf)
12
+ node.run
13
+ end
14
+
15
+ end
5
16
 
6
17
  class Bitcoinrbd < Thor
7
18
 
8
- option :mode, default: 'spv'
9
- option :network, default: 'mainnet'
10
- desc 'start', 'start bitcoinrbd daemon process'
19
+ class_option :network, aliases: '-n', default: :mainnet
20
+
21
+ desc 'start', 'start bitcoinrb daemon.'
11
22
  def start
12
- raise ArgumentError, 'currently only support spv mode.' unless options[:mode] == 'spv'
13
- Bitcoin.chain_params = network.to_sym
23
+ network = options['network'] ? options['network'].to_sym : :mainnet
24
+ Bitcoin.chain_params = network
14
25
  FileUtils.mkdir_p(Bitcoin.base_dir)
15
- execute_daemon(['start'])
26
+ execute_daemon(['start', network: network])
16
27
  end
17
28
 
18
- option :mode, default: 'spv'
19
- option :network, default: 'mainnet'
20
- desc 'stop', 'start bitcoinrbd daemon process'
21
- def stop
22
- execute_daemon(['stop'])
23
- end
29
+ private
24
30
 
25
31
  def execute_daemon(cmd_args)
26
- Bitcoin::Nodes::SPV.spawn!({working_dir: Bitcoin.base_dir,
27
- log_file: "#{Bitcoin.base_dir}/bitcoinrbd.log",
32
+ BitcoinDaemon.spawn!({working_dir: Bitcoin.base_dir,
33
+ log_file: "#{Bitcoin.base_dir}/log/bitcoinrbd.log",
28
34
  pid_file: "#{Bitcoin.base_dir}/bitcoinrbd.pid",
29
35
  sync_log: true,
30
36
  singleton: true}, cmd_args)
@@ -24,6 +24,7 @@ module Bitcoin
24
24
  attr_reader :proof_of_work_limit
25
25
  attr_reader :dns_seeds
26
26
  attr_reader :genesis
27
+ attr_reader :bip44_coin_type
27
28
 
28
29
  # mainnet genesis
29
30
  def self.mainnet
@@ -30,3 +30,4 @@ genesis:
30
30
  bits: 0x1d00ffff
31
31
  version: 1
32
32
  prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
33
+ bip44_coin_type: 0
@@ -25,4 +25,5 @@ genesis:
25
25
  nonce: 2
26
26
  bits: 0x207fffff
27
27
  version: 1
28
- prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
28
+ prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
29
+ bip44_coin_type: 1
@@ -29,4 +29,5 @@ genesis:
29
29
  nonce: 414098458
30
30
  bits: 0x1d00ffff
31
31
  version: 1
32
- prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
32
+ prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
33
+ bip44_coin_type: 1
@@ -64,6 +64,10 @@ module Bitcoin
64
64
  key.pubkey
65
65
  end
66
66
 
67
+ def hash160
68
+ Bitcoin.hash160(pub)
69
+ end
70
+
67
71
  # get address
68
72
  def addr
69
73
  key.to_p2pkh
@@ -84,6 +88,11 @@ module Bitcoin
84
88
  identifier.slice(0..7)
85
89
  end
86
90
 
91
+ # whether hardened key.
92
+ def hardened?
93
+ number >= 2**31
94
+ end
95
+
87
96
  # derive new key
88
97
  def derive(number)
89
98
  new_key = ExtKey.new
@@ -139,6 +148,10 @@ module Bitcoin
139
148
  pubkey
140
149
  end
141
150
 
151
+ def hash160
152
+ Bitcoin.hash160(pub)
153
+ end
154
+
142
155
  # get address
143
156
  def addr
144
157
  Bitcoin::Key.new(pubkey: pubkey).to_p2pkh
@@ -171,6 +184,11 @@ module Bitcoin
171
184
  Base58.encode(hex)
172
185
  end
173
186
 
187
+ # whether hardened key.
188
+ def hardened?
189
+ number >= 2**31
190
+ end
191
+
174
192
  # derive child key
175
193
  def derive(number)
176
194
  new_key = ExtPubkey.new
@@ -107,6 +107,7 @@ module Bitcoin
107
107
  end
108
108
 
109
109
  def handshake_done
110
+ return unless @incomming_handshake && @outgoing_handshake
110
111
  logger.info 'handshake finished.'
111
112
  @connected = true
112
113
  post_handshake
@@ -116,10 +117,13 @@ module Bitcoin
116
117
  logger.info("receive version message. #{version.build_json}")
117
118
  @version = version
118
119
  send_message(Bitcoin::Message::VerAck.new)
120
+ @incomming_handshake = true
121
+ handshake_done
119
122
  end
120
123
 
121
124
  def on_ver_ack
122
125
  logger.info('receive verack message.')
126
+ @outgoing_handshake = true
123
127
  handshake_done
124
128
  end
125
129
 
@@ -35,6 +35,16 @@ module Bitcoin
35
35
  request('sendrawtransaction', hex_tx)
36
36
  end
37
37
 
38
+ desc 'createwallet "wallet_id"', 'Create new HD wallet. It returns an error if an existing wallet_id is specified. '
39
+ def createwallet(wallet_id)
40
+ request('createwallet', wallet_id)
41
+ end
42
+
43
+ desc 'listwallets', 'Returns a list of currently loaded wallets. For full information on the wallet, use "getwalletinfo"'
44
+ def listwallets
45
+ request('listwallets')
46
+ end
47
+
38
48
  private
39
49
 
40
50
  def config
@@ -53,8 +63,12 @@ module Bitcoin
53
63
  RestClient::Request.execute(method: :post, url: config.server_url, payload: data.to_json,
54
64
  headers: {content_type: :json}) do |response, request, result|
55
65
  return false if !result.kind_of?(Net::HTTPSuccess) && response.empty?
56
- json = JSON.parse(response.to_str)
57
- puts JSON.pretty_generate(json)
66
+ begin
67
+ json = JSON.parse(response.to_str)
68
+ puts JSON.pretty_generate(json)
69
+ rescue Exception
70
+ puts response.to_str
71
+ end
58
72
  end
59
73
  rescue Exception => e
60
74
  puts e.message
@@ -31,13 +31,22 @@ module Bitcoin
31
31
  operation = proc {
32
32
  command, args = parse_json_params
33
33
  logger.debug("process http request. command = #{command}")
34
- send(command, *args).to_json
34
+ begin
35
+ send(command, *args).to_json
36
+ rescue Exception => e
37
+ e
38
+ end
35
39
  }
36
40
  callback = proc{ |result|
37
41
  response = EM::DelegatedHttpResponse.new(self)
38
- response.status = 200
42
+ if result.is_a?(Exception)
43
+ response.status = 500
44
+ response.content = result.message
45
+ else
46
+ response.status = 200
47
+ response.content = result
48
+ end
39
49
  response.content_type 'application/json'
40
- response.content = result
41
50
  response.send_response
42
51
  }
43
52
  EM.defer(operation, callback)
@@ -78,6 +78,20 @@ module Bitcoin
78
78
  tx.txid
79
79
  end
80
80
 
81
+ # wallet api
82
+
83
+ # create wallet
84
+ def createwallet(wallet_id = 1, wallet_path_prefix = Bitcoin::Wallet::Base::DEFAULT_PATH_PREFIX)
85
+ wallet = Bitcoin::Wallet::Base.create(wallet_id, wallet_path_prefix)
86
+ node.wallet = wallet unless node.wallet
87
+ {wallet_id: wallet.wallet_id, mnemonic: wallet.master_key.mnemonic}
88
+ end
89
+
90
+ # get wallet list.
91
+ def listwallets(wallet_path_prefix = Bitcoin::Wallet::Base::DEFAULT_PATH_PREFIX)
92
+ Bitcoin::Wallet::Base.wallet_paths(wallet_path_prefix)
93
+ end
94
+
81
95
  end
82
96
 
83
97
  end
@@ -413,8 +413,7 @@ module Bitcoin
413
413
  return nil unless p2pkh?
414
414
  hash160 = chunks[2].pushed_data.bth
415
415
  return nil unless hash160.htb.bytesize == 20
416
- hex = Bitcoin.chain_params.address_version + hash160
417
- Bitcoin.encode_base58_address(hex)
416
+ Bitcoin.encode_base58_address(hash160, Bitcoin.chain_params.address_version)
418
417
  end
419
418
 
420
419
  # generate p2wpkh address. if script dose not p2wpkh, return nil.
@@ -427,8 +426,7 @@ module Bitcoin
427
426
  return nil unless p2sh?
428
427
  hash160 = chunks[1].pushed_data.bth
429
428
  return nil unless hash160.htb.bytesize == 20
430
- hex = Bitcoin.chain_params.p2sh_version + hash160
431
- Bitcoin.encode_base58_address(hex)
429
+ Bitcoin.encode_base58_address(hash160, Bitcoin.chain_params.p2sh_version)
432
430
  end
433
431
 
434
432
  # generate p2wsh address. if script dose not p2wsh, return nil.
data/lib/bitcoin/util.rb CHANGED
@@ -82,12 +82,9 @@ module Bitcoin
82
82
  Digest::RMD160.hexdigest(Digest::SHA256.digest(hex.htb))
83
83
  end
84
84
 
85
- def encode_base58_address(hex)
86
- Base58.encode(hex + calc_checksum(hex))
87
- end
88
-
89
- def decode_base58_address(addr)
90
- Base58.decode(addr)
85
+ def encode_base58_address(hex, addr_version)
86
+ base = addr_version + hex
87
+ Base58.encode(base + calc_checksum(base))
91
88
  end
92
89
 
93
90
  def calc_checksum(hex)
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -9,12 +9,12 @@ module Bitcoin
9
9
  attr_reader :purpose # either 44 or 49
10
10
  attr_reader :index # BIP-44 index
11
11
  attr_reader :name # account name
12
- attr_accessor :receive_depth # receive address depth
13
- attr_accessor :change_depth # change address depth
12
+ attr_accessor :receive_depth # receive address depth(address index)
13
+ attr_accessor :change_depth # change address depth(address index)
14
14
  attr_accessor :lookahead
15
15
  attr_accessor :wallet
16
16
 
17
- def initialize(purpose = PURPOSE_TYPE[:legacy], index = 0, name = '')
17
+ def initialize(purpose = PURPOSE_TYPE[:nested_witness], index = 0, name = '')
18
18
  @purpose = purpose
19
19
  @index = index
20
20
  @name = name
@@ -46,22 +46,20 @@ module Bitcoin
46
46
  end
47
47
 
48
48
  def init
49
- lookahead.times do |index|
50
- derive_receive(index)
51
- derive_change(index)
52
- end
49
+ @receive_depth = lookahead
50
+ @change_depth = lookahead
53
51
  @index = wallet.accounts.size
54
52
  save
55
53
  end
56
54
 
57
55
  # derive receive key
58
- def derive_receive(index)
59
- derive(0, index)
56
+ def derive_receive(address_index)
57
+ derive_path(0, address_index)
60
58
  end
61
59
 
62
60
  # derive change key
63
- def derive_change(index)
64
- derive(1, index)
61
+ def derive_change(address_index)
62
+ derive_path(1, address_index)
65
63
  end
66
64
 
67
65
  # save this account payload to database.
@@ -69,11 +67,27 @@ module Bitcoin
69
67
  wallet.db.save_account(self)
70
68
  end
71
69
 
70
+ # get the list of derived keys for receive key.
71
+ def derived_receive_keys
72
+ receive_depth.times.map{|i|derive_key(0,i)}
73
+ end
74
+
75
+ # get the list of derived keys for change key.
76
+ def derived_change_keys
77
+ receive_depth.times.map{|i|derive_key(1,i)}
78
+ end
79
+
72
80
  private
73
81
 
74
- # derive key
75
- def derive(branch, index)
82
+ def derive_key(branch, address_index)
83
+ account_key.derive(branch).derive(address_index)
84
+ end
76
85
 
86
+ def account_key
87
+ return @cached_account_key if @cached_account_key
88
+ coin_type = Bitcoin.chain_params.bip44_coin_type
89
+ # m / purpose' / coin_type' / account_index'
90
+ @cached_account_key = wallet.master_key.key.derive(2**31 + purpose).derive(2**31 + coin_type).derive(2**31 + index)
77
91
  end
78
92
 
79
93
  end
@@ -6,8 +6,9 @@ module Bitcoin
6
6
 
7
7
  attr_accessor :wallet_id
8
8
  attr_reader :db
9
+ attr_reader :path
9
10
 
10
- DEFAULT_PATH_PREFIX = "#{Bitcoin.base_dir}/db/wallet"
11
+ DEFAULT_PATH_PREFIX = "#{Bitcoin.base_dir}/db/wallet/"
11
12
 
12
13
  # Create new wallet. If wallet already exist, throw error.
13
14
  # The wallet generates a seed using SecureRandom and store to db at initialization.
@@ -21,6 +22,7 @@ module Bitcoin
21
22
  raise RuntimeError, 'the seed already exist.' if w.db.registered_master?
22
23
  master = Bitcoin::Wallet::MasterKey.generate
23
24
  w.db.register_master_key(master)
25
+ w.create_account('Default')
24
26
  w
25
27
  end
26
28
 
@@ -31,12 +33,22 @@ module Bitcoin
31
33
  self.new(wallet_id, path_prefix)
32
34
  end
33
35
 
36
+ # get wallets path
37
+ # @return [Array] Array of paths for each wallet dir.
38
+ def self.wallet_paths(path_prefix = DEFAULT_PATH_PREFIX)
39
+ Dir.glob("#{path_prefix}wallet*/")
40
+ end
41
+
34
42
  # get account list based on BIP-44
35
43
  def accounts
36
- db.accounts.map{|raw| Account.parse_from_payload(raw)}
44
+ db.accounts.map do |raw|
45
+ a = Account.parse_from_payload(raw)
46
+ a.wallet = self
47
+ a
48
+ end
37
49
  end
38
50
 
39
- def create_account(purpose = Account::PURPOSE_TYPE[:legacy], index = 0, name)
51
+ def create_account(purpose = Account::PURPOSE_TYPE[:nested_witness], index = 0, name)
40
52
  account = Account.new(purpose, index, name)
41
53
  account.wallet = self
42
54
  account.init
@@ -69,12 +81,13 @@ module Bitcoin
69
81
  private
70
82
 
71
83
  def initialize(wallet_id, path_prefix)
72
- @db = Bitcoin::Wallet::DB.new("#{path_prefix}_#{wallet_id}")
84
+ @path = "#{path_prefix}wallet#{wallet_id}/"
85
+ @db = Bitcoin::Wallet::DB.new(@path)
73
86
  @wallet_id = wallet_id
74
87
  end
75
88
 
76
89
  def self.exist?(wallet_id, path_prefix)
77
- path = "#{path_prefix}_#{wallet_id}"
90
+ path = "#{path_prefix}wallet#{wallet_id}"
78
91
  Dir.exist?(path)
79
92
  end
80
93
 
@@ -21,7 +21,7 @@ module Bitcoin
21
21
  # generate new master key.
22
22
  # @return Bitcoin::Wallet::MasterKey
23
23
  def self.generate
24
- entropy = SecureRandom.hex(16)
24
+ entropy = SecureRandom.hex(32)
25
25
  mnemonic = Bitcoin::Mnemonic.new('english')
26
26
  self.recover_from_words(mnemonic.to_mnemonic(entropy))
27
27
  end
@@ -42,6 +42,7 @@ module Bitcoin
42
42
  flag, payload = unpack_var_int(payload)
43
43
  raise 'encrypted flag is invalid.' unless [0, 1].include?(flag)
44
44
  salt, payload = unpack_var_string(payload)
45
+ salt = '' unless salt
45
46
  seed, payload = unpack_var_string(payload)
46
47
  self.new(seed.bth, salt: salt.bth, encrypted: flag == 1)
47
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoinrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-02 00:00:00.000000000 Z
11
+ date: 2017-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa
@@ -373,7 +373,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
373
373
  version: '0'
374
374
  requirements: []
375
375
  rubyforge_project:
376
- rubygems_version: 2.6.12
376
+ rubygems_version: 2.6.13
377
377
  signing_key:
378
378
  specification_version: 4
379
379
  summary: "[WIP]The implementation of Bitcoin Protocol for Ruby."