bitcoin 0.1.2 → 0.2.0

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.
Files changed (68) hide show
  1. metadata +17 -288
  2. data/.rspec +0 -1
  3. data/.rvmrc +0 -1
  4. data/Gemfile +0 -4
  5. data/Gemfile.lock +0 -98
  6. data/Guardfile +0 -38
  7. data/README.markdown +0 -24
  8. data/Rakefile +0 -1
  9. data/bin/rbcoin +0 -8
  10. data/bitcoin.gemspec +0 -40
  11. data/config/cucumber.yml +0 -5
  12. data/config/darcs.boring +0 -121
  13. data/doc/DEFINITION_OF_DONE.markdown +0 -12
  14. data/doc/HISTORY.markdown +0 -19
  15. data/doc/LICENCE.markdown +0 -25
  16. data/doc/TODO.markdown +0 -31
  17. data/doc/UBIQUITOUS_LANGUAGE.markdown +0 -15
  18. data/features/descriptions/command_help.feature +0 -31
  19. data/features/descriptions/satoshi_wallet/add_address.feature +0 -49
  20. data/features/descriptions/satoshi_wallet/show_addresses.feature +0 -18
  21. data/features/descriptions/satoshi_wallet/show_version.feature +0 -17
  22. data/features/descriptions/satoshi_wallet/subcommand_help.feature +0 -20
  23. data/features/fixtures/ABOUT_FIXTURES.markdown +0 -6
  24. data/features/fixtures/addressbook_wallet.dat +0 -0
  25. data/features/fixtures/new_wallet.dat +0 -0
  26. data/features/step_definitions/command_steps.rb +0 -3
  27. data/features/step_definitions/wallet_steps.rb +0 -11
  28. data/features/support/env.rb +0 -9
  29. data/lib/bitcoin.rb +0 -5
  30. data/lib/bitcoin/cli.rb +0 -35
  31. data/lib/bitcoin/commands.rb +0 -3
  32. data/lib/bitcoin/commands/help_command.rb +0 -32
  33. data/lib/bitcoin/commands/satoshi_wallet.rb +0 -11
  34. data/lib/bitcoin/commands/satoshi_wallet/add_address_command.rb +0 -61
  35. data/lib/bitcoin/commands/satoshi_wallet/show_addresses_command.rb +0 -16
  36. data/lib/bitcoin/commands/satoshi_wallet/show_version_command.rb +0 -15
  37. data/lib/bitcoin/commands/satoshi_wallet_command.rb +0 -37
  38. data/lib/bitcoin/commands/satoshi_wallet_command_environment.rb +0 -28
  39. data/lib/bitcoin/console/capturing_stream_bundle.rb +0 -42
  40. data/lib/bitcoin/console/stream_bundle.rb +0 -21
  41. data/lib/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository.rb +0 -155
  42. data/lib/bitcoin/data_access/satoshi/satoshi_version.rb +0 -58
  43. data/lib/bitcoin/data_access/satoshi/satoshi_wallet.rb +0 -39
  44. data/lib/bitcoin/domain/address_book.rb +0 -19
  45. data/lib/bitcoin/domain/bitcoin_address.rb +0 -33
  46. data/lib/bitcoin/filesystem/empty_temp_dir.rb +0 -74
  47. data/lib/bitcoin/rspec/argument_matchers.rb +0 -1
  48. data/lib/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher.rb +0 -23
  49. data/lib/bitcoin/rspec/directory_helpers.rb +0 -22
  50. data/lib/bitcoin/version.rb +0 -3
  51. data/spec/bitcoin/cli_spec.rb +0 -128
  52. data/spec/bitcoin/commands/help_command_spec.rb +0 -53
  53. data/spec/bitcoin/commands/satoshi_wallet/add_address_command_spec.rb +0 -149
  54. data/spec/bitcoin/commands/satoshi_wallet/show_addresses_command_spec.rb +0 -26
  55. data/spec/bitcoin/commands/satoshi_wallet/show_version_command_spec.rb +0 -26
  56. data/spec/bitcoin/commands/satoshi_wallet_command_environment_spec.rb +0 -76
  57. data/spec/bitcoin/commands/satoshi_wallet_command_spec.rb +0 -73
  58. data/spec/bitcoin/console/_contracts/stream_bundle_contract.rb +0 -29
  59. data/spec/bitcoin/console/capturing_stream_bundle_spec.rb +0 -74
  60. data/spec/bitcoin/console/stream_bundle_spec.rb +0 -13
  61. data/spec/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository_spec.rb +0 -78
  62. data/spec/bitcoin/data_access/satoshi/satoshi_version_spec.rb +0 -112
  63. data/spec/bitcoin/data_access/satoshi/satoshi_wallet_spec.rb +0 -102
  64. data/spec/bitcoin/domain/address_book_spec.rb +0 -63
  65. data/spec/bitcoin/domain/bitcoin_address_spec.rb +0 -52
  66. data/spec/bitcoin/filesystem/empty_temp_dir_spec.rb +0 -170
  67. data/spec/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher_spec.rb +0 -36
  68. data/spec/spec_helper.rb +0 -29
@@ -1,6 +0,0 @@
1
- # About the fixtures
2
-
3
- Fixtures are bad, mmmkay?
4
-
5
- But until we have a bulletproof means of writing a full and correct Satoshi Wallet
6
- file, it's safer to use fixtures than to rely on our unproven Berkeley DB code.
@@ -1,3 +0,0 @@
1
- Then %r/the command should fail/ do
2
- Then "the exit status should be 1"
3
- end
@@ -1,11 +0,0 @@
1
- module Fixtures
2
- def fixture_file_data(filename)
3
- File.read(File.join(PROJECT_ROOT, "features", "fixtures", filename))
4
- end
5
- end
6
-
7
- World(Fixtures)
8
-
9
- Given %r/^a new Satoshi Wallet "([^"]*)"$/ do |wallet_filename|
10
- write_file(wallet_filename, fixture_file_data(wallet_filename))
11
- end
@@ -1,9 +0,0 @@
1
- require 'bundler'
2
- Bundler.setup
3
-
4
- PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), "..", "..")).freeze
5
-
6
- # So Aruba can find the binary
7
- ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
8
-
9
- require 'aruba/cucumber'
@@ -1,5 +0,0 @@
1
- require "bitcoin/version"
2
-
3
- module Bitcoin
4
- # Your code goes here...
5
- end
@@ -1,35 +0,0 @@
1
- require 'bitcoin/commands'
2
-
3
- module Bitcoin
4
- class CLI
5
- class CommandError < RuntimeError; end
6
-
7
- def initialize(stream_bundle)
8
- @stream_bundle = stream_bundle
9
- end
10
-
11
- def run(args)
12
- command_name, *remaining_args = *args
13
- dispatch_command(command_name, remaining_args)
14
- rescue CommandError => error
15
- 1
16
- else
17
- 0
18
- end
19
-
20
- private
21
-
22
- def dispatch_command(command_name, remaining_args)
23
- case command_name
24
- when nil, "help"
25
- Commands::HelpCommand.new(@stream_bundle).show_help
26
- when "satoshi-wallet"
27
- command_environment = Commands::SatoshiWalletCommandEnvironment.new(@stream_bundle)
28
- Commands::SatoshiWalletCommand.new(@stream_bundle, command_environment).run(remaining_args)
29
- else
30
- Commands::HelpCommand.new(@stream_bundle).show_unknown_command_help(command_name)
31
- raise CommandError.new
32
- end
33
- end
34
- end
35
- end
@@ -1,3 +0,0 @@
1
- require_relative 'commands/help_command'
2
- require_relative 'commands/satoshi_wallet_command'
3
- require_relative 'commands/satoshi_wallet_command_environment'
@@ -1,32 +0,0 @@
1
- require 'lstrip-on-steroids'
2
-
3
- module Bitcoin
4
- module Commands
5
- class HelpCommand
6
- def initialize(stream_bundle)
7
- @stream_bundle = stream_bundle
8
- end
9
-
10
- def show_help
11
- @stream_bundle.puts_output(
12
- -%{
13
- Usage: rbcoin COMMAND ...
14
-
15
- Commands:
16
- help Display help about rbcoin and rbcoin commands
17
- satoshi-wallet Manipulate the wallet.dat file of the original client
18
-
19
- Use "rbcoin COMMAND --help" or "rbcoin help COMMAND" for help on a single command
20
- Use "rbcoin --version" to see the rbcoin version number
21
- Use "rbcoin --exact-version" to see the all version details (with dependencies)
22
- }
23
- )
24
- end
25
-
26
- def show_unknown_command_help(command_name)
27
- @stream_bundle.puts_output(%'rbcoin failed: No such command "#{command_name}"')
28
- @stream_bundle.puts_output("Try: `rbcoin help`")
29
- end
30
- end
31
- end
32
- end
@@ -1,11 +0,0 @@
1
- module Bitcoin
2
- module Commands
3
- module SatoshiWallet
4
-
5
- end
6
- end
7
- end
8
-
9
- require_relative 'satoshi_wallet/add_address_command'
10
- require_relative 'satoshi_wallet/show_addresses_command'
11
- require_relative 'satoshi_wallet/show_version_command'
@@ -1,61 +0,0 @@
1
- require 'bitcoin/cli' # For CommandError
2
-
3
- require 'bitcoin/domain/bitcoin_address'
4
-
5
- module Bitcoin
6
- module Commands
7
- module SatoshiWallet
8
- class AddAddressCommand
9
- def initialize(stream_bundle)
10
- @stream_bundle = stream_bundle
11
- end
12
-
13
- def run(wallet, options)
14
- assert_valid_args(options[:args])
15
-
16
- address, name = *options[:args]
17
-
18
- assert_valid_name(name)
19
-
20
- wallet.add_address(Domain::BitcoinAddress.new(address), name: name)
21
- @stream_bundle.puts_output("Address added successfully")
22
- rescue Domain::BitcoinAddress::InvalidBitcoinAddressError => error
23
- @stream_bundle.puts_error(error.message)
24
- @stream_bundle.puts_error("The address was not added to the wallet")
25
- raise CLI::CommandError.new
26
- end
27
-
28
- private
29
-
30
- def assert_valid_args(args)
31
- if args.length < 2
32
- @stream_bundle.puts_error("You must provide both a Bitcoin address and a name to add to a wallet")
33
- @stream_bundle.puts_error("No changes were made to the wallet")
34
- raise CLI::CommandError.new
35
- elsif args.length > 2
36
- @stream_bundle.puts_error(
37
- -%{
38
- Received too many arguments
39
-
40
- To make sure the name is formatted correctly we ask you to use use quotes
41
- around the name, e.g.: "#{args.drop(1).join(" ")}"
42
-
43
- No changes were made to the wallet
44
- }
45
- )
46
- raise CLI::CommandError.new
47
- end
48
-
49
- def assert_valid_name(name)
50
- if name.bytesize > 252
51
- @stream_bundle.puts_error(%'The address name "#{name}" is too long\n')
52
- @stream_bundle.puts_error("Currently we do not allow address names over 252 bytes long\n")
53
- @stream_bundle.puts_error("The address was not added to the wallet\n")
54
- raise CLI::CommandError.new
55
- end
56
- end
57
- end
58
- end
59
- end
60
- end
61
- end
@@ -1,16 +0,0 @@
1
- module Bitcoin
2
- module Commands
3
- module SatoshiWallet
4
- class ShowAddressesCommand
5
- def initialize(stream_bundle)
6
- @stream_bundle = stream_bundle
7
- end
8
-
9
- def run(wallet, options)
10
- @stream_bundle.puts_output("# All addresses in #{options[:wallet_filename]}")
11
- @stream_bundle.puts_output(wallet.addresses)
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,15 +0,0 @@
1
- module Bitcoin
2
- module Commands
3
- module SatoshiWallet
4
- class ShowVersionCommand
5
- def initialize(stream_bundle)
6
- @stream_bundle = stream_bundle
7
- end
8
-
9
- def run(wallet, options = { })
10
- @stream_bundle.puts_output(wallet.version)
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,37 +0,0 @@
1
- require 'tmpdir'
2
-
3
- require 'bitcoin/cli' # circular dependency on CLI for CommandError
4
- require 'bitcoin/commands/satoshi_wallet'
5
- require 'bitcoin/data_access/satoshi/satoshi_wallet'
6
- require 'bitcoin/domain/bitcoin_address'
7
- require 'bitcoin/filesystem/empty_temp_dir'
8
-
9
- module Bitcoin
10
- module Commands
11
- class SatoshiWalletCommand
12
- TEMP_DB_PATH = "bitcoinrb_db_tmp"
13
-
14
- def initialize(stream_bundle, command_environment)
15
- @stream_bundle = stream_bundle
16
- @command_environment = command_environment
17
- end
18
-
19
- def run(args)
20
- command_name, *remaining_args = *args
21
- command_class =
22
- case command_name
23
- when "add-address"
24
- SatoshiWallet::AddAddressCommand
25
- when "show-addresses"
26
- SatoshiWallet::ShowAddressesCommand
27
- when "show-version"
28
- SatoshiWallet::ShowVersionCommand
29
- else
30
- @stream_bundle.puts_error(%'Unknown satoshi-wallet subcommand: "#{command_name}"')
31
- raise CLI::CommandError.new
32
- end
33
- @command_environment.run_command(command_class.new(@stream_bundle), remaining_args)
34
- end
35
- end
36
- end
37
- end
@@ -1,28 +0,0 @@
1
- require 'bitcoin/filesystem/empty_temp_dir'
2
-
3
- module Bitcoin
4
- module Commands
5
- class SatoshiWalletCommandEnvironment
6
- def initialize(stream_bundle)
7
- @stream_bundle = stream_bundle
8
- end
9
-
10
- def run_command(command, arguments)
11
- wallet_filename, *remaining_args = *arguments
12
-
13
- if !File.exist?(wallet_filename)
14
- @stream_bundle.puts_error("Couldn't find wallet file: #{wallet_filename}")
15
- raise CLI::CommandError.new
16
- end
17
-
18
- absolute_wallet_path = File.expand_path(wallet_filename)
19
-
20
- FileSystem::EmptyTempDir.open(with_name: "bitcoinrb_db_tmp", parallel_to: absolute_wallet_path) do |temp_dir|
21
- DataAccess::Satoshi::SatoshiWallet.open(wallet_filename: absolute_wallet_path, db_dirname: temp_dir.absolute_path) do |wallet|
22
- command.run(wallet, wallet_filename: wallet_filename, args: remaining_args)
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,42 +0,0 @@
1
- require_relative 'stream_bundle'
2
-
3
- module Bitcoin
4
- module Console
5
- # CapturingStreamBundles are StreamBundles that record the data written to them
6
- # for easy inspection later. They are useful for testing purposes.
7
- class CapturingStreamBundle
8
- class << self
9
- def test_bundle
10
- new(StringIO.new, StringIO.new, StringIO.new)
11
- end
12
- end
13
-
14
- def initialize(input, output, error)
15
- @stream_bundle = StreamBundle.new(input, output, error)
16
-
17
- @captured_output = StringIO.new
18
- @captured_error = StringIO.new
19
- end
20
-
21
- def puts_output(stringlike)
22
- @stream_bundle.puts_output(stringlike)
23
- @captured_output.puts(stringlike)
24
- end
25
-
26
- def puts_error(stringlike)
27
- @stream_bundle.puts_error(stringlike)
28
- @captured_error.puts(stringlike)
29
- end
30
-
31
- def captured_output
32
- @captured_output.rewind
33
- @captured_output.read
34
- end
35
-
36
- def captured_error
37
- @captured_error.rewind
38
- @captured_error.read
39
- end
40
- end
41
- end
42
- end
@@ -1,21 +0,0 @@
1
- module Bitcoin
2
- module Console
3
- # StreamBundles are objects that encapsulate the standard unix pipes
4
- # (STDIN, STDOUT, STDERR)
5
- class StreamBundle
6
- def initialize(input, output, error)
7
- @input = input
8
- @output = output
9
- @error = error
10
- end
11
-
12
- def puts_output(stringlike)
13
- @output.puts(stringlike)
14
- end
15
-
16
- def puts_error(stringlike)
17
- @error.puts(stringlike)
18
- end
19
- end
20
- end
21
- end
@@ -1,155 +0,0 @@
1
- require 'sbdb'
2
- require 'bdb/base'
3
-
4
- module Bitcoin
5
- module DataAccess
6
- module Satoshi
7
- # Raw Berkeley DB access (thin wrapper around SBDB) for wallet data
8
- # WARNING! This code is in really bad shape. It works, but is verbose
9
- # and full of duplication. It needs massive refactoring.
10
- class BDBSatoshiWalletRepository
11
- def initialize(db_filename, options)
12
- @db_filename = db_filename
13
- @db_dirname = options[:db_dirname]
14
- end
15
-
16
- def bdb_bytes_to_utf8_string(bytes)
17
- bytes.pack("C*").force_encoding("UTF-8")
18
- end
19
-
20
- def get_value_immediate_uint32le(key_name)
21
- with_bdb_db do |db|
22
- db[make_key(key_name)].unpack("V").first
23
- end
24
- end
25
-
26
- def set_value_immediate_uint32le(key_name, value_data)
27
- with_bdb_db do |db|
28
- db[make_key(key_name)] = [ value_data ].pack("V")
29
- end
30
- end
31
-
32
- def get_key_and_value_data_string_utf8(key_name)
33
- with_bdb_db do |db|
34
- db_records(db).select { |record|
35
- record.first == key_name
36
- }.map { |name, data_hash|
37
- data_hash
38
- }.map { |data_hash|
39
- [ data_hash[:key_data], data_hash[:value_data] ].map { |value|
40
- bdb_bytes_to_utf8_string(value)
41
- }
42
- }
43
- end
44
- end
45
-
46
- def get_value_with_key_data_string_utf8(key_name, key_data)
47
- with_bdb_db do |db|
48
- value_data = db[make_key_with_data(key_name, key_data)]
49
- return unless value_data
50
- value_bytes = value_data.unpack("C*")
51
- value_bytes.shift(read_compact_size(value_bytes)).pack("C*")
52
- end
53
- end
54
-
55
- def set_value_with_key_data_string_utf8(key_name, key_data, value_data)
56
- with_bdb_db do |db|
57
- db[make_key_with_data(key_name, key_data)] = make_key(value_data)
58
- end
59
- end
60
-
61
- def make_key(key_name)
62
- key = [ ]
63
- key << write_compact_size(key_name)
64
- key.concat(key_name.unpack("C*"))
65
- key.pack("C*")
66
- end
67
-
68
- def make_key_with_data(key_name, key_data)
69
- make_key(key_name) + make_key(key_data)
70
- end
71
-
72
- # Maybe allow changing read/write & read-only when calling this?
73
- def with_bdb_env(&block)
74
- # This doesn't yet exactly mirror the DB setup in CWalletDB::LoadWallet
75
- SBDB::Env.new(
76
- dir: File.expand_path(@db_dirname),
77
- lg_max: 10_000_000,
78
- flags: Bdb::DB_CREATE | # Create the environment if it does not already exist.
79
- Bdb::DB_INIT_LOCK | # Initialize locking.
80
- Bdb::DB_INIT_LOG | # Initialize logging
81
- Bdb::DB_INIT_MPOOL | # Initialize the in-memory cache.
82
- Bdb::DB_INIT_TXN | # Initialize transactions
83
- Bdb::DB_THREAD | # TODO: What?
84
- Bdb::DB_RECOVER # TODO: What?
85
- ) do |env|
86
- yield env
87
- end
88
- end
89
-
90
- def with_bdb_db(&block)
91
- with_bdb_env do |env|
92
- bitcoin_logical_database_name = "main"
93
- # Leaving this here for reference: we could offer a read-only mode if we wanted (see Env flags though)
94
- read_write_flags = Bdb::DB_CREATE | Bdb::DB_AUTO_COMMIT
95
- read_only_flags = Bdb::DB_RDONLY
96
- env.open(SBDB::Btree, File.expand_path(@db_filename), name: bitcoin_logical_database_name, flags: read_write_flags) do |db|
97
- yield db
98
- end
99
- end
100
- end
101
-
102
- def db_records(db)
103
- db.to_hash.map { |key, value|
104
- # Key name
105
- key_bytes = key.bytes.to_a
106
- key_name_length = read_compact_size(key_bytes)
107
- key_name = key_bytes.shift(key_name_length).pack("C*").force_encoding("UTF-8")
108
-
109
- # Key data
110
- key_data_length = read_compact_size(key_bytes)
111
- key_data_raw = key_bytes.shift(key_data_length)
112
-
113
- # Value data
114
- value_bytes = value.bytes.to_a
115
- value_data_raw =
116
- case key_name
117
- when "version" # values that don't start with a length
118
- value_bytes
119
- else # variable-length values
120
- value_length = read_compact_size(value_bytes)
121
- value_bytes.shift(value_length)
122
- end
123
-
124
- [ key_name, { key_data: key_data_raw, value_data: value_data_raw } ]
125
- }
126
- end
127
-
128
- def write_compact_size(string)
129
- string.bytesize
130
- end
131
-
132
- def read_compact_size(byte_array)
133
- # The Satoshi client throws an error here if the determined length is greater
134
- # than (uint64)MAX_SIZE - I don't know if we need to worry about it
135
-
136
- byte_1 = byte_array.shift
137
- if byte_1.nil?
138
- 0
139
- elsif byte_1 < 253
140
- byte_1
141
- elsif byte_1 == 253
142
- # Little-endian 16-bit
143
- byte_array.shift(2).pack("C*").unpack("v").first
144
- elsif byte_1 == 254
145
- # Little-endian 32-bit int
146
- byte_array.shift(4).pack("C*").unpack("V").first
147
- else
148
- # 64-bit int (is this little-endian or native?)
149
- byte_array.shift(8).pack("C*").unpack("Q").first
150
- end
151
- end
152
- end
153
- end
154
- end
155
- end