tapyrus 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/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +100 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/tapyrusrb-cli +5 -0
- data/exe/tapyrusrbd +41 -0
- data/lib/openassets/marker_output.rb +20 -0
- data/lib/openassets/payload.rb +54 -0
- data/lib/openassets/util.rb +28 -0
- data/lib/openassets.rb +9 -0
- data/lib/tapyrus/base58.rb +38 -0
- data/lib/tapyrus/block.rb +77 -0
- data/lib/tapyrus/block_header.rb +88 -0
- data/lib/tapyrus/bloom_filter.rb +78 -0
- data/lib/tapyrus/chain_params.rb +90 -0
- data/lib/tapyrus/chainparams/mainnet.yml +41 -0
- data/lib/tapyrus/chainparams/regtest.yml +38 -0
- data/lib/tapyrus/chainparams/testnet.yml +41 -0
- data/lib/tapyrus/constants.rb +195 -0
- data/lib/tapyrus/descriptor.rb +147 -0
- data/lib/tapyrus/ext_key.rb +337 -0
- data/lib/tapyrus/key.rb +296 -0
- data/lib/tapyrus/key_path.rb +26 -0
- data/lib/tapyrus/logger.rb +42 -0
- data/lib/tapyrus/merkle_tree.rb +149 -0
- data/lib/tapyrus/message/addr.rb +35 -0
- data/lib/tapyrus/message/base.rb +28 -0
- data/lib/tapyrus/message/block.rb +46 -0
- data/lib/tapyrus/message/block_transaction_request.rb +45 -0
- data/lib/tapyrus/message/block_transactions.rb +31 -0
- data/lib/tapyrus/message/block_txn.rb +27 -0
- data/lib/tapyrus/message/cmpct_block.rb +42 -0
- data/lib/tapyrus/message/error.rb +10 -0
- data/lib/tapyrus/message/fee_filter.rb +27 -0
- data/lib/tapyrus/message/filter_add.rb +28 -0
- data/lib/tapyrus/message/filter_clear.rb +17 -0
- data/lib/tapyrus/message/filter_load.rb +39 -0
- data/lib/tapyrus/message/get_addr.rb +17 -0
- data/lib/tapyrus/message/get_block_txn.rb +27 -0
- data/lib/tapyrus/message/get_blocks.rb +29 -0
- data/lib/tapyrus/message/get_data.rb +21 -0
- data/lib/tapyrus/message/get_headers.rb +28 -0
- data/lib/tapyrus/message/header_and_short_ids.rb +57 -0
- data/lib/tapyrus/message/headers.rb +35 -0
- data/lib/tapyrus/message/headers_parser.rb +24 -0
- data/lib/tapyrus/message/inv.rb +21 -0
- data/lib/tapyrus/message/inventories_parser.rb +23 -0
- data/lib/tapyrus/message/inventory.rb +51 -0
- data/lib/tapyrus/message/mem_pool.rb +17 -0
- data/lib/tapyrus/message/merkle_block.rb +42 -0
- data/lib/tapyrus/message/network_addr.rb +63 -0
- data/lib/tapyrus/message/not_found.rb +21 -0
- data/lib/tapyrus/message/ping.rb +30 -0
- data/lib/tapyrus/message/pong.rb +26 -0
- data/lib/tapyrus/message/prefilled_tx.rb +29 -0
- data/lib/tapyrus/message/reject.rb +46 -0
- data/lib/tapyrus/message/send_cmpct.rb +43 -0
- data/lib/tapyrus/message/send_headers.rb +16 -0
- data/lib/tapyrus/message/tx.rb +30 -0
- data/lib/tapyrus/message/ver_ack.rb +17 -0
- data/lib/tapyrus/message/version.rb +69 -0
- data/lib/tapyrus/message.rb +70 -0
- data/lib/tapyrus/mnemonic/wordlist/chinese_simplified.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/chinese_traditional.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/english.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/french.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/italian.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/japanese.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/spanish.txt +2048 -0
- data/lib/tapyrus/mnemonic.rb +77 -0
- data/lib/tapyrus/network/connection.rb +73 -0
- data/lib/tapyrus/network/message_handler.rb +241 -0
- data/lib/tapyrus/network/peer.rb +223 -0
- data/lib/tapyrus/network/peer_discovery.rb +42 -0
- data/lib/tapyrus/network/pool.rb +135 -0
- data/lib/tapyrus/network.rb +13 -0
- data/lib/tapyrus/node/cli.rb +112 -0
- data/lib/tapyrus/node/configuration.rb +38 -0
- data/lib/tapyrus/node/spv.rb +79 -0
- data/lib/tapyrus/node.rb +7 -0
- data/lib/tapyrus/opcodes.rb +178 -0
- data/lib/tapyrus/out_point.rb +44 -0
- data/lib/tapyrus/rpc/http_server.rb +65 -0
- data/lib/tapyrus/rpc/request_handler.rb +150 -0
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +72 -0
- data/lib/tapyrus/rpc.rb +7 -0
- data/lib/tapyrus/script/multisig.rb +92 -0
- data/lib/tapyrus/script/script.rb +551 -0
- data/lib/tapyrus/script/script_error.rb +111 -0
- data/lib/tapyrus/script/script_interpreter.rb +668 -0
- data/lib/tapyrus/script/tx_checker.rb +81 -0
- data/lib/tapyrus/script_witness.rb +38 -0
- data/lib/tapyrus/secp256k1/native.rb +174 -0
- data/lib/tapyrus/secp256k1/ruby.rb +123 -0
- data/lib/tapyrus/secp256k1.rb +12 -0
- data/lib/tapyrus/slip39/share.rb +122 -0
- data/lib/tapyrus/slip39/sss.rb +245 -0
- data/lib/tapyrus/slip39/wordlist/english.txt +1024 -0
- data/lib/tapyrus/slip39.rb +93 -0
- data/lib/tapyrus/store/chain_entry.rb +67 -0
- data/lib/tapyrus/store/db/level_db.rb +98 -0
- data/lib/tapyrus/store/db.rb +9 -0
- data/lib/tapyrus/store/spv_chain.rb +101 -0
- data/lib/tapyrus/store.rb +9 -0
- data/lib/tapyrus/tx.rb +347 -0
- data/lib/tapyrus/tx_in.rb +89 -0
- data/lib/tapyrus/tx_out.rb +74 -0
- data/lib/tapyrus/util.rb +133 -0
- data/lib/tapyrus/validation.rb +115 -0
- data/lib/tapyrus/version.rb +3 -0
- data/lib/tapyrus/wallet/account.rb +151 -0
- data/lib/tapyrus/wallet/base.rb +162 -0
- data/lib/tapyrus/wallet/db.rb +81 -0
- data/lib/tapyrus/wallet/master_key.rb +110 -0
- data/lib/tapyrus/wallet.rb +8 -0
- data/lib/tapyrus.rb +219 -0
- data/tapyrusrb.conf.sample +0 -0
- data/tapyrusrb.gemspec +47 -0
- metadata +451 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
|
|
3
|
+
# merkle tree
|
|
4
|
+
class MerkleTree
|
|
5
|
+
|
|
6
|
+
attr_accessor :root
|
|
7
|
+
|
|
8
|
+
def initialize(root = nil)
|
|
9
|
+
@root = root
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def merkle_root
|
|
13
|
+
root.value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.build_from_leaf(txids)
|
|
17
|
+
if txids.size == 1
|
|
18
|
+
nodes = [Node.new(txids.first)]
|
|
19
|
+
else
|
|
20
|
+
nodes = txids.each_slice(2).map{ |m|
|
|
21
|
+
left = Node.new(m[0])
|
|
22
|
+
right = Node.new(m[1] ? m[1] : m[0])
|
|
23
|
+
[left, right]
|
|
24
|
+
}.flatten
|
|
25
|
+
end
|
|
26
|
+
new(build_initial_tree(nodes))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# https://bitcoin.org/en/developer-reference#creating-a-merkleblock-message
|
|
30
|
+
def self.build_partial(tx_count, hashes, flags)
|
|
31
|
+
flags = flags.each_char.map(&:to_i)
|
|
32
|
+
root = build_initial_tree( Array.new(tx_count) { Node.new })
|
|
33
|
+
current_node = root
|
|
34
|
+
hash_index = 0
|
|
35
|
+
flags.each do |f|
|
|
36
|
+
current_node.flag = f
|
|
37
|
+
if f.zero? || current_node.leaf?
|
|
38
|
+
current_node.value = hashes[hash_index]
|
|
39
|
+
hash_index += 1
|
|
40
|
+
end
|
|
41
|
+
current_node = current_node.next_partial
|
|
42
|
+
if hash_index == hashes.size
|
|
43
|
+
if current_node&.leaf?
|
|
44
|
+
current_node.value = hashes.last
|
|
45
|
+
end
|
|
46
|
+
break
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
new(root)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.build_initial_tree(nodes)
|
|
53
|
+
while nodes.size != 1
|
|
54
|
+
nodes = nodes.each_slice(2).map { |m|
|
|
55
|
+
parent = Node.new
|
|
56
|
+
parent.left = m[0]
|
|
57
|
+
parent.right = m[1] ? m[1] : m[0].dup
|
|
58
|
+
parent
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
nodes.first
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def find_node(value)
|
|
65
|
+
root.find_node(value)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# node of merkle tree
|
|
69
|
+
class Node
|
|
70
|
+
|
|
71
|
+
attr_accessor :flag
|
|
72
|
+
attr_accessor :value
|
|
73
|
+
attr_accessor :parent
|
|
74
|
+
attr_accessor :left
|
|
75
|
+
attr_accessor :right
|
|
76
|
+
|
|
77
|
+
def initialize(value = nil)
|
|
78
|
+
@value = value
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def left=(node)
|
|
82
|
+
node.parent = self
|
|
83
|
+
@left = node
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def right=(node)
|
|
87
|
+
node.parent = self
|
|
88
|
+
@right = node
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def value
|
|
92
|
+
return @value if @value
|
|
93
|
+
self.right = left.dup unless right
|
|
94
|
+
Tapyrus.double_sha256([left.value + right.value].pack('H*')).bth
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def root?
|
|
98
|
+
parent.nil?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def leaf?
|
|
102
|
+
right.nil? && left.nil?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def partial?
|
|
106
|
+
!flag.nil?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def next_partial
|
|
110
|
+
return nil if root? && (flag.zero? || (left.nil? && right.nil?) || (left.partial? && right.partial?))
|
|
111
|
+
return parent.next_partial if flag.zero? || leaf?
|
|
112
|
+
return left unless left.partial?
|
|
113
|
+
self.right = left.dup unless right
|
|
114
|
+
right.partial? ? parent.next_partial : right
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# calculate the depth of this node in the tree.
|
|
118
|
+
def depth
|
|
119
|
+
d = 0
|
|
120
|
+
current_node = self
|
|
121
|
+
until current_node.root? do
|
|
122
|
+
current_node = current_node.parent
|
|
123
|
+
d += 1
|
|
124
|
+
end
|
|
125
|
+
d
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @param target value to be found
|
|
129
|
+
# @return node which has same value as target. nil if this node and any children don't have same value.
|
|
130
|
+
def find_node(target)
|
|
131
|
+
return self if value == target
|
|
132
|
+
return nil if flag && flag.zero?
|
|
133
|
+
return left&.find_node(target) || right&.find_node(target)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def index
|
|
137
|
+
i = 0
|
|
138
|
+
d = 1
|
|
139
|
+
current_node = self
|
|
140
|
+
until current_node.root? do
|
|
141
|
+
i += d if current_node.parent.right == current_node
|
|
142
|
+
current_node = current_node.parent
|
|
143
|
+
d *= 2
|
|
144
|
+
end
|
|
145
|
+
i
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'ipaddr'
|
|
2
|
+
|
|
3
|
+
module Tapyrus
|
|
4
|
+
module Message
|
|
5
|
+
|
|
6
|
+
# addr message
|
|
7
|
+
# https://bitcoin.org/en/developer-reference#addr
|
|
8
|
+
class Addr < Base
|
|
9
|
+
|
|
10
|
+
COMMAND = 'addr'
|
|
11
|
+
|
|
12
|
+
attr_reader :addrs
|
|
13
|
+
|
|
14
|
+
def initialize(addrs = [])
|
|
15
|
+
@addrs = addrs
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.parse_from_payload(payload)
|
|
19
|
+
buf = StringIO.new(payload)
|
|
20
|
+
addr_count = Tapyrus.unpack_var_int_from_io(buf)
|
|
21
|
+
addr = new
|
|
22
|
+
addr_count.times do
|
|
23
|
+
addr.addrs << NetworkAddr.parse_from_payload(buf)
|
|
24
|
+
end
|
|
25
|
+
addr
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_payload
|
|
29
|
+
Tapyrus.pack_var_int(addrs.length) << addrs.map(&:to_payload).join
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# Base message class
|
|
5
|
+
class Base
|
|
6
|
+
include Tapyrus::Util
|
|
7
|
+
extend Tapyrus::Util
|
|
8
|
+
|
|
9
|
+
# generate message header (binary format)
|
|
10
|
+
# https://bitcoin.org/en/developer-reference#message-headers
|
|
11
|
+
def to_pkt
|
|
12
|
+
payload = to_payload
|
|
13
|
+
magic = Tapyrus.chain_params.magic_head.htb
|
|
14
|
+
command_name = self.class.const_get(:COMMAND, false).ljust(12, "\x00")
|
|
15
|
+
payload_size = [payload.bytesize].pack('V')
|
|
16
|
+
checksum = Tapyrus.double_sha256(payload)[0...4]
|
|
17
|
+
magic << command_name << payload_size << checksum << payload
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# abstract method
|
|
21
|
+
def to_payload
|
|
22
|
+
raise 'to_payload must be implemented in a child class.'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# block message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#block
|
|
6
|
+
class Block < Base
|
|
7
|
+
|
|
8
|
+
attr_accessor :header
|
|
9
|
+
attr_accessor :transactions
|
|
10
|
+
attr_accessor :use_segwit
|
|
11
|
+
|
|
12
|
+
COMMAND = 'block'
|
|
13
|
+
|
|
14
|
+
def initialize(header, transactions = [], use_segwit = false)
|
|
15
|
+
@header = header
|
|
16
|
+
@transactions = transactions
|
|
17
|
+
@use_segwit = use_segwit
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.parse_from_payload(payload)
|
|
21
|
+
buf = StringIO.new(payload)
|
|
22
|
+
header = Tapyrus::BlockHeader.parse_from_payload(buf.read(80))
|
|
23
|
+
transactions = []
|
|
24
|
+
unless buf.eof?
|
|
25
|
+
tx_count = Tapyrus.unpack_var_int_from_io(buf)
|
|
26
|
+
tx_count.times do
|
|
27
|
+
transactions << Tapyrus::Tx.parse_from_payload(buf)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
new(header, transactions)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_payload
|
|
34
|
+
header.to_payload << Tapyrus.pack_var_int(transactions.size) <<
|
|
35
|
+
transactions.map{|t|use_segwit ? t.to_payload : t.serialize_old_format}.join
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# generate Tapyrus::Block object.
|
|
39
|
+
def to_block
|
|
40
|
+
Tapyrus::Block.new(header, transactions)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# BIP-152 Compact Block's data format.
|
|
5
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#BlockTransactionsRequest
|
|
6
|
+
class BlockTransactionRequest
|
|
7
|
+
|
|
8
|
+
attr_accessor :block_hash # When matching with Tapyrus::BlockHeader#hash It is necessary to reverse the byte order.
|
|
9
|
+
attr_accessor :indexes
|
|
10
|
+
|
|
11
|
+
def initialize(block_hash, indexes)
|
|
12
|
+
@block_hash = block_hash
|
|
13
|
+
@indexes = indexes
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.parse_from_payload(payload)
|
|
17
|
+
buf = StringIO.new(payload)
|
|
18
|
+
block_hash = buf.read(32).bth
|
|
19
|
+
index_len = Tapyrus.unpack_var_int_from_io(buf)
|
|
20
|
+
indexes = index_len.times.map{Tapyrus.unpack_var_int_from_io(buf)}
|
|
21
|
+
# index data differentially encoded
|
|
22
|
+
offset = 0
|
|
23
|
+
index_len.times do |i|
|
|
24
|
+
index = indexes[i]
|
|
25
|
+
index += offset
|
|
26
|
+
indexes[i] = index
|
|
27
|
+
offset = index + 1
|
|
28
|
+
end
|
|
29
|
+
self.new(block_hash, indexes)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_payload
|
|
33
|
+
p = block_hash.htb << Tapyrus.pack_var_int(indexes.size)
|
|
34
|
+
indexes.size.times do |i|
|
|
35
|
+
index = indexes[i]
|
|
36
|
+
index -= indexes[i-1] + 1 if i > 0
|
|
37
|
+
p << Tapyrus.pack_var_int(index)
|
|
38
|
+
end
|
|
39
|
+
p
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# BIP-152 Compact Block's data format.
|
|
5
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#BlockTransactions
|
|
6
|
+
class BlockTransactions
|
|
7
|
+
|
|
8
|
+
attr_accessor :block_hash
|
|
9
|
+
attr_accessor :transactions
|
|
10
|
+
|
|
11
|
+
def initialize(block_hash, transactions)
|
|
12
|
+
@block_hash = block_hash
|
|
13
|
+
@transactions = transactions
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.parse_from_payload(payload)
|
|
17
|
+
buf = StringIO.new(payload)
|
|
18
|
+
block_hash = buf.read(32).bth
|
|
19
|
+
tx_count = Tapyrus.unpack_var_int_from_io(buf)
|
|
20
|
+
txn = tx_count.times.map{Tapyrus::Tx.parse_from_payload(buf)}
|
|
21
|
+
self.new(block_hash, txn)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_payload
|
|
25
|
+
block_hash.htb << Tapyrus.pack_var_int(transactions.size) << transactions.map(&:to_payload).join
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# blocktxn message.
|
|
5
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki#blocktxn
|
|
6
|
+
class BlockTxn < Base
|
|
7
|
+
|
|
8
|
+
COMMAND = 'blocktxn'
|
|
9
|
+
|
|
10
|
+
attr_accessor :block_transactions
|
|
11
|
+
|
|
12
|
+
def initialize(block_transactions)
|
|
13
|
+
@block_transactions = block_transactions
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.parse_from_payload(payload)
|
|
17
|
+
self.new(BlockTransactions.parse_from_payload(payload))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_payload
|
|
21
|
+
block_transactions.to_payload
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# cmpctblock message
|
|
5
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
|
|
6
|
+
class CmpctBlock < Base
|
|
7
|
+
|
|
8
|
+
COMMAND = 'cmpctblock'
|
|
9
|
+
|
|
10
|
+
attr_accessor :header_and_short_ids
|
|
11
|
+
|
|
12
|
+
def initialize(header_and_short_ids)
|
|
13
|
+
@header_and_short_ids = header_and_short_ids
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# generate CmpctBlock from Block data.
|
|
17
|
+
# @param [Tapyrus::Block] block the block to generate CmpctBlock.
|
|
18
|
+
# @param [Integer] version Compact Block version specified by sendcmpct message.
|
|
19
|
+
# @param [Integer] nonce
|
|
20
|
+
# @return [Tapyrus::Message::CmpctBlock]
|
|
21
|
+
def self.from_block(block, version, nonce = SecureRandom.hex(8).to_i(16))
|
|
22
|
+
raise 'Unsupported version.' unless [1, 2].include?(version)
|
|
23
|
+
h = HeaderAndShortIDs.new(block.header, nonce)
|
|
24
|
+
block.transactions[1..-1].each do |tx|
|
|
25
|
+
h.short_ids << h.short_id(version == 1 ? tx.txid : tx.wtxid)
|
|
26
|
+
end
|
|
27
|
+
h.prefilled_txn << PrefilledTx.new(0, block.transactions.first)
|
|
28
|
+
self.new(h)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.parse_from_payload(payload)
|
|
32
|
+
self.new(HeaderAndShortIDs.parse_from_payload(payload))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_payload
|
|
36
|
+
header_and_short_ids.to_payload
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# feefilter message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#feefilter
|
|
6
|
+
class FeeFilter < Base
|
|
7
|
+
|
|
8
|
+
COMMAND = 'feefilter'
|
|
9
|
+
|
|
10
|
+
# The fee rate (in satoshis per kilobyte)
|
|
11
|
+
attr_accessor :fee_rate
|
|
12
|
+
|
|
13
|
+
def initialize(fee_rate)
|
|
14
|
+
@fee_rate = fee_rate
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.parse_from_payload(payload)
|
|
18
|
+
new(payload.unpack('Q').first)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_payload
|
|
22
|
+
[fee_rate].pack('Q')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# filteradd message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#filteradd
|
|
6
|
+
class FilterAdd < Base
|
|
7
|
+
|
|
8
|
+
COMMAND = 'filteradd'
|
|
9
|
+
|
|
10
|
+
# element must be sent in the byte order they would use when appearing in a raw transaction;
|
|
11
|
+
attr_accessor :element
|
|
12
|
+
|
|
13
|
+
def initialize(element)
|
|
14
|
+
@element = element
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.parse_from_payload(payload)
|
|
18
|
+
new(Tapyrus.unpack_var_string(payload).first.bth)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_payload
|
|
22
|
+
Tapyrus.pack_var_string(element.htb)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# filterload message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#filterload
|
|
6
|
+
class FilterLoad < Base
|
|
7
|
+
|
|
8
|
+
COMMAND = 'filterload'
|
|
9
|
+
|
|
10
|
+
BLOOM_UPDATE_NONE = 0
|
|
11
|
+
BLOOM_UPDATE_ALL = 1
|
|
12
|
+
BLOOM_UPDATE_P2PUBKEY_ONLY = 2
|
|
13
|
+
|
|
14
|
+
attr_accessor :filter
|
|
15
|
+
attr_accessor :flag
|
|
16
|
+
|
|
17
|
+
def initialize(filter, flag = BLOOM_UPDATE_ALL)
|
|
18
|
+
@filter = filter
|
|
19
|
+
@flag = flag
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.parse_from_payload(payload)
|
|
23
|
+
buf = StringIO.new(payload)
|
|
24
|
+
filter_count = Tapyrus.unpack_var_int_from_io(buf)
|
|
25
|
+
filter = buf.read(filter_count).unpack('C*')
|
|
26
|
+
func_count = buf.read(4).unpack('V').first
|
|
27
|
+
tweak = buf.read(4).unpack('V').first
|
|
28
|
+
flag = buf.read(1).unpack('C').first
|
|
29
|
+
FilterLoad.new(Tapyrus::BloomFilter.new(filter, func_count, tweak), flag)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_payload
|
|
33
|
+
Tapyrus.pack_var_int(filter.filter.size) << filter.filter.pack('C*') << [filter.hash_funcs, filter.tweak, flag].pack('VVC')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# getblocktxn message.
|
|
5
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
|
|
6
|
+
class GetBlockTxn < Base
|
|
7
|
+
|
|
8
|
+
COMMAND = 'getblocktxn'
|
|
9
|
+
|
|
10
|
+
attr_accessor :request
|
|
11
|
+
|
|
12
|
+
def initialize(request)
|
|
13
|
+
@request = request
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.parse_from_payload(payload)
|
|
17
|
+
self.new(BlockTransactionRequest.parse_from_payload(payload))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_payload
|
|
21
|
+
request.to_payload
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# block message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#getblocks
|
|
6
|
+
class GetBlocks < Base
|
|
7
|
+
include HeadersParser
|
|
8
|
+
extend HeadersParser
|
|
9
|
+
|
|
10
|
+
COMMAND = 'getblocks'
|
|
11
|
+
|
|
12
|
+
# protocol version
|
|
13
|
+
attr_accessor :version
|
|
14
|
+
|
|
15
|
+
# block header hashes
|
|
16
|
+
attr_accessor :hashes
|
|
17
|
+
|
|
18
|
+
attr_accessor :stop_hash
|
|
19
|
+
|
|
20
|
+
def initialize(version, hashes, stop_hash = DEFAULT_STOP_HASH)
|
|
21
|
+
@version = version
|
|
22
|
+
@hashes = hashes
|
|
23
|
+
@stop_hash = stop_hash
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# getdadta message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#getdata
|
|
6
|
+
class GetData < Base
|
|
7
|
+
include InventoriesParser
|
|
8
|
+
extend InventoriesParser
|
|
9
|
+
|
|
10
|
+
COMMAND ='getdata'
|
|
11
|
+
|
|
12
|
+
attr_reader :inventories
|
|
13
|
+
|
|
14
|
+
def initialize(inventories = [])
|
|
15
|
+
@inventories = inventories
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Tapyrus
|
|
2
|
+
module Message
|
|
3
|
+
|
|
4
|
+
# getheaders message
|
|
5
|
+
# https://bitcoin.org/en/developer-reference#getheaders
|
|
6
|
+
class GetHeaders < Base
|
|
7
|
+
include HeadersParser
|
|
8
|
+
extend HeadersParser
|
|
9
|
+
|
|
10
|
+
COMMAND = 'getheaders'
|
|
11
|
+
|
|
12
|
+
# protocol version
|
|
13
|
+
attr_accessor :version
|
|
14
|
+
|
|
15
|
+
# block header hashes
|
|
16
|
+
attr_accessor :hashes
|
|
17
|
+
|
|
18
|
+
attr_accessor :stop_hash
|
|
19
|
+
|
|
20
|
+
def initialize(version, hashes, stop_hash = DEFAULT_STOP_HASH)
|
|
21
|
+
@version = version
|
|
22
|
+
@hashes = hashes
|
|
23
|
+
@stop_hash = stop_hash
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|