coin-op 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +28 -0
- data/lib/coin-op.rb +12 -0
- data/lib/coin-op/bit.rb +21 -0
- data/lib/coin-op/bit/input.rb +73 -0
- data/lib/coin-op/bit/multi_wallet.rb +261 -0
- data/lib/coin-op/bit/output.rb +79 -0
- data/lib/coin-op/bit/script.rb +94 -0
- data/lib/coin-op/bit/spendable.rb +85 -0
- data/lib/coin-op/bit/transaction.rb +238 -0
- data/lib/coin-op/blockchain/blockr.rb +162 -0
- data/lib/coin-op/blockchain/mockchain.rb +124 -0
- data/lib/coin-op/crypto.rb +70 -0
- data/lib/coin-op/encodings.rb +26 -0
- metadata +144 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
require "bitcoin"
|
2
|
+
|
3
|
+
Bitcoin::NETWORKS[:mockchain] = {
|
4
|
+
:project => :bitcoin,
|
5
|
+
:magic_head => "mock",
|
6
|
+
:address_version => "6f",
|
7
|
+
:p2sh_version => "c4",
|
8
|
+
:privkey_version => "ef",
|
9
|
+
:default_port => 48333,
|
10
|
+
:protocol_version => 70001,
|
11
|
+
:max_money => 21_000_000 * 100_000_000,
|
12
|
+
:dns_seeds => [],
|
13
|
+
:genesis_hash => "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943",
|
14
|
+
:proof_of_work_limit => 553713663,
|
15
|
+
:alert_pubkeys => [],
|
16
|
+
:known_nodes => [],
|
17
|
+
:checkpoints => {},
|
18
|
+
:min_tx_fee => 10_000,
|
19
|
+
:min_relay_tx_fee => 10_000,
|
20
|
+
}
|
21
|
+
|
22
|
+
Bitcoin.network = :mockchain
|
23
|
+
|
24
|
+
|
25
|
+
module CoinOp::Bit
|
26
|
+
|
27
|
+
class MockChain
|
28
|
+
include ::Bitcoin::Builder
|
29
|
+
|
30
|
+
attr_reader :key, :store, :last, :coinbase_value
|
31
|
+
|
32
|
+
def initialize(config={})
|
33
|
+
@key = Bitcoin::Key.new
|
34
|
+
@key.generate
|
35
|
+
@config = config
|
36
|
+
@coinbase_value = 50e8
|
37
|
+
|
38
|
+
if @config[:db]
|
39
|
+
@store = Bitcoin::Storage.sequel(
|
40
|
+
:db => @config[:db], :log_level => :warn
|
41
|
+
)
|
42
|
+
@store.connect
|
43
|
+
if head = @store.get_head
|
44
|
+
@last = head
|
45
|
+
else
|
46
|
+
self.reset
|
47
|
+
end
|
48
|
+
else
|
49
|
+
self.reset
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def reset
|
54
|
+
@store.reset if @store
|
55
|
+
@block0 = self.add :key => @key, :previous => "00"*32
|
56
|
+
|
57
|
+
Bitcoin.network[:genesis_hash] = @block0.hash
|
58
|
+
@store.store_block(@block0) if @store
|
59
|
+
@last = @block0
|
60
|
+
end
|
61
|
+
|
62
|
+
def mine(key=nil)
|
63
|
+
key ||= @key
|
64
|
+
block = self.add :key => key, :previous => @last.hash
|
65
|
+
end
|
66
|
+
|
67
|
+
def add(options={})
|
68
|
+
if !options[:key]
|
69
|
+
raise "Must provide :key"
|
70
|
+
end
|
71
|
+
options[:bits] ||= Bitcoin.network[:proof_of_work_limit]
|
72
|
+
previous_block = options[:previous] || @last
|
73
|
+
|
74
|
+
block = build_block(Bitcoin.decode_compact_bits(options[:bits])) do |b|
|
75
|
+
b.time options[:time] if options[:time]
|
76
|
+
b.prev_block previous_block
|
77
|
+
b.tx do |t|
|
78
|
+
t.input {|i| i.coinbase }
|
79
|
+
t.output do |o|
|
80
|
+
o.value @coinbase_value
|
81
|
+
o.script {|s| s.recipient options[:key].addr }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
if options[:transactions]
|
86
|
+
options[:transactions].each do |transaction|
|
87
|
+
block.tx << transaction
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
@store.store_block(block) if @store
|
92
|
+
@last = block
|
93
|
+
block
|
94
|
+
end
|
95
|
+
|
96
|
+
def transaction(recipients)
|
97
|
+
last_transaction = @last.tx.first
|
98
|
+
|
99
|
+
transaction = Builder.build_tx do |t|
|
100
|
+
t.input do |i|
|
101
|
+
i.prev_out last_transaction
|
102
|
+
i.prev_out_index 0
|
103
|
+
i.signature_key @key
|
104
|
+
end
|
105
|
+
|
106
|
+
recipients.each do |address, value|
|
107
|
+
t.output do |o|
|
108
|
+
o.value value
|
109
|
+
o.script do |s|
|
110
|
+
s.type :address
|
111
|
+
s.recipient address
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "rbnacl"
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
module CoinOp
|
5
|
+
module Crypto
|
6
|
+
|
7
|
+
class PassphraseBox
|
8
|
+
include CoinOp::Encodings
|
9
|
+
extend CoinOp::Encodings
|
10
|
+
|
11
|
+
# PBKDF2 work factor
|
12
|
+
ITERATIONS = 100_000
|
13
|
+
|
14
|
+
# Given passphrase and plaintext as strings, returns a Hash
|
15
|
+
# containing the ciphertext and other values needed for later
|
16
|
+
# decryption.
|
17
|
+
def self.encrypt(passphrase, plaintext)
|
18
|
+
box = self.new(passphrase)
|
19
|
+
box.encrypt(plaintext)
|
20
|
+
end
|
21
|
+
|
22
|
+
# PassphraseBox.decrypt "my great password",
|
23
|
+
# :salt => salt, :nonce => nonce, :ciphertext => ciphertext
|
24
|
+
#
|
25
|
+
def self.decrypt(passphrase, hash)
|
26
|
+
salt, nonce, ciphertext =
|
27
|
+
hash.values_at(:salt, :nonce, :ciphertext).map {|s| decode_base58(s) }
|
28
|
+
box = self.new(passphrase, salt, hash[:iterations])
|
29
|
+
box.decrypt(nonce, ciphertext)
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :salt
|
33
|
+
|
34
|
+
# Initialize with an existing salt and iterations to allow
|
35
|
+
# decryption. Otherwise, creates new values for these, meaning
|
36
|
+
# it creates an entirely new secret-box.
|
37
|
+
def initialize(passphrase, salt=nil, iterations=nil)
|
38
|
+
@salt = salt || RbNaCl::Random.random_bytes(16)
|
39
|
+
@iterations = iterations || ITERATIONS
|
40
|
+
|
41
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(
|
42
|
+
passphrase, @salt,
|
43
|
+
# TODO: decide on a very safe work factor
|
44
|
+
# https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
|
45
|
+
#
|
46
|
+
@iterations, # number of iterations
|
47
|
+
32 # key length in bytes
|
48
|
+
)
|
49
|
+
@box = RbNaCl::SecretBox.new(key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def encrypt(plaintext)
|
53
|
+
nonce = RbNaCl::Random.random_bytes(RbNaCl::SecretBox.nonce_bytes)
|
54
|
+
ciphertext = @box.encrypt(nonce, plaintext)
|
55
|
+
{
|
56
|
+
:salt => base58(@salt),
|
57
|
+
:iterations => @iterations,
|
58
|
+
:nonce => base58(nonce),
|
59
|
+
:ciphertext => base58(ciphertext)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def decrypt(nonce, ciphertext)
|
64
|
+
@box.decrypt(nonce, ciphertext)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module CoinOp
|
3
|
+
|
4
|
+
module Encodings
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def hex(blob)
|
8
|
+
blob.unpack("H*")[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
def decode_hex(string)
|
12
|
+
[string].pack("H*")
|
13
|
+
end
|
14
|
+
|
15
|
+
def base58(blob)
|
16
|
+
::Bitcoin.encode_base58(self.hex(blob))
|
17
|
+
end
|
18
|
+
|
19
|
+
def decode_base58(string)
|
20
|
+
self.decode_hex(::Bitcoin.decode_base58(string))
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: coin-op
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew King
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bitcoin-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: money-tree
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.8'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.8'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: starter
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.1.12
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.1.12
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sequel
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.8'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-reporters
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- matthew@bitvault.io
|
100
|
+
- dustin@bitvault.io
|
101
|
+
- julian@bitvault.io
|
102
|
+
executables: []
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- LICENSE
|
107
|
+
- README.md
|
108
|
+
- lib/coin-op.rb
|
109
|
+
- lib/coin-op/bit.rb
|
110
|
+
- lib/coin-op/bit/input.rb
|
111
|
+
- lib/coin-op/bit/multi_wallet.rb
|
112
|
+
- lib/coin-op/bit/output.rb
|
113
|
+
- lib/coin-op/bit/script.rb
|
114
|
+
- lib/coin-op/bit/spendable.rb
|
115
|
+
- lib/coin-op/bit/transaction.rb
|
116
|
+
- lib/coin-op/blockchain/blockr.rb
|
117
|
+
- lib/coin-op/blockchain/mockchain.rb
|
118
|
+
- lib/coin-op/crypto.rb
|
119
|
+
- lib/coin-op/encodings.rb
|
120
|
+
homepage: https://github.com/BitVault/coin-op
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
metadata: {}
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options: []
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 2.2.0
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Crypto currency classes in Ruby
|
144
|
+
test_files: []
|