bitcoinrb 0.3.1 → 0.7.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 +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +6 -3
- data/README.md +17 -6
- data/bitcoinrb.gemspec +9 -8
- data/exe/bitcoinrbd +5 -0
- data/lib/bitcoin.rb +35 -19
- data/lib/bitcoin/bip85_entropy.rb +111 -0
- data/lib/bitcoin/block_filter.rb +14 -0
- data/lib/bitcoin/block_header.rb +2 -0
- data/lib/bitcoin/chain_params.rb +9 -8
- data/lib/bitcoin/chainparams/regtest.yml +1 -1
- data/lib/bitcoin/chainparams/signet.yml +39 -0
- data/lib/bitcoin/chainparams/testnet.yml +1 -1
- data/lib/bitcoin/constants.rb +45 -12
- data/lib/bitcoin/descriptor.rb +1 -1
- data/lib/bitcoin/errors.rb +19 -0
- data/lib/bitcoin/ext.rb +5 -0
- data/lib/bitcoin/ext/ecdsa.rb +31 -0
- data/lib/bitcoin/ext/json_parser.rb +46 -0
- data/lib/bitcoin/ext_key.rb +50 -19
- data/lib/bitcoin/key.rb +46 -29
- data/lib/bitcoin/key_path.rb +12 -5
- data/lib/bitcoin/message.rb +79 -0
- data/lib/bitcoin/message/addr_v2.rb +34 -0
- data/lib/bitcoin/message/base.rb +17 -0
- data/lib/bitcoin/message/cf_parser.rb +16 -0
- data/lib/bitcoin/message/cfcheckpt.rb +36 -0
- data/lib/bitcoin/message/cfheaders.rb +40 -0
- data/lib/bitcoin/message/cfilter.rb +35 -0
- data/lib/bitcoin/message/fee_filter.rb +1 -1
- data/lib/bitcoin/message/filter_load.rb +3 -3
- data/lib/bitcoin/message/get_cfcheckpt.rb +29 -0
- data/lib/bitcoin/message/get_cfheaders.rb +24 -0
- data/lib/bitcoin/message/get_cfilters.rb +25 -0
- data/lib/bitcoin/message/header_and_short_ids.rb +1 -1
- data/lib/bitcoin/message/inventory.rb +1 -1
- data/lib/bitcoin/message/merkle_block.rb +1 -1
- data/lib/bitcoin/message/network_addr.rb +141 -18
- data/lib/bitcoin/message/ping.rb +1 -1
- data/lib/bitcoin/message/pong.rb +1 -1
- data/lib/bitcoin/message/send_addr_v2.rb +13 -0
- data/lib/bitcoin/message/send_cmpct.rb +2 -2
- data/lib/bitcoin/message/version.rb +7 -0
- data/lib/bitcoin/mnemonic.rb +7 -7
- data/lib/bitcoin/network/peer.rb +9 -4
- data/lib/bitcoin/network/peer_discovery.rb +1 -1
- data/lib/bitcoin/node/cli.rb +14 -10
- data/lib/bitcoin/node/configuration.rb +3 -1
- data/lib/bitcoin/node/spv.rb +9 -1
- data/lib/bitcoin/opcodes.rb +14 -1
- data/lib/bitcoin/out_point.rb +7 -0
- data/lib/bitcoin/payment_code.rb +92 -0
- data/lib/bitcoin/psbt/hd_key_path.rb +1 -1
- data/lib/bitcoin/psbt/input.rb +8 -17
- data/lib/bitcoin/psbt/output.rb +1 -1
- data/lib/bitcoin/psbt/tx.rb +11 -16
- data/lib/bitcoin/rpc/bitcoin_core_client.rb +22 -12
- data/lib/bitcoin/rpc/request_handler.rb +3 -3
- data/lib/bitcoin/script/script.rb +68 -28
- data/lib/bitcoin/script/script_error.rb +27 -1
- data/lib/bitcoin/script/script_interpreter.rb +164 -67
- data/lib/bitcoin/script/tx_checker.rb +64 -14
- data/lib/bitcoin/secp256k1.rb +1 -0
- data/lib/bitcoin/secp256k1/native.rb +138 -25
- data/lib/bitcoin/secp256k1/rfc6979.rb +43 -0
- data/lib/bitcoin/secp256k1/ruby.rb +82 -54
- data/lib/bitcoin/sighash_generator.rb +156 -0
- data/lib/bitcoin/store.rb +2 -1
- data/lib/bitcoin/store/chain_entry.rb +1 -0
- data/lib/bitcoin/store/db/level_db.rb +2 -2
- data/lib/bitcoin/store/utxo_db.rb +226 -0
- data/lib/bitcoin/tx.rb +17 -88
- data/lib/bitcoin/tx_in.rb +4 -5
- data/lib/bitcoin/tx_out.rb +2 -3
- data/lib/bitcoin/util.rb +34 -6
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet.rb +1 -0
- data/lib/bitcoin/wallet/account.rb +2 -1
- data/lib/bitcoin/wallet/base.rb +3 -3
- data/lib/bitcoin/wallet/db.rb +1 -1
- data/lib/bitcoin/wallet/master_key.rb +1 -0
- data/lib/bitcoin/wallet/utxo.rb +37 -0
- metadata +66 -32
@@ -20,7 +20,7 @@ module Bitcoin
|
|
20
20
|
m = new
|
21
21
|
buf = StringIO.new(payload)
|
22
22
|
m.header = Bitcoin::BlockHeader.parse_from_payload(buf.read(80))
|
23
|
-
m.tx_count = buf.read(4).
|
23
|
+
m.tx_count = buf.read(4).unpack1('V')
|
24
24
|
hash_count = Bitcoin.unpack_var_int_from_io(buf)
|
25
25
|
hash_count.times do
|
26
26
|
m.hashes << buf.read(32).bth
|
@@ -1,10 +1,16 @@
|
|
1
1
|
require 'ipaddr'
|
2
|
+
require 'base32'
|
2
3
|
|
3
4
|
module Bitcoin
|
4
5
|
module Message
|
5
6
|
|
7
|
+
NETWORK_ID = {ipv4: 0x01, ipv6: 0x02, tor_v2: 0x03, tor_v3: 0x04, i2p: 0x05, cjdns: 0x06}
|
8
|
+
INTERNAL_IN_IPV6_PREFIX = "fd6b:88c0:8724"
|
9
|
+
|
6
10
|
class NetworkAddr
|
7
11
|
|
12
|
+
TYPE = {legacy: 0x01, addr_v2: 0x02}
|
13
|
+
|
8
14
|
# unix time.
|
9
15
|
# Nodes advertising their own IP address set this to the current time.
|
10
16
|
# Nodes advertising IP addresses they’ve connected to set this to the last time they connected to that node.
|
@@ -14,47 +20,164 @@ module Bitcoin
|
|
14
20
|
# The services the node advertised in its version message.
|
15
21
|
attr_accessor :services
|
16
22
|
|
17
|
-
attr_accessor :
|
23
|
+
attr_accessor :net # network ID that defined by BIP-155
|
24
|
+
|
25
|
+
# Network address. The interpretation depends on networkID.
|
26
|
+
# If ipv4 or ipv6 this field is a IPAddr object, otherwise hex string.
|
27
|
+
attr_accessor :addr
|
18
28
|
|
19
29
|
attr_accessor :port
|
20
30
|
|
21
31
|
attr_reader :skip_time
|
22
32
|
|
23
|
-
def initialize(ip: '127.0.0.1', port: Bitcoin.chain_params.default_port,
|
33
|
+
def initialize(ip: '127.0.0.1', port: Bitcoin.chain_params.default_port,
|
34
|
+
services: DEFAULT_SERVICE_FLAGS, time: Time.now.to_i, net: NETWORK_ID[:ipv4])
|
24
35
|
@time = time
|
25
|
-
@ip_addr = IPAddr.new(ip)
|
26
36
|
@port = port
|
27
37
|
@services = services
|
38
|
+
@net = net
|
39
|
+
case net
|
40
|
+
when NETWORK_ID[:ipv4], NETWORK_ID[:ipv6]
|
41
|
+
@addr = IPAddr.new(ip) if ip
|
42
|
+
end
|
28
43
|
end
|
29
44
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
45
|
+
# Parse addr payload
|
46
|
+
# @param [String] payload payload of addr
|
47
|
+
# @param [Integer] type Address format type
|
48
|
+
# @return [NetworkAddr]
|
49
|
+
def self.parse_from_payload(payload, type: TYPE[:legacy])
|
50
|
+
case type
|
51
|
+
when TYPE[:legacy]
|
52
|
+
load_legacy_payload(payload)
|
53
|
+
when TYPE[:addr_v2]
|
54
|
+
load_addr_v2_payload(payload)
|
55
|
+
else
|
56
|
+
raise Bitcoin::Message::Error, "Unknown type: #{type}."
|
57
|
+
end
|
39
58
|
end
|
40
59
|
|
41
60
|
def self.local_addr
|
42
61
|
addr = new
|
43
|
-
addr.
|
62
|
+
addr.addr = IPAddr.new('127.0.0.1')
|
44
63
|
addr.port = Bitcoin.chain_params.default_port
|
45
64
|
addr.services = DEFAULT_SERVICE_FLAGS
|
46
65
|
addr
|
47
66
|
end
|
48
67
|
|
49
|
-
|
50
|
-
|
68
|
+
# Show addr string. e.g 127.0.0.1
|
69
|
+
def addr_string
|
70
|
+
case net
|
71
|
+
when NETWORK_ID[:ipv4]
|
72
|
+
addr.native
|
73
|
+
when NETWORK_ID[:ipv6]
|
74
|
+
if addr.to_s.start_with?(INTERNAL_IN_IPV6_PREFIX)
|
75
|
+
Base32.encode(addr.hton[6..-1]).downcase.delete('=') + ".internal"
|
76
|
+
else
|
77
|
+
addr.to_s
|
78
|
+
end
|
79
|
+
when NETWORK_ID[:tor_v2]
|
80
|
+
Base32.encode(addr.htb).downcase + ".onion"
|
81
|
+
when NETWORK_ID[:tor_v3]
|
82
|
+
# TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
|
83
|
+
pubkey = addr.htb
|
84
|
+
checksum = OpenSSL::Digest.new('SHA3-256').digest('.onion checksum' + pubkey + "\x03")
|
85
|
+
Base32.encode(pubkey + checksum[0...2] + "\x03").downcase + ".onion"
|
86
|
+
when NETWORK_ID[:i2p]
|
87
|
+
Base32.encode(addr.htb).downcase.delete('=') + ".b32.i2p"
|
88
|
+
when NETWORK_ID[:cjdns]
|
89
|
+
addr.to_s
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_payload(skip_time = false, type: TYPE[:legacy])
|
94
|
+
case type
|
95
|
+
when TYPE[:legacy]
|
96
|
+
legacy_payload(skip_time)
|
97
|
+
when TYPE[:addr_v2]
|
98
|
+
v2_payload
|
99
|
+
else
|
100
|
+
raise Bitcoin::Message::Error, "Unknown type: #{type}."
|
101
|
+
end
|
51
102
|
end
|
52
103
|
|
53
|
-
|
104
|
+
# Load addr payload with legacy format.
|
105
|
+
def self.load_legacy_payload(payload)
|
106
|
+
buf = payload.is_a?(String) ? StringIO.new(payload) : payload
|
107
|
+
has_time = buf.size > 26
|
108
|
+
addr = NetworkAddr.new(time: nil)
|
109
|
+
addr.time = buf.read(4).unpack1('V') if has_time
|
110
|
+
addr.services = buf.read(8).unpack1('Q')
|
111
|
+
addr.addr = IPAddr::new_ntoh(buf.read(16))
|
112
|
+
addr.port = buf.read(2).unpack1('n')
|
113
|
+
addr
|
114
|
+
end
|
115
|
+
|
116
|
+
# Load addr payload with addr v2 format.
|
117
|
+
def self.load_addr_v2_payload(payload)
|
118
|
+
buf = payload.is_a?(String) ? StringIO.new(payload) : payload
|
119
|
+
addr = NetworkAddr.new(time: buf.read(4).unpack1('V'))
|
120
|
+
addr.services = Bitcoin.unpack_var_int_from_io(buf)
|
121
|
+
addr.net = buf.read(1).unpack1('C')
|
122
|
+
raise Bitcoin::Message::Error, "Unknown network id: #{addr.net}" unless NETWORK_ID.value?(addr.net)
|
123
|
+
addr_len = Bitcoin.unpack_var_int_from_io(buf)
|
124
|
+
addr.addr = case addr.net
|
125
|
+
when NETWORK_ID[:ipv4]
|
126
|
+
raise Bitcoin::Message::Error, "Invalid IPv4 address." unless addr_len == 4
|
127
|
+
IPAddr::new_ntoh(buf.read(addr_len))
|
128
|
+
when NETWORK_ID[:ipv6]
|
129
|
+
raise Bitcoin::Message::Error, "Invalid IPv6 address." unless addr_len == 16
|
130
|
+
a = IPAddr::new_ntoh(buf.read(addr_len))
|
131
|
+
raise Bitcoin::Message::Error, "Invalid IPv6 address." if a.ipv4_mapped?
|
132
|
+
a
|
133
|
+
when NETWORK_ID[:tor_v2]
|
134
|
+
raise Bitcoin::Message::Error, "Invalid Tor v2 address." unless addr_len == 10
|
135
|
+
buf.read(addr_len).bth
|
136
|
+
when NETWORK_ID[:tor_v3]
|
137
|
+
raise Bitcoin::Message::Error, "Invalid Tor v3 address." unless addr_len == 32
|
138
|
+
buf.read(addr_len).bth
|
139
|
+
when NETWORK_ID[:i2p]
|
140
|
+
raise Bitcoin::Message::Error, "Invalid I2P address." unless addr_len == 32
|
141
|
+
buf.read(addr_len).bth
|
142
|
+
when NETWORK_ID[:cjdns]
|
143
|
+
raise Bitcoin::Message::Error, "Invalid CJDNS address." unless addr_len == 16
|
144
|
+
a = IPAddr::new_ntoh(buf.read(addr_len))
|
145
|
+
raise Bitcoin::Message::Error, "Invalid CJDNS address." unless a.to_s.start_with?('fc00:')
|
146
|
+
a
|
147
|
+
end
|
148
|
+
addr.port = buf.read(2).unpack1('n')
|
149
|
+
addr
|
150
|
+
end
|
151
|
+
|
152
|
+
def legacy_payload(skip_time)
|
54
153
|
p = ''
|
55
154
|
p << [time].pack('V') unless skip_time
|
56
|
-
|
57
|
-
p << [services].pack('Q') <<
|
155
|
+
ip = addr.ipv4? ? addr.ipv4_mapped : addr
|
156
|
+
p << [services].pack('Q') << ip.hton << [port].pack('n')
|
157
|
+
end
|
158
|
+
|
159
|
+
def v2_payload
|
160
|
+
p = [time].pack('V')
|
161
|
+
p << Bitcoin.pack_var_int(services)
|
162
|
+
p << [net].pack('C')
|
163
|
+
case net
|
164
|
+
when NETWORK_ID[:ipv4]
|
165
|
+
p << Bitcoin.pack_var_int(4)
|
166
|
+
p << addr.to_i.to_s(16).htb
|
167
|
+
when NETWORK_ID[:ipv6]
|
168
|
+
p << Bitcoin.pack_var_int(16)
|
169
|
+
p << addr.hton
|
170
|
+
when NETWORK_ID[:tor_v2]
|
171
|
+
p << Bitcoin.pack_var_int(10)
|
172
|
+
when NETWORK_ID[:tor_v3]
|
173
|
+
p << Bitcoin.pack_var_int(32)
|
174
|
+
when NETWORK_ID[:i2p]
|
175
|
+
p << Bitcoin.pack_var_int(32)
|
176
|
+
when NETWORK_ID[:cjdns]
|
177
|
+
p << Bitcoin.pack_var_int(16)
|
178
|
+
end
|
179
|
+
p << [port].pack('n')
|
180
|
+
p
|
58
181
|
end
|
59
182
|
|
60
183
|
end
|
data/lib/bitcoin/message/ping.rb
CHANGED
data/lib/bitcoin/message/pong.rb
CHANGED
@@ -21,8 +21,8 @@ module Bitcoin
|
|
21
21
|
|
22
22
|
def self.parse_from_payload(payload)
|
23
23
|
buf = StringIO.new(payload)
|
24
|
-
mode = buf.read(1).
|
25
|
-
version = buf.read(8).
|
24
|
+
mode = buf.read(1).unpack1('c')
|
25
|
+
version = buf.read(8).unpack1('Q')
|
26
26
|
new(mode, version)
|
27
27
|
end
|
28
28
|
|
@@ -64,6 +64,13 @@ module Bitcoin
|
|
64
64
|
( version >= 70001 && payload ) ? unpack_boolean(payload) : [ true, nil ]
|
65
65
|
end
|
66
66
|
|
67
|
+
# Check whether +service_flag+ support this version.
|
68
|
+
# @param [Integer] service_flag the service flags.
|
69
|
+
# @return [Boolean] whether support +service_flag+
|
70
|
+
def support?(service_flag)
|
71
|
+
(services & service_flag) != 0
|
72
|
+
end
|
73
|
+
|
67
74
|
end
|
68
75
|
end
|
69
76
|
end
|
data/lib/bitcoin/mnemonic.rb
CHANGED
@@ -6,11 +6,11 @@ module Bitcoin
|
|
6
6
|
|
7
7
|
WORD_DIR = "#{__dir__}/mnemonic/wordlist"
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :language
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
raise ArgumentError, 'specified language is not supported.' unless Mnemonic.word_lists.include?(
|
13
|
-
@
|
11
|
+
def initialize(language)
|
12
|
+
raise ArgumentError, 'specified language is not supported.' unless Mnemonic.word_lists.include?(language)
|
13
|
+
@language = language
|
14
14
|
end
|
15
15
|
|
16
16
|
# get support language list
|
@@ -39,7 +39,7 @@ module Bitcoin
|
|
39
39
|
# @return [Array] the array of mnemonic word.
|
40
40
|
def to_mnemonic(entropy)
|
41
41
|
raise ArgumentError, 'entropy is empty.' if entropy.nil? || entropy.empty?
|
42
|
-
e = entropy.htb.
|
42
|
+
e = entropy.htb.unpack1('B*')
|
43
43
|
seed = e + checksum(e)
|
44
44
|
mnemonic_index = seed.chars.each_slice(11).map{|i|i.join.to_i(2)}
|
45
45
|
word_master = load_words
|
@@ -61,7 +61,7 @@ module Bitcoin
|
|
61
61
|
# @param [String] entropy an entropy with bit string format
|
62
62
|
# @return [String] an entropy checksum with bit string format
|
63
63
|
def checksum(entropy)
|
64
|
-
b = Bitcoin.sha256([entropy].pack('B*')).
|
64
|
+
b = Bitcoin.sha256([entropy].pack('B*')).unpack1('B*')
|
65
65
|
b.slice(0, (entropy.length/32))
|
66
66
|
end
|
67
67
|
|
@@ -69,7 +69,7 @@ module Bitcoin
|
|
69
69
|
|
70
70
|
# load word list contents
|
71
71
|
def load_words
|
72
|
-
File.readlines("#{WORD_DIR}/#{
|
72
|
+
File.readlines("#{WORD_DIR}/#{language}.txt").map(&:strip)
|
73
73
|
end
|
74
74
|
|
75
75
|
end
|
data/lib/bitcoin/network/peer.rb
CHANGED
@@ -83,10 +83,15 @@ module Bitcoin
|
|
83
83
|
|
84
84
|
def post_handshake
|
85
85
|
@connected = true
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
if remote_version.support?(Bitcoin::Message::SERVICE_FLAGS[:bloom])
|
87
|
+
pool.handle_new_peer(self)
|
88
|
+
# require remote peer to use headers message instead fo inv message.
|
89
|
+
conn.send_message(Bitcoin::Message::SendHeaders.new)
|
90
|
+
EM.add_periodic_timer(PING_INTERVAL) {send_ping}
|
91
|
+
else
|
92
|
+
close("peer does not support NODE_BLOOM.")
|
93
|
+
pool.pending_peers.delete(self)
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
# start block header download
|
@@ -30,7 +30,7 @@ module Bitcoin
|
|
30
30
|
logger.debug 'discover peer address from DNS seeds.'
|
31
31
|
dns_seeds.map { |seed|
|
32
32
|
begin
|
33
|
-
Socket.getaddrinfo(seed, Bitcoin.chain_params.default_port).map{|a|a[2]}.uniq
|
33
|
+
Socket.getaddrinfo("#{seed}", Bitcoin.chain_params.default_port).map{|a|a[2]}.uniq
|
34
34
|
rescue SocketError => e
|
35
35
|
logger.error "SocketError occurred when load DNS seed: #{seed}, error: #{e.message}"
|
36
36
|
nil
|
data/lib/bitcoin/node/cli.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'net/http'
|
2
2
|
require 'thor'
|
3
3
|
require 'json'
|
4
4
|
|
@@ -92,15 +92,19 @@ module Bitcoin
|
|
92
92
|
:id => 'jsonrpc'
|
93
93
|
}
|
94
94
|
begin
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
95
|
+
uri = URI.parse(config.server_url)
|
96
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
97
|
+
http.use_ssl = uri.scheme === "https"
|
98
|
+
request = Net::HTTP::Post.new('/')
|
99
|
+
request.content_type = 'application/json'
|
100
|
+
request.body = data.to_json
|
101
|
+
response = http.request(request)
|
102
|
+
body = response.body
|
103
|
+
begin
|
104
|
+
json = JSON.parse(body.to_str)
|
105
|
+
puts JSON.pretty_generate(json)
|
106
|
+
rescue Exception
|
107
|
+
puts body.to_str
|
104
108
|
end
|
105
109
|
rescue Exception => e
|
106
110
|
puts e.message
|
@@ -4,8 +4,10 @@ module Bitcoin
|
|
4
4
|
module Node
|
5
5
|
class Configuration
|
6
6
|
|
7
|
-
attr_reader :conf
|
7
|
+
attr_reader :conf # Hash
|
8
8
|
|
9
|
+
# initialize configuration
|
10
|
+
# @param [Hash] opts parameter for node.
|
9
11
|
def initialize(opts = {})
|
10
12
|
# TODO apply configuration file.
|
11
13
|
opts[:network] = :mainnet unless opts[:network]
|
data/lib/bitcoin/node/spv.rb
CHANGED
@@ -13,6 +13,14 @@ module Bitcoin
|
|
13
13
|
attr_accessor :wallet
|
14
14
|
attr_accessor :bloom
|
15
15
|
|
16
|
+
# Initialize spv settings
|
17
|
+
# @param [Bitcoin::Node::Configuration] configuration configuration for spv.
|
18
|
+
#
|
19
|
+
# ```ruby
|
20
|
+
# config = Bitcoin::Node::Configuration.new(network: :mainnet)
|
21
|
+
# spv = Bitcoin::Node::SPV.new(config)
|
22
|
+
# spv.run
|
23
|
+
# ````
|
16
24
|
def initialize(configuration)
|
17
25
|
@chain = Bitcoin::Store::SPVChain.new
|
18
26
|
@configuration = configuration
|
@@ -45,7 +53,7 @@ module Bitcoin
|
|
45
53
|
# broadcast a transaction
|
46
54
|
def broadcast(tx)
|
47
55
|
pool.broadcast(tx)
|
48
|
-
logger.debug "broadcast tx: #{tx.
|
56
|
+
logger.debug "broadcast tx: #{tx.to_hex}"
|
49
57
|
end
|
50
58
|
|
51
59
|
# add filter element to bloom filter.
|
data/lib/bitcoin/opcodes.rb
CHANGED
@@ -136,6 +136,8 @@ module Bitcoin
|
|
136
136
|
OP_NOP9 = 0xb8
|
137
137
|
OP_NOP10 = 0xb9
|
138
138
|
|
139
|
+
OP_CHECKSIGADD = 0xba # BIP 342 opcodes (Tapscript)
|
140
|
+
|
139
141
|
# https://en.bitcoin.it/wiki/Script#Pseudo-words
|
140
142
|
OP_PUBKEYHASH = 0xfd
|
141
143
|
OP_PUBKEY = 0xfe
|
@@ -145,6 +147,9 @@ module Bitcoin
|
|
145
147
|
OPCODES_MAP = Hash[*(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map { |c| [const_get(c), c.to_s] }.flatten]
|
146
148
|
NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
147
149
|
|
150
|
+
OP_SUCCESSES = [0x50, 0x62, 0x89, 0x8a, 0x8d, 0x8e, (0x7e..0x81).to_a,
|
151
|
+
(0x83..0x86).to_a, (0x95..0x99).to_a, (0xbb..0xfe).to_a].flatten
|
152
|
+
|
148
153
|
def opcode_to_name(opcode)
|
149
154
|
return OPCODES_MAP[opcode].delete('OP_') if opcode == OP_0 || (opcode <= OP_16 && opcode >= OP_1)
|
150
155
|
OPCODES_MAP[opcode]
|
@@ -156,7 +161,8 @@ module Bitcoin
|
|
156
161
|
end
|
157
162
|
|
158
163
|
# whether opcode is predefined opcode
|
159
|
-
def defined?(opcode)
|
164
|
+
def defined?(opcode, allow_success = false)
|
165
|
+
return true if allow_success && op_success?(opcode)
|
160
166
|
!opcode_to_name(opcode).nil?
|
161
167
|
end
|
162
168
|
|
@@ -174,5 +180,12 @@ module Bitcoin
|
|
174
180
|
nil
|
175
181
|
end
|
176
182
|
|
183
|
+
# Check whether +opcode+ is OP_SUCCESSx or not?
|
184
|
+
# @param [Integer] opcode an opcode.
|
185
|
+
# @return [Boolean] if +opcode+ is OP_SUCCESSx return true, otherwise false.
|
186
|
+
def op_success?(opcode)
|
187
|
+
OP_SUCCESSES.include?(opcode)
|
188
|
+
end
|
189
|
+
|
177
190
|
end
|
178
191
|
end
|