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
@@ -0,0 +1,45 @@
|
|
1
|
+
module OpenAssets
|
2
|
+
|
3
|
+
MARKER = "\x4f\x41"
|
4
|
+
VERSION = "\x01\x00"
|
5
|
+
|
6
|
+
# the open assets payload
|
7
|
+
class Payload
|
8
|
+
|
9
|
+
attr_accessor :quantities
|
10
|
+
attr_accessor :metadata
|
11
|
+
|
12
|
+
def initialize(quantities = [], metadata = '')
|
13
|
+
@quantities = quantities
|
14
|
+
@metadata = metadata
|
15
|
+
end
|
16
|
+
|
17
|
+
# parse open assets payload
|
18
|
+
# @return [Payload] a open assets payload object, if payload is invalid, return nil.
|
19
|
+
def self.parse_from_payload(payload)
|
20
|
+
buf = StringIO.new(payload)
|
21
|
+
marker = buf.read(2)
|
22
|
+
version = buf.read(2)
|
23
|
+
return nil if marker != MARKER || version != VERSION
|
24
|
+
count = Bitcoin.unpack_var_int_from_io(buf)
|
25
|
+
quantities = []
|
26
|
+
count.times do
|
27
|
+
quantities << LEB128.decode_unsigned(buf, buf.pos)
|
28
|
+
end
|
29
|
+
metadata_length = Bitcoin.unpack_var_int_from_io(buf)
|
30
|
+
return nil if buf.length < metadata_length + buf.pos
|
31
|
+
metadata = buf.read(metadata_length).each_byte.map(&:chr).join
|
32
|
+
new(quantities, metadata)
|
33
|
+
end
|
34
|
+
|
35
|
+
# generate binary payload
|
36
|
+
def to_payload
|
37
|
+
payload = MARKER << VERSION
|
38
|
+
payload << Bitcoin.pack_var_int(quantities.size) << quantities.map{|q| LEB128.encode_unsigned(q).read }.join
|
39
|
+
payload << Bitcoin.pack_var_int(metadata.length) << metadata.bytes.map{|b|b.to_s(16)}.join.htb
|
40
|
+
payload
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/openassets.rb
ADDED
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
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -108,6 +108,34 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: parallel
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: leb128
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.0.0
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.0.0
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
140
|
name: bundler
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +178,20 @@ dependencies:
|
|
150
178
|
- - "~>"
|
151
179
|
- !ruby/object:Gem::Version
|
152
180
|
version: '3.0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: timecop
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
153
195
|
description: "[WIP]The implementation of Bitcoin Protocol for Ruby."
|
154
196
|
email:
|
155
197
|
- azuchi@haw.co.jp
|
@@ -176,12 +218,12 @@ files:
|
|
176
218
|
- exe/bitcoinrbd
|
177
219
|
- lib/bitcoin.rb
|
178
220
|
- lib/bitcoin/base58.rb
|
221
|
+
- lib/bitcoin/block.rb
|
179
222
|
- lib/bitcoin/block_header.rb
|
180
223
|
- lib/bitcoin/chain_params.rb
|
181
224
|
- lib/bitcoin/chainparams/mainnet.yml
|
182
225
|
- lib/bitcoin/chainparams/regtest.yml
|
183
226
|
- lib/bitcoin/chainparams/testnet.yml
|
184
|
-
- lib/bitcoin/connection.rb
|
185
227
|
- lib/bitcoin/constants.rb
|
186
228
|
- lib/bitcoin/ext_key.rb
|
187
229
|
- lib/bitcoin/key.rb
|
@@ -200,7 +242,6 @@ files:
|
|
200
242
|
- lib/bitcoin/message/get_blocks.rb
|
201
243
|
- lib/bitcoin/message/get_data.rb
|
202
244
|
- lib/bitcoin/message/get_headers.rb
|
203
|
-
- lib/bitcoin/message/handler.rb
|
204
245
|
- lib/bitcoin/message/headers.rb
|
205
246
|
- lib/bitcoin/message/headers_parser.rb
|
206
247
|
- lib/bitcoin/message/inv.rb
|
@@ -225,10 +266,15 @@ files:
|
|
225
266
|
- lib/bitcoin/mnemonic/wordlist/italian.txt
|
226
267
|
- lib/bitcoin/mnemonic/wordlist/japanese.txt
|
227
268
|
- lib/bitcoin/mnemonic/wordlist/spanish.txt
|
228
|
-
- lib/bitcoin/
|
229
|
-
- lib/bitcoin/
|
230
|
-
- lib/bitcoin/
|
231
|
-
- lib/bitcoin/
|
269
|
+
- lib/bitcoin/network.rb
|
270
|
+
- lib/bitcoin/network/connection.rb
|
271
|
+
- lib/bitcoin/network/message_handler.rb
|
272
|
+
- lib/bitcoin/network/peer.rb
|
273
|
+
- lib/bitcoin/network/peer_discovery.rb
|
274
|
+
- lib/bitcoin/network/pool.rb
|
275
|
+
- lib/bitcoin/node.rb
|
276
|
+
- lib/bitcoin/node/spv.rb
|
277
|
+
- lib/bitcoin/node/spv_block_chain.rb
|
232
278
|
- lib/bitcoin/opcodes.rb
|
233
279
|
- lib/bitcoin/out_point.rb
|
234
280
|
- lib/bitcoin/script/script.rb
|
@@ -239,12 +285,17 @@ files:
|
|
239
285
|
- lib/bitcoin/secp256k1.rb
|
240
286
|
- lib/bitcoin/secp256k1/native.rb
|
241
287
|
- lib/bitcoin/secp256k1/ruby.rb
|
288
|
+
- lib/bitcoin/store.rb
|
289
|
+
- lib/bitcoin/store/spv_block_store.rb
|
242
290
|
- lib/bitcoin/tx.rb
|
243
291
|
- lib/bitcoin/tx_in.rb
|
244
292
|
- lib/bitcoin/tx_out.rb
|
245
293
|
- lib/bitcoin/util.rb
|
246
294
|
- lib/bitcoin/validation.rb
|
247
295
|
- lib/bitcoin/version.rb
|
296
|
+
- lib/openassets.rb
|
297
|
+
- lib/openassets/marker_output.rb
|
298
|
+
- lib/openassets/payload.rb
|
248
299
|
homepage: https://github.com/haw-itn/bitcoinrb
|
249
300
|
licenses:
|
250
301
|
- MIT
|
data/lib/bitcoin/connection.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
module Bitcoin
|
2
|
-
|
3
|
-
# Basic Bitcoin P2P connection class
|
4
|
-
class Connection < EM::Connection
|
5
|
-
|
6
|
-
attr_reader :host, :port, :handler, :logger
|
7
|
-
attr_accessor :connected
|
8
|
-
|
9
|
-
# if true, this peer send new block announcements using a headers message rather than an inv message.
|
10
|
-
attr_accessor :sendheaders
|
11
|
-
|
12
|
-
# minimum fee(in satoshis per kilobyte) for relay tx
|
13
|
-
attr_accessor :fee_rate
|
14
|
-
|
15
|
-
def initialize(host, port)
|
16
|
-
@host = host
|
17
|
-
@port = port
|
18
|
-
@logger = Bitcoin::Logger.create(:connection)
|
19
|
-
@handler = Message::Handler.new(self, @logger)
|
20
|
-
@connected = false
|
21
|
-
@sendheaders = false
|
22
|
-
@attr_accessor = 0
|
23
|
-
end
|
24
|
-
|
25
|
-
def post_init
|
26
|
-
logger.info "connected. #{remote_node}"
|
27
|
-
begin_handshake
|
28
|
-
end
|
29
|
-
|
30
|
-
# handle receiving data from remote node.
|
31
|
-
def receive_data(data)
|
32
|
-
logger.info "receive data from #{remote_node}"
|
33
|
-
handler.handle(data)
|
34
|
-
end
|
35
|
-
|
36
|
-
# close network connection.
|
37
|
-
def close(msg = '')
|
38
|
-
logger.info "close connection with #{remote_node}. #{msg}"
|
39
|
-
close_connection_after_writing
|
40
|
-
EM.stop
|
41
|
-
end
|
42
|
-
|
43
|
-
def handshake_done
|
44
|
-
logger.info 'handshake finished.'
|
45
|
-
@connected = true
|
46
|
-
end
|
47
|
-
|
48
|
-
def send_message(msg)
|
49
|
-
logger.info "send message #{msg.class::COMMAND}"
|
50
|
-
send_data(msg.to_pkt)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def remote_node
|
56
|
-
"#{host}:#{port}"
|
57
|
-
end
|
58
|
-
|
59
|
-
# start handshake
|
60
|
-
def begin_handshake
|
61
|
-
logger.info "begin handshake with #{remote_node}"
|
62
|
-
ver = Bitcoin::Message::Version.new(remote_addr: remote_node, start_height: 0) # TODO use start_height in wallet
|
63
|
-
send_message(ver)
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
@@ -1,183 +0,0 @@
|
|
1
|
-
module Bitcoin
|
2
|
-
module Message
|
3
|
-
|
4
|
-
# Default P2P message handler.
|
5
|
-
class Handler
|
6
|
-
|
7
|
-
attr_reader :logger
|
8
|
-
attr_reader :conn
|
9
|
-
|
10
|
-
def initialize(conn, logger = Bitcoin::Logger.create(:parser))
|
11
|
-
@conn = conn
|
12
|
-
@logger = logger
|
13
|
-
@message = ""
|
14
|
-
end
|
15
|
-
|
16
|
-
# handle p2p message.
|
17
|
-
def handle(message)
|
18
|
-
logger.info "handle message #{message.bth}"
|
19
|
-
begin
|
20
|
-
parse(message)
|
21
|
-
rescue Error => e
|
22
|
-
logger.error("invalid header magic. #{e.message}")
|
23
|
-
conn.close
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def parse(message)
|
30
|
-
@message += message
|
31
|
-
command, payload, rest = parse_header
|
32
|
-
return unless command
|
33
|
-
|
34
|
-
handle_command(command, payload)
|
35
|
-
@message = ""
|
36
|
-
parse(rest) if rest && rest.bytesize > 0
|
37
|
-
end
|
38
|
-
|
39
|
-
def parse_header
|
40
|
-
head_magic = Bitcoin.chain_params.magic_head
|
41
|
-
return if @message.nil? || @message.size < HEADER_SIZE
|
42
|
-
|
43
|
-
magic, command, length, checksum = @message.unpack('a4A12Va4')
|
44
|
-
raise Error, "invalid header magic. #{magic.bth}" unless magic.bth == head_magic
|
45
|
-
|
46
|
-
payload = @message[HEADER_SIZE...(HEADER_SIZE + length)]
|
47
|
-
return if payload.size < length
|
48
|
-
raise Error, "header checksum mismatch. #{checksum.bth}" unless Bitcoin.double_sha256(payload)[0...4] == checksum
|
49
|
-
|
50
|
-
rest = @message[(HEADER_SIZE + length)..-1]
|
51
|
-
[command, payload, rest]
|
52
|
-
end
|
53
|
-
|
54
|
-
def handle_command(command, payload)
|
55
|
-
logger.info("process command #{command}. payload = #{payload.bth}")
|
56
|
-
case command
|
57
|
-
when Version::COMMAND
|
58
|
-
on_version(Version.parse_from_payload(payload))
|
59
|
-
when VerAck::COMMAND
|
60
|
-
on_ver_ack
|
61
|
-
when GetAddr::COMMAND
|
62
|
-
on_get_addr
|
63
|
-
when Addr::COMMAND
|
64
|
-
on_addr(Addr.parse_from_payload(payload))
|
65
|
-
when SendHeaders::COMMAND
|
66
|
-
on_send_headers
|
67
|
-
when FeeFilter::COMMAND
|
68
|
-
on_fee_filter(FeeFilter.parse_from_payload(payload))
|
69
|
-
when Ping::COMMAND
|
70
|
-
on_ping(Ping.parse_from_payload(payload))
|
71
|
-
when Pong::COMMAND
|
72
|
-
on_pong(Pong.parse_from_payload(payload))
|
73
|
-
when GetHeaders::COMMAND
|
74
|
-
on_get_headers(GetHeaders.parse_from_payload(payload))
|
75
|
-
when Headers::COMMAND
|
76
|
-
on_headers(Headers.parse_from_payload(payload))
|
77
|
-
when Block::COMMAND
|
78
|
-
on_block(Block.parse_from_payload(payload))
|
79
|
-
when Tx::COMMAND
|
80
|
-
on_tx(Tx.parse_from_payload(payload))
|
81
|
-
when NotFound::COMMAND
|
82
|
-
on_not_found(NotFound.parse_from_payload(payload))
|
83
|
-
when MemPool::COMMAND
|
84
|
-
on_mem_pool
|
85
|
-
when Reject::COMMAND
|
86
|
-
on_reject(Reject.parse_from_payload(payload))
|
87
|
-
when SendCmpct::COMMAND
|
88
|
-
on_send_cmpct(SendCmpct.parse_from_payload(payload))
|
89
|
-
when Inv::COMMAND
|
90
|
-
on_inv(Inv.parse_from_payload(payload))
|
91
|
-
else
|
92
|
-
logger.warn("unsupported command received. #{command}")
|
93
|
-
conn.close("with command #{command}")
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def on_version(version)
|
98
|
-
logger.info("receive version message. #{version.build_json}")
|
99
|
-
conn.send_message(VerAck.new)
|
100
|
-
end
|
101
|
-
|
102
|
-
def on_ver_ack
|
103
|
-
logger.info('receive verack message.')
|
104
|
-
conn.handshake_done
|
105
|
-
end
|
106
|
-
|
107
|
-
def on_get_addr
|
108
|
-
logger.info('receive getaddr message.')
|
109
|
-
end
|
110
|
-
|
111
|
-
def on_addr(addr)
|
112
|
-
logger.info("receive addr message. #{addr.build_json}")
|
113
|
-
# TODO
|
114
|
-
end
|
115
|
-
|
116
|
-
def on_send_headers
|
117
|
-
logger.info('receive sendheaders message.')
|
118
|
-
conn.sendheaders = true
|
119
|
-
end
|
120
|
-
|
121
|
-
def on_fee_filter(fee_filter)
|
122
|
-
logger.info("receive feefilter message. #{fee_filter.build_json}")
|
123
|
-
conn.fee_rate = fee_filter.fee_rate
|
124
|
-
end
|
125
|
-
|
126
|
-
def on_ping(ping)
|
127
|
-
logger.info("receive ping message. #{ping.build_json}")
|
128
|
-
conn.send_message(ping.to_response)
|
129
|
-
end
|
130
|
-
|
131
|
-
def on_pong(pong)
|
132
|
-
logger.info("receive pong message. #{pong.build_json}")
|
133
|
-
# TODO calculate response
|
134
|
-
end
|
135
|
-
|
136
|
-
def on_get_headers(headers)
|
137
|
-
logger.info("receive getheaders message. #{headers.build_json}")
|
138
|
-
# TODO
|
139
|
-
end
|
140
|
-
|
141
|
-
def on_headers(headers)
|
142
|
-
logger.info("receive headers message. #{headers.build_json}")
|
143
|
-
# TODO
|
144
|
-
end
|
145
|
-
|
146
|
-
def on_block(block)
|
147
|
-
logger.info("receive block message. #{block.build_json}")
|
148
|
-
# TODO
|
149
|
-
end
|
150
|
-
|
151
|
-
def on_tx(tx)
|
152
|
-
logger.info("receive tx message. #{tx.build_json}")
|
153
|
-
# TODO
|
154
|
-
end
|
155
|
-
|
156
|
-
def on_not_found(not_found)
|
157
|
-
logger.info("receive notfound message. #{not_found.build_json}")
|
158
|
-
# TODO
|
159
|
-
end
|
160
|
-
|
161
|
-
def on_mem_pool
|
162
|
-
logger.info('receive mempool message.')
|
163
|
-
# TODO return mempool tx
|
164
|
-
end
|
165
|
-
|
166
|
-
def on_reject(reject)
|
167
|
-
logger.warn("receive reject message. #{reject.build_json}")
|
168
|
-
# TODO
|
169
|
-
end
|
170
|
-
|
171
|
-
def on_send_cmpct(cmpct)
|
172
|
-
logger.info("receive sendcmpct message. #{cmpct.build_json}")
|
173
|
-
# TODO if mode is high and version is 1, relay block with cmpctblock message
|
174
|
-
end
|
175
|
-
|
176
|
-
def on_inv(inv)
|
177
|
-
logger.info("receive inv message. #{inv.build_json}")
|
178
|
-
# TODO
|
179
|
-
end
|
180
|
-
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
data/lib/bitcoin/nodes/spv.rb
DELETED