bitcoinrb 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/bitcoinrb.gemspec +7 -3
- data/exe/bitcoinrb-cli +1 -1
- data/exe/bitcoinrbd +9 -23
- data/lib/bitcoin/block.rb +66 -0
- data/lib/bitcoin/block_header.rb +33 -1
- data/lib/bitcoin/chain_params.rb +11 -4
- data/lib/bitcoin/chainparams/mainnet.yml +9 -2
- data/lib/bitcoin/chainparams/regtest.yml +9 -1
- data/lib/bitcoin/chainparams/testnet.yml +9 -1
- data/lib/bitcoin/constants.rb +13 -0
- data/lib/bitcoin/ext_key.rb +2 -1
- data/lib/bitcoin/merkle_tree.rb +50 -51
- data/lib/bitcoin/message/block.rb +5 -0
- data/lib/bitcoin/message.rb +5 -5
- data/lib/bitcoin/network/connection.rb +58 -0
- data/lib/bitcoin/network/message_handler.rb +192 -0
- data/lib/bitcoin/network/peer.rb +55 -0
- data/lib/bitcoin/network/peer_discovery.rb +34 -0
- data/lib/bitcoin/network/pool.rb +74 -0
- data/lib/bitcoin/network.rb +14 -0
- data/lib/bitcoin/node/spv.rb +39 -0
- data/lib/bitcoin/node/spv_block_chain.rb +15 -0
- data/lib/bitcoin/node.rb +6 -0
- data/lib/bitcoin/script/script.rb +13 -0
- data/lib/bitcoin/store/spv_block_store.rb +11 -0
- data/lib/bitcoin/store.rb +7 -0
- data/lib/bitcoin/tx.rb +11 -0
- data/lib/bitcoin/tx_out.rb +2 -0
- data/lib/bitcoin/validation.rb +33 -11
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin.rb +5 -2
- data/lib/openassets/marker_output.rb +14 -0
- data/lib/openassets/payload.rb +45 -0
- data/lib/openassets.rb +8 -0
- metadata +59 -8
- data/lib/bitcoin/connection.rb +0 -68
- data/lib/bitcoin/message/handler.rb +0 -183
- data/lib/bitcoin/nodes/spv/cli.rb +0 -12
- data/lib/bitcoin/nodes/spv/daemon.rb +0 -21
- data/lib/bitcoin/nodes/spv.rb +0 -13
- data/lib/bitcoin/nodes.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1508c7b3cad66796b7ef2bde7e744e478eb5f6c
|
4
|
+
data.tar.gz: 11c7f275b40ec3a70f5f55607ec4f8aee4ea0bd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '095ba38bc01e7ef0b83091f63c537f2ce06e0cd91645fcbc7988da05ff54ea25dcf85f9725782d3f5e16057b5c5777275e7ad12c77388e32153f37100c724bbb'
|
7
|
+
data.tar.gz: 5aa55097029750cf282dc23a1caa5702e1b21a942409adeac25836b083d59fc6994f72300fc76c8415c5d9f21f01b3af0b5d188a9ca035734971cbac0ffd03d3
|
data/.gitignore
CHANGED
data/bitcoinrb.gemspec
CHANGED
@@ -26,8 +26,12 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_runtime_dependency 'daemon-spawn'
|
27
27
|
spec.add_runtime_dependency 'thor'
|
28
28
|
spec.add_runtime_dependency 'ffi'
|
29
|
+
spec.add_runtime_dependency 'parallel'
|
30
|
+
spec.add_runtime_dependency 'leb128', '~> 1.0.0'
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
33
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
spec.add_development_dependency 'timecop'
|
29
36
|
|
30
|
-
spec.add_development_dependency "bundler", "~> 1.11"
|
31
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
33
37
|
end
|
data/exe/bitcoinrb-cli
CHANGED
data/exe/bitcoinrbd
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'thor'
|
3
3
|
require 'bitcoin'
|
4
|
-
require 'bitcoin/
|
4
|
+
require 'bitcoin/node/spv'
|
5
5
|
|
6
6
|
class Bitcoinrbd < Thor
|
7
7
|
|
@@ -10,40 +10,26 @@ class Bitcoinrbd < Thor
|
|
10
10
|
desc 'start', 'start bitcoinrbd daemon process'
|
11
11
|
def start
|
12
12
|
raise ArgumentError, 'currently only support spv mode.' unless options[:mode] == 'spv'
|
13
|
-
|
13
|
+
Bitcoin.chain_params = network.to_sym
|
14
|
+
FileUtils.mkdir_p(Bitcoin.base_dir)
|
15
|
+
execute_daemon(['start'])
|
14
16
|
end
|
15
17
|
|
16
18
|
option :mode, default: 'spv'
|
17
19
|
option :network, default: 'mainnet'
|
18
20
|
desc 'stop', 'start bitcoinrbd daemon process'
|
19
21
|
def stop
|
20
|
-
execute_daemon(
|
22
|
+
execute_daemon(['stop'])
|
21
23
|
end
|
22
24
|
|
23
|
-
def execute_daemon(
|
24
|
-
Bitcoin::Nodes::SPV
|
25
|
-
log_file: "#{base_dir}/bitcoinrbd.log",
|
26
|
-
pid_file: "#{base_dir}/bitcoinrbd.pid",
|
25
|
+
def execute_daemon(cmd_args)
|
26
|
+
Bitcoin::Nodes::SPV.spawn!({working_dir: Bitcoin.base_dir,
|
27
|
+
log_file: "#{Bitcoin.base_dir}/bitcoinrbd.log",
|
28
|
+
pid_file: "#{Bitcoin.base_dir}/bitcoinrbd.pid",
|
27
29
|
sync_log: true,
|
28
30
|
singleton: true}, cmd_args)
|
29
31
|
end
|
30
32
|
|
31
|
-
private
|
32
|
-
|
33
|
-
def setup_base_dir(network)
|
34
|
-
case network
|
35
|
-
when 'mainnet'
|
36
|
-
base_dir = Bitcoin.base_dir
|
37
|
-
when 'testnet'
|
38
|
-
base_dir = "#{Bitcoin.base_dir}/testnet3"
|
39
|
-
when 'regtest'
|
40
|
-
base_dir = "#{Bitcoin.base_dir}/regtest"
|
41
|
-
else
|
42
|
-
raise ArgumentError, 'Unsupported network specified.'
|
43
|
-
end
|
44
|
-
FileUtils.mkdir_p(base_dir)
|
45
|
-
base_dir
|
46
|
-
end
|
47
33
|
end
|
48
34
|
|
49
35
|
Bitcoinrbd.start(ARGV)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
class Block
|
3
|
+
|
4
|
+
attr_accessor :header
|
5
|
+
attr_accessor :transactions
|
6
|
+
|
7
|
+
def initialize(header, transactions = [])
|
8
|
+
@header = header
|
9
|
+
@transactions = transactions
|
10
|
+
end
|
11
|
+
|
12
|
+
# calculate block weight
|
13
|
+
def weight
|
14
|
+
stripped_size * (WITNESS_SCALE_FACTOR - 1) + size
|
15
|
+
end
|
16
|
+
|
17
|
+
# calculate total size (include witness data.)
|
18
|
+
def size
|
19
|
+
80 + Bitcoin.pack_var_int(transactions.size).bytesize +
|
20
|
+
transactions.inject(0){|sum, tx| sum + (tx.witness? ? tx.serialize_witness_format.bytesize : tx.serialize_old_format.bytesize)}
|
21
|
+
end
|
22
|
+
|
23
|
+
# calculate base size (not include witness data.)
|
24
|
+
def stripped_size
|
25
|
+
80 + Bitcoin.pack_var_int(transactions.size).bytesize +
|
26
|
+
transactions.inject(0){|sum, tx| sum + tx.serialize_old_format.bytesize}
|
27
|
+
end
|
28
|
+
|
29
|
+
# check the merkle root in the block header matches merkle root calculated from tx list.
|
30
|
+
def valid_merkle_root?
|
31
|
+
calculate_merkle_root == header.merkle_root
|
32
|
+
end
|
33
|
+
|
34
|
+
# calculate merkle root from tx list.
|
35
|
+
def calculate_merkle_root
|
36
|
+
Bitcoin::MerkleTree.build_from_leaf(transactions.map(&:txid)).merkle_root
|
37
|
+
end
|
38
|
+
|
39
|
+
# check the witness commitment in coinbase tx matches witness commitment calculated from tx list.
|
40
|
+
def valid_witness_commitment?
|
41
|
+
transactions[0].witness_commitment == calculate_witness_commitment
|
42
|
+
end
|
43
|
+
|
44
|
+
# calculate witness commitment from tx list.
|
45
|
+
def calculate_witness_commitment
|
46
|
+
wtxid_list = [COINBASE_WTXID]
|
47
|
+
wtxid_list.concat(transactions[1..-1].map{|tx| tx.wtxid})
|
48
|
+
reserved_value = transactions[0].inputs[0].script_witness.stack.map(&:bth).join
|
49
|
+
root_hash = Bitcoin::MerkleTree.build_from_leaf(wtxid_list).merkle_root
|
50
|
+
Digest::SHA256.digest(Digest::SHA256.digest(
|
51
|
+
[reserved_value + root_hash].pack('H*').reverse )).bth
|
52
|
+
end
|
53
|
+
|
54
|
+
# return this block height. block height is included in coinbase.
|
55
|
+
# if block version under 1, height does not include in coinbase, so return nil.
|
56
|
+
def height
|
57
|
+
return nil if header.version < 2
|
58
|
+
coinbase_tx = transactions[0]
|
59
|
+
return nil unless coinbase_tx.coinbase_tx?
|
60
|
+
buf = StringIO.new(coinbase_tx.inputs[0].script_sig.to_payload)
|
61
|
+
len = Bitcoin.unpack_var_int_from_io(buf)
|
62
|
+
buf.read(len).reverse.bth.to_i(16)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/lib/bitcoin/block_header.rb
CHANGED
@@ -7,7 +7,7 @@ module Bitcoin
|
|
7
7
|
attr_accessor :version
|
8
8
|
attr_accessor :prev_hash
|
9
9
|
attr_accessor :merkle_root
|
10
|
-
attr_accessor :time
|
10
|
+
attr_accessor :time # unix timestamp
|
11
11
|
attr_accessor :bits
|
12
12
|
attr_accessor :nonce
|
13
13
|
|
@@ -30,6 +30,38 @@ module Bitcoin
|
|
30
30
|
[version, prev_hash.htb.reverse, merkle_root.htb.reverse, time, bits, nonce].pack('Va32a32VVV')
|
31
31
|
end
|
32
32
|
|
33
|
+
# compute difficulty target from bits.
|
34
|
+
def difficulty_target
|
35
|
+
exponent = ((bits >> 24) & 0xff)
|
36
|
+
mantissa = bits & 0x7fffff
|
37
|
+
mantissa *= -1 if (bits & 0x800000) > 0
|
38
|
+
(mantissa * 2 ** (8 * (exponent - 3)))
|
39
|
+
end
|
40
|
+
|
41
|
+
# evaluate block header
|
42
|
+
def valid?
|
43
|
+
valid_pow? && valid_timestamp?
|
44
|
+
end
|
45
|
+
|
46
|
+
# evaluate valid proof of work.
|
47
|
+
def valid_pow?
|
48
|
+
hash.hex < difficulty_target
|
49
|
+
end
|
50
|
+
|
51
|
+
# evaluate valid timestamp.
|
52
|
+
# https://en.bitcoin.it/wiki/Block_timestamp
|
53
|
+
def valid_timestamp?
|
54
|
+
time <= Time.now.to_i + Bitcoin::MAX_FUTURE_BLOCK_TIME
|
55
|
+
end
|
56
|
+
|
57
|
+
# compute chain work of this block.
|
58
|
+
# @return [Integer] a chain work.
|
59
|
+
def work
|
60
|
+
target = difficulty_target
|
61
|
+
return 0 if target < 1
|
62
|
+
(2**256) / (target + 1)
|
63
|
+
end
|
64
|
+
|
33
65
|
private
|
34
66
|
|
35
67
|
def calc_hash
|
data/lib/bitcoin/chain_params.rb
CHANGED
@@ -21,21 +21,21 @@ module Bitcoin
|
|
21
21
|
attr_reader :target_spacing
|
22
22
|
attr_reader :max_money
|
23
23
|
attr_reader :bip34_height
|
24
|
-
attr_reader :genesis_hash
|
25
24
|
attr_reader :proof_of_work_limit
|
26
25
|
attr_reader :dns_seeds
|
26
|
+
attr_reader :genesis
|
27
27
|
|
28
|
-
# mainnet
|
28
|
+
# mainnet genesis
|
29
29
|
def self.mainnet
|
30
30
|
YAML.load(File.open("#{__dir__}/chainparams/mainnet.yml"))
|
31
31
|
end
|
32
32
|
|
33
|
-
# testnet
|
33
|
+
# testnet genesis
|
34
34
|
def self.testnet
|
35
35
|
YAML.load(File.open("#{__dir__}/chainparams/testnet.yml"))
|
36
36
|
end
|
37
37
|
|
38
|
-
# regtest
|
38
|
+
# regtest genesis
|
39
39
|
def self.regtest
|
40
40
|
YAML.load(File.open("#{__dir__}/chainparams/regtest.yml"))
|
41
41
|
end
|
@@ -52,6 +52,13 @@ module Bitcoin
|
|
52
52
|
network == 'regtest'
|
53
53
|
end
|
54
54
|
|
55
|
+
def genesis_block
|
56
|
+
header = Bitcoin::BlockHeader.new(
|
57
|
+
genesis['version'], genesis['prev_hash'], genesis['merkle_root'],
|
58
|
+
genesis['time'], genesis['bits'], genesis['nonce'])
|
59
|
+
Bitcoin::Block.new(header)
|
60
|
+
end
|
61
|
+
|
55
62
|
end
|
56
63
|
|
57
64
|
end
|
@@ -15,11 +15,18 @@ retarget_time: 1209600 # 2 weeks
|
|
15
15
|
target_spacing: 600 # block interval
|
16
16
|
max_money: 21000000
|
17
17
|
bip34_height: 227931
|
18
|
-
genesis_hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
19
18
|
proof_of_work_limit: 0x1d00ffff
|
20
19
|
dns_seeds:
|
21
20
|
- "seed.bitcoin.sipa.be"
|
22
21
|
- "dnsseed.bluematt.me"
|
23
22
|
- "dnsseed.bitcoin.dashjr.org"
|
24
23
|
- "seed.bitcoinstats.com"
|
25
|
-
- "seed.bitcoin.jonasschnelli.ch"
|
24
|
+
- "seed.bitcoin.jonasschnelli.ch"
|
25
|
+
genesis:
|
26
|
+
hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
27
|
+
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
28
|
+
time: 1231006505
|
29
|
+
nonce: 2083236893
|
30
|
+
bits: 0x1d00ffff
|
31
|
+
version: 1
|
32
|
+
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
@@ -17,4 +17,12 @@ max_money: 21000000
|
|
17
17
|
bip34_height: 0
|
18
18
|
genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
19
19
|
proof_of_work_limit: 0x207fffff
|
20
|
-
dns_seeds:
|
20
|
+
dns_seeds:
|
21
|
+
genesis:
|
22
|
+
hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
23
|
+
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
24
|
+
time: 1296688602
|
25
|
+
nonce: 2
|
26
|
+
bits: 0x207fffff
|
27
|
+
version: 1
|
28
|
+
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
@@ -21,4 +21,12 @@ dns_seeds:
|
|
21
21
|
- "testnet-seed.bitcoin.jonasschnelli.ch"
|
22
22
|
- "seed.tbtc.petertodd.org"
|
23
23
|
- "testnet-seed.bluematt.me"
|
24
|
-
- "testnet-seed.bitcoin.schildbach.de"
|
24
|
+
- "testnet-seed.bitcoin.schildbach.de"
|
25
|
+
genesis:
|
26
|
+
hash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
27
|
+
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
28
|
+
time: 1296688602
|
29
|
+
nonce: 414098458
|
30
|
+
bits: 0x1d00ffff
|
31
|
+
version: 1
|
32
|
+
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
data/lib/bitcoin/constants.rb
CHANGED
@@ -154,4 +154,17 @@ module Bitcoin
|
|
154
154
|
ERRCODES_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [const_get(c), c.to_s] }.flatten]
|
155
155
|
NAME_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
156
156
|
|
157
|
+
# witness commitment
|
158
|
+
WITNESS_COMMITMENT_HEADER = 'aa21a9ed'
|
159
|
+
|
160
|
+
COINBASE_WTXID = '00'* 32
|
161
|
+
|
162
|
+
# for message
|
163
|
+
MESSAGE_HEADER_SIZE = 24
|
164
|
+
|
165
|
+
# for peer
|
166
|
+
PARALLEL_THREAD = 3
|
167
|
+
|
168
|
+
# Maximum amount of time that a block timestamp is allowed to exceed the current network-adjusted time before the block will be accepted.
|
169
|
+
MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60
|
157
170
|
end
|
data/lib/bitcoin/ext_key.rb
CHANGED
@@ -17,11 +17,12 @@ module Bitcoin
|
|
17
17
|
attr_accessor :parent_fingerprint
|
18
18
|
|
19
19
|
# generate master key from seed.
|
20
|
+
# @params [String] seed a seed data with hex format.
|
20
21
|
def self.generate_master(seed)
|
21
22
|
ext_key = ExtKey.new
|
22
23
|
ext_key.depth = ext_key.number = 0
|
23
24
|
ext_key.parent_fingerprint = '00000000'
|
24
|
-
l = Bitcoin.hmac_sha512('Bitcoin seed', seed)
|
25
|
+
l = Bitcoin.hmac_sha512('Bitcoin seed', seed.htb)
|
25
26
|
left = l[0..31].bth.to_i(16)
|
26
27
|
raise 'invalid key' if left >= CURVE_ORDER || left == 0
|
27
28
|
ext_key.key = Bitcoin::Key.new(priv_key: l[0..31].bth)
|
data/lib/bitcoin/merkle_tree.rb
CHANGED
@@ -52,69 +52,68 @@ module Bitcoin
|
|
52
52
|
nodes.first
|
53
53
|
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
# node of merkle tree
|
58
|
-
class Node
|
55
|
+
# node of merkle tree
|
56
|
+
class Node
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
58
|
+
attr_accessor :flag
|
59
|
+
attr_accessor :hash
|
60
|
+
attr_accessor :parent
|
61
|
+
attr_accessor :left
|
62
|
+
attr_accessor :right
|
65
63
|
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
def initialize(hash = nil)
|
65
|
+
@hash = hash
|
66
|
+
end
|
69
67
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
def left=(node)
|
69
|
+
node.parent = self
|
70
|
+
@left = node
|
71
|
+
end
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
def right=(node)
|
74
|
+
node.parent = self
|
75
|
+
@right = node
|
76
|
+
end
|
79
77
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
78
|
+
def hash
|
79
|
+
return @hash if @hash
|
80
|
+
self.right = left.dup unless right
|
81
|
+
Digest::SHA256.digest(Digest::SHA256.digest(
|
82
|
+
[right.hash + left.hash].pack('H*').reverse )).reverse.bth
|
83
|
+
end
|
86
84
|
|
87
|
-
|
88
|
-
|
89
|
-
|
85
|
+
def root?
|
86
|
+
parent.nil?
|
87
|
+
end
|
90
88
|
|
91
|
-
|
92
|
-
|
93
|
-
|
89
|
+
def leaf?
|
90
|
+
right.nil? && left.nil?
|
91
|
+
end
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
93
|
+
def partial?
|
94
|
+
!flag.nil?
|
95
|
+
end
|
98
96
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
97
|
+
def next_partial
|
98
|
+
return nil if root? && (flag.zero? || (left.partial? && right.partial?))
|
99
|
+
return parent.next_partial if flag.zero? || leaf?
|
100
|
+
return left unless left.partial?
|
101
|
+
self.right = left.dup unless right
|
102
|
+
right.partial? ? parent.next_partial : right
|
103
|
+
end
|
106
104
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
105
|
+
# calculate the depth of this node in the tree.
|
106
|
+
def depth
|
107
|
+
d = 0
|
108
|
+
current_node = self
|
109
|
+
until current_node.root? do
|
110
|
+
current_node = current_node.parent
|
111
|
+
d += 1
|
112
|
+
end
|
113
|
+
d
|
114
114
|
end
|
115
|
-
d
|
116
|
-
end
|
117
115
|
|
116
|
+
end
|
118
117
|
end
|
119
118
|
|
120
119
|
end
|
data/lib/bitcoin/message.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module Bitcoin
|
2
2
|
module Message
|
3
3
|
|
4
|
-
autoload :Handler, 'bitcoin/message/handler'
|
5
4
|
autoload :Base, 'bitcoin/message/base'
|
6
5
|
autoload :Inventory, 'bitcoin/message/inventory'
|
7
6
|
autoload :InventoriesParser, 'bitcoin/message/inventories_parser'
|
@@ -31,19 +30,20 @@ module Bitcoin
|
|
31
30
|
autoload :Reject, 'bitcoin/message/reject'
|
32
31
|
autoload :SendCmpct, 'bitcoin/message/send_cmpct'
|
33
32
|
|
34
|
-
HEADER_SIZE = 24
|
35
33
|
USER_AGENT = "/bitcoinrb:#{Bitcoin::VERSION}/"
|
36
34
|
|
37
35
|
SERVICE_FLAGS = {
|
38
36
|
none: 0,
|
39
|
-
network: 1 << 0, # the node is capable of serving the block chain. It is currently set by all Bitcoin Core
|
37
|
+
network: 1 << 0, # the node is capable of serving the block chain. It is currently set by all Bitcoin Core node, and is unset by SPV clients or other peers that just want network services but don't provide them.
|
40
38
|
# getutxo: 1 << 1, # BIP-64. not implemented in Bitcoin Core.
|
41
|
-
bloom: 1 << 2, # the node is capable and willing to handle bloom-filtered connections. Bitcoin Core
|
39
|
+
bloom: 1 << 2, # the node is capable and willing to handle bloom-filtered connections. Bitcoin Core node used to support this by default, without advertising this bit, but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)
|
42
40
|
witness: 1 << 3, # the node can be asked for blocks and transactions including witness data.
|
43
41
|
# xthin: 1 << 4 # support Xtreme Thinblocks. not implemented in Bitcoin Core
|
44
42
|
}
|
45
43
|
|
46
|
-
DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:network] | SERVICE_FLAGS[:bloom] | SERVICE_FLAGS[:witness]
|
44
|
+
# DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:network] | SERVICE_FLAGS[:bloom] | SERVICE_FLAGS[:witness]
|
45
|
+
|
46
|
+
DEFAULT_SERVICE_FLAGS = SERVICE_FLAGS[:none] | SERVICE_FLAGS[:witness]
|
47
47
|
|
48
48
|
DEFAULT_STOP_HASH = "00"*32
|
49
49
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
|
3
|
+
module Network
|
4
|
+
|
5
|
+
# Basic Bitcoin P2P connection class
|
6
|
+
class Connection < EM::Connection
|
7
|
+
|
8
|
+
include MessageHandler
|
9
|
+
|
10
|
+
attr_reader :peer, :logger
|
11
|
+
|
12
|
+
# remote peer version.
|
13
|
+
attr_accessor :version
|
14
|
+
|
15
|
+
# if true, this peer send new block announcements using a headers message rather than an inv message.
|
16
|
+
attr_accessor :sendheaders
|
17
|
+
|
18
|
+
# minimum fee(in satoshis per kilobyte) for relay tx
|
19
|
+
attr_accessor :fee_rate
|
20
|
+
|
21
|
+
def initialize(peer)
|
22
|
+
@peer = peer
|
23
|
+
@logger = Bitcoin::Logger.create(:debug)
|
24
|
+
@sendheaders = false
|
25
|
+
@attr_accessor = 0
|
26
|
+
@message = ''
|
27
|
+
end
|
28
|
+
|
29
|
+
def post_init
|
30
|
+
logger.info "connected. #{addr}"
|
31
|
+
begin_handshake
|
32
|
+
end
|
33
|
+
|
34
|
+
# handle receiving data from remote node.
|
35
|
+
def receive_data(data)
|
36
|
+
handle(data)
|
37
|
+
end
|
38
|
+
|
39
|
+
def post_handshake
|
40
|
+
peer.post_handshake
|
41
|
+
end
|
42
|
+
|
43
|
+
def addr
|
44
|
+
peer.addr
|
45
|
+
end
|
46
|
+
|
47
|
+
# close network connection.
|
48
|
+
def close(msg = '')
|
49
|
+
logger.info "close connection with #{addr}. #{msg}"
|
50
|
+
close_connection_after_writing
|
51
|
+
EM.stop
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|