bitcoinrb 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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."