tapyrus 0.1.0 → 0.2.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/README.md +6 -14
- data/exe/tapyrusrbd +2 -2
- data/lib/openassets/util.rb +2 -4
- data/lib/schnorr.rb +83 -0
- data/lib/schnorr/signature.rb +38 -0
- data/lib/tapyrus.rb +9 -11
- data/lib/tapyrus/block.rb +1 -32
- data/lib/tapyrus/block_header.rb +7 -6
- data/lib/tapyrus/chain_params.rb +13 -26
- data/lib/tapyrus/chainparams/{testnet.yml → dev.yml} +7 -9
- data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -10
- data/lib/tapyrus/constants.rb +12 -34
- data/lib/tapyrus/ext.rb +5 -0
- data/lib/tapyrus/ext/json_parser.rb +47 -0
- data/lib/tapyrus/ext_key.rb +5 -10
- data/lib/tapyrus/key.rb +57 -29
- data/lib/tapyrus/message.rb +2 -2
- data/lib/tapyrus/message/base.rb +1 -0
- data/lib/tapyrus/message/block.rb +3 -3
- data/lib/tapyrus/message/cmpct_block.rb +3 -5
- data/lib/tapyrus/message/tx.rb +2 -2
- data/lib/tapyrus/network/peer.rb +1 -15
- data/lib/tapyrus/node/cli.rb +15 -11
- data/lib/tapyrus/node/configuration.rb +1 -1
- data/lib/tapyrus/node/spv.rb +1 -1
- data/lib/tapyrus/opcodes.rb +5 -0
- data/lib/tapyrus/out_point.rb +1 -1
- data/lib/tapyrus/rpc/request_handler.rb +3 -3
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
- data/lib/tapyrus/script/color.rb +79 -0
- data/lib/tapyrus/script/multisig.rb +0 -27
- data/lib/tapyrus/script/script.rb +74 -89
- data/lib/tapyrus/script/script_error.rb +8 -14
- data/lib/tapyrus/script/script_interpreter.rb +65 -86
- data/lib/tapyrus/script/tx_checker.rb +16 -4
- data/lib/tapyrus/secp256k1.rb +1 -0
- data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
- data/lib/tapyrus/secp256k1/ruby.rb +5 -31
- data/lib/tapyrus/store/chain_entry.rb +1 -0
- data/lib/tapyrus/tx.rb +18 -160
- data/lib/tapyrus/tx_in.rb +4 -11
- data/lib/tapyrus/tx_out.rb +2 -1
- data/lib/tapyrus/util.rb +8 -0
- data/lib/tapyrus/validation.rb +1 -6
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +1 -0
- data/lib/tapyrus/wallet/master_key.rb +1 -0
- data/tapyrusrb.gemspec +3 -3
- metadata +42 -39
- data/lib/tapyrus/chainparams/regtest.yml +0 -38
- data/lib/tapyrus/descriptor.rb +0 -147
- data/lib/tapyrus/script_witness.rb +0 -38
data/lib/tapyrus/message/tx.rb
CHANGED
@@ -17,11 +17,11 @@ module Tapyrus
|
|
17
17
|
|
18
18
|
def self.parse_from_payload(payload)
|
19
19
|
tx = Tapyrus::Tx.parse_from_payload(payload)
|
20
|
-
new(tx
|
20
|
+
new(tx)
|
21
21
|
end
|
22
22
|
|
23
23
|
def to_payload
|
24
|
-
|
24
|
+
tx.to_payload
|
25
25
|
end
|
26
26
|
|
27
27
|
end
|
data/lib/tapyrus/network/peer.rb
CHANGED
@@ -99,21 +99,7 @@ module Tapyrus
|
|
99
99
|
|
100
100
|
# broadcast tx.
|
101
101
|
def broadcast_tx(tx)
|
102
|
-
conn.send_message(Tapyrus::Message::Tx.new(tx
|
103
|
-
end
|
104
|
-
|
105
|
-
# check the remote peer support witness.
|
106
|
-
def support_witness?
|
107
|
-
return false unless remote_version
|
108
|
-
remote_version.services & Tapyrus::Message::SERVICE_FLAGS[:witness] > 0
|
109
|
-
end
|
110
|
-
|
111
|
-
# check the remote peer supports compact block.
|
112
|
-
def support_cmpct?
|
113
|
-
return false if remote_version.version < Tapyrus::Message::VERSION[:compact]
|
114
|
-
return true unless local_version.services & Tapyrus::Message::SERVICE_FLAGS[:witness] > 0
|
115
|
-
return false unless support_witness?
|
116
|
-
remote_version.version >= Tapyrus::Message::VERSION[:compact_witness]
|
102
|
+
conn.send_message(Tapyrus::Message::Tx.new(tx))
|
117
103
|
end
|
118
104
|
|
119
105
|
# get peer's block type.
|
data/lib/tapyrus/node/cli.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'net/http'
|
2
2
|
require 'thor'
|
3
3
|
require 'json'
|
4
4
|
|
@@ -7,7 +7,7 @@ module Tapyrus
|
|
7
7
|
|
8
8
|
class CLI < Thor
|
9
9
|
|
10
|
-
class_option :network, aliases: '-n', default: :
|
10
|
+
class_option :network, aliases: '-n', default: :prod
|
11
11
|
|
12
12
|
desc 'getblockchaininfo', 'Returns an object containing various state info regarding blockchain processing.'
|
13
13
|
def getblockchaininfo
|
@@ -92,15 +92,19 @@ module Tapyrus
|
|
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
|
@@ -8,7 +8,7 @@ module Tapyrus
|
|
8
8
|
|
9
9
|
def initialize(opts = {})
|
10
10
|
# TODO apply configuration file.
|
11
|
-
opts[:network] = :
|
11
|
+
opts[:network] = :prod unless opts[:network]
|
12
12
|
opts[:relay] = false unless opts[:relay]
|
13
13
|
Tapyrus.chain_params = opts[:network]
|
14
14
|
|
data/lib/tapyrus/node/spv.rb
CHANGED
data/lib/tapyrus/opcodes.rb
CHANGED
@@ -141,6 +141,11 @@ module Tapyrus
|
|
141
141
|
OP_PUBKEY = 0xfe
|
142
142
|
OP_INVALIDOPCODE = 0xff
|
143
143
|
|
144
|
+
# tapyrus extension
|
145
|
+
OP_CHECKDATASIG = 0xba
|
146
|
+
OP_CHECKDATASIGVERIFY = 0xbb
|
147
|
+
OP_COLOR = 0xbc
|
148
|
+
|
144
149
|
DUPLICATE_KEY = [:OP_NOP2, :OP_NOP3]
|
145
150
|
OPCODES_MAP = Hash[*(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map { |c| [const_get(c), c.to_s] }.flatten]
|
146
151
|
NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
data/lib/tapyrus/out_point.rb
CHANGED
@@ -31,8 +31,8 @@ module Tapyrus
|
|
31
31
|
{
|
32
32
|
hash: block_id,
|
33
33
|
height: entry.height,
|
34
|
-
|
35
|
-
|
34
|
+
features: entry.header.features,
|
35
|
+
featuresHex: entry.header.features.to_even_length_hex,
|
36
36
|
merkleroot: entry.header.merkle_root.rhex,
|
37
37
|
time: entry.header.time,
|
38
38
|
mediantime: node.chain.mtp(block_hash),
|
@@ -42,7 +42,7 @@ module Tapyrus
|
|
42
42
|
nextblockhash: node.chain.next_hash(block_hash).rhex
|
43
43
|
}
|
44
44
|
else
|
45
|
-
entry.header.
|
45
|
+
entry.header.to_hex
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -1,15 +1,16 @@
|
|
1
|
-
require '
|
1
|
+
require 'net/http'
|
2
|
+
require 'json/pure'
|
2
3
|
|
3
4
|
module Tapyrus
|
4
5
|
module RPC
|
5
6
|
|
6
|
-
# Client implementation for RPC to
|
7
|
+
# Client implementation for RPC to Tapyrus Core.
|
7
8
|
#
|
8
9
|
# [Usage]
|
9
10
|
# config = {schema: 'http', host: 'localhost', port: 18332, user: 'xxx', password: 'yyy'}
|
10
|
-
# client = Tapyrus::RPC::
|
11
|
+
# client = Tapyrus::RPC::TapyrusCoreClient.new(config)
|
11
12
|
#
|
12
|
-
# You can execute the CLI command supported by
|
13
|
+
# You can execute the CLI command supported by Tapyrus Core as follows:
|
13
14
|
#
|
14
15
|
# client.listunspent
|
15
16
|
# client.getblockchaininfo
|
@@ -53,17 +54,18 @@ module Tapyrus
|
|
53
54
|
:params => params,
|
54
55
|
:id => 'jsonrpc'
|
55
56
|
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
57
|
+
uri = URI.parse(server_url)
|
58
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
59
|
+
http.use_ssl = uri.scheme === "https"
|
60
|
+
request = Net::HTTP::Post.new('/')
|
61
|
+
request.basic_auth(uri.user, uri.password)
|
62
|
+
request.content_type = 'application/json'
|
63
|
+
request.body = data.to_json
|
64
|
+
response = http.request(request)
|
65
|
+
body = response.body
|
66
|
+
response = Tapyrus::Ext::JsonParser.new(body.gsub(/\\u([\da-fA-F]{4})/) { [$1].pack('H*').unpack('n*').pack('U*').encode('ISO-8859-1').force_encoding('UTF-8') }).parse
|
67
|
+
raise response['error'].to_s if response['error']
|
68
|
+
response['result']
|
67
69
|
end
|
68
70
|
|
69
71
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
module Color
|
3
|
+
module TokenTypes
|
4
|
+
NONE = 0x00
|
5
|
+
REISSUABLE = 0xC1
|
6
|
+
NON_REISSUABLE = 0xC2
|
7
|
+
NFT = 0xC3
|
8
|
+
end
|
9
|
+
|
10
|
+
class ColorIdentifier
|
11
|
+
include Tapyrus::HexConverter
|
12
|
+
|
13
|
+
attr_reader :type, :payload
|
14
|
+
|
15
|
+
def self.reissuable(script_pubkey)
|
16
|
+
new(TokenTypes::REISSUABLE, Tapyrus.sha256(script_pubkey.to_payload))
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.non_reissuable(out_point)
|
20
|
+
new(TokenTypes::NON_REISSUABLE, Tapyrus.sha256(out_point.to_payload))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.nft(out_point)
|
24
|
+
new(TokenTypes::NFT, Tapyrus.sha256(out_point.to_payload))
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_payload
|
28
|
+
[type, payload].pack('Ca*')
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse_from_payload(payload)
|
32
|
+
type, payload = payload.unpack('Ca*')
|
33
|
+
new(type, payload)
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
other && other.to_payload == to_payload
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid?
|
41
|
+
return false unless [TokenTypes::REISSUABLE, TokenTypes::NON_REISSUABLE, TokenTypes::NFT].include?(type)
|
42
|
+
return false unless payload.bytesize == 32
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def initialize(type, payload)
|
49
|
+
@type = type
|
50
|
+
@payload = payload
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module ColoredOutput
|
55
|
+
def colored?
|
56
|
+
script_pubkey.cp2pkh? || script_pubkey.cp2sh?
|
57
|
+
end
|
58
|
+
|
59
|
+
def color_id
|
60
|
+
@color_id ||= ColorIdentifier.parse_from_payload(script_pubkey.chunks[0].pushed_data)
|
61
|
+
end
|
62
|
+
|
63
|
+
def reissuable?
|
64
|
+
return false unless colored?
|
65
|
+
color_id.type == TokenTypes::REISSUABLE
|
66
|
+
end
|
67
|
+
|
68
|
+
def non_reissuable?
|
69
|
+
return false unless colored?
|
70
|
+
color_id.type == TokenTypes::NON_REISSUABLE
|
71
|
+
end
|
72
|
+
|
73
|
+
def nft?
|
74
|
+
return false unless colored?
|
75
|
+
color_id.type == TokenTypes::NFT
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -61,32 +61,5 @@ module Tapyrus
|
|
61
61
|
prefix + pubkeys.map { |k| sigs[k] ? Tapyrus::Script.pack_pushdata(sigs[k]) : nil }.join +
|
62
62
|
Tapyrus::Script.pack_pushdata(script.chunks[-1].pushed_data)
|
63
63
|
end
|
64
|
-
|
65
|
-
def self.add_sig_to_multisig_script_witness(sig_to_add, script_witness, hash_type = SIGHASH_TYPE[:all])
|
66
|
-
signature = sig_to_add + [hash_type].pack("C*")
|
67
|
-
script_witness.stack << signature
|
68
|
-
end
|
69
|
-
|
70
|
-
# Sort signatures in the given +script_witness+ according to the order of pubkeys in
|
71
|
-
# the redeem script. Also needs the +sig_hash+ to match signatures to pubkeys.
|
72
|
-
# @param [ScriptWitness] script_witness for multisig.
|
73
|
-
# @param [String] sig_hash to be signed.
|
74
|
-
def self.sort_witness_multisig_signatures(script_witness, sig_hash)
|
75
|
-
redeem_script = Tapyrus::Script.parse_from_payload(script_witness.stack[-1])
|
76
|
-
pubkeys = redeem_script.get_multisig_pubkeys
|
77
|
-
sigs = Hash[script_witness.stack[1...-1].map.with_index do |sig, idx|
|
78
|
-
pubkey = pubkeys.map do |key|
|
79
|
-
Tapyrus::Key.new(pubkey: key.bth).verify(sig, sig_hash) ? key : nil
|
80
|
-
end.compact.first
|
81
|
-
raise "Key for signature ##{idx} not found in redeem script!" unless pubkey
|
82
|
-
[pubkey, sig]
|
83
|
-
end]
|
84
|
-
script_witness.stack.clear
|
85
|
-
script_witness.stack << ''
|
86
|
-
pubkeys.each do |pubkey|
|
87
|
-
script_witness.stack << sigs[pubkey] if sigs[pubkey]
|
88
|
-
end
|
89
|
-
script_witness.stack << redeem_script.to_payload
|
90
|
-
end
|
91
64
|
end
|
92
65
|
end
|
@@ -5,6 +5,7 @@ module Tapyrus
|
|
5
5
|
|
6
6
|
# tapyrus script
|
7
7
|
class Script
|
8
|
+
include Tapyrus::HexConverter
|
8
9
|
include Tapyrus::Opcodes
|
9
10
|
|
10
11
|
attr_accessor :chunks
|
@@ -18,11 +19,6 @@ module Tapyrus
|
|
18
19
|
new << OP_DUP << OP_HASH160 << pubkey_hash << OP_EQUALVERIFY << OP_CHECKSIG
|
19
20
|
end
|
20
21
|
|
21
|
-
# generate P2WPKH script
|
22
|
-
def self.to_p2wpkh(pubkey_hash)
|
23
|
-
new << WITNESS_VERSION << pubkey_hash
|
24
|
-
end
|
25
|
-
|
26
22
|
# generate m of n multisig p2sh script
|
27
23
|
# @param [String] m the number of signatures required for multisig
|
28
24
|
# @param [Array] pubkeys array of public keys that compose multisig
|
@@ -45,6 +41,40 @@ module Tapyrus
|
|
45
41
|
Script.to_p2sh(to_hash160)
|
46
42
|
end
|
47
43
|
|
44
|
+
# generate cp2pkh script
|
45
|
+
# @param [ColorIdentifier] color identifier
|
46
|
+
# @param [String] hash160 of pubkey
|
47
|
+
# @return [Script] CP2PKH script
|
48
|
+
# @raise [ArgumentError] if color_id is nil or invalid
|
49
|
+
def self.to_cp2pkh(color_id, pubkey_hash)
|
50
|
+
raise ArgumentError, 'Specified color identifier is invalid' unless color_id&.valid?
|
51
|
+
new << color_id.to_payload << OP_COLOR << OP_DUP << OP_HASH160 << pubkey_hash << OP_EQUALVERIFY << OP_CHECKSIG
|
52
|
+
end
|
53
|
+
|
54
|
+
# generate cp2sh script
|
55
|
+
# @param [ColorIdentifier] color identifier
|
56
|
+
# @param [String] hash160 of script
|
57
|
+
# @return [Script] CP2SH script
|
58
|
+
# @raise [ArgumentError] if color_id is nil or invalid
|
59
|
+
def self.to_cp2sh(color_id, script_hash)
|
60
|
+
raise ArgumentError, 'Specified color identifier is invalid' unless color_id&.valid?
|
61
|
+
new << color_id.to_payload << OP_COLOR << OP_HASH160 << script_hash << OP_EQUAL
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add color identifier to existing p2pkh or p2sh
|
65
|
+
# @param [ColorIdentifier] color identifier
|
66
|
+
# @return [Script] CP2PKH or CP2SH script
|
67
|
+
# @raise [ArgumentError] if color_id is nil or invalid
|
68
|
+
# @raise [RuntimeError] if script is neither p2pkh nor p2sh
|
69
|
+
def add_color(color_id)
|
70
|
+
raise ArgumentError, 'Specified color identifier is invalid' unless color_id&.valid?
|
71
|
+
raise RuntimeError, 'Only p2pkh and p2sh can add color' unless p2pkh? or p2sh?
|
72
|
+
Tapyrus::Script.new.tap do |s|
|
73
|
+
s << color_id.to_payload << OP_COLOR
|
74
|
+
s.chunks += self.chunks
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
48
78
|
def get_multisig_pubkeys
|
49
79
|
num = Tapyrus::Opcodes.opcode_to_small_int(chunks[-2].bth.to_i(16))
|
50
80
|
(1..num).map{ |i| chunks[i].pushed_data }
|
@@ -59,13 +89,6 @@ module Tapyrus
|
|
59
89
|
new << m << pubkeys << pubkeys.size << OP_CHECKMULTISIG
|
60
90
|
end
|
61
91
|
|
62
|
-
# generate p2wsh script for +redeem_script+
|
63
|
-
# @param [Script] redeem_script target redeem script
|
64
|
-
# @param [Script] p2wsh script
|
65
|
-
def self.to_p2wsh(redeem_script)
|
66
|
-
new << WITNESS_VERSION << redeem_script.to_sha256
|
67
|
-
end
|
68
|
-
|
69
92
|
# generate script from string.
|
70
93
|
def self.from_string(string)
|
71
94
|
script = new
|
@@ -151,14 +174,15 @@ module Tapyrus
|
|
151
174
|
def addresses
|
152
175
|
return [p2pkh_addr] if p2pkh?
|
153
176
|
return [p2sh_addr] if p2sh?
|
154
|
-
return [
|
177
|
+
return [cp2pkh_addr] if cp2pkh?
|
178
|
+
return [cp2sh_addr] if cp2sh?
|
155
179
|
return get_multisig_pubkeys.map{|pubkey| Tapyrus::Key.new(pubkey: pubkey.bth).to_p2pkh} if multisig?
|
156
180
|
[]
|
157
181
|
end
|
158
182
|
|
159
183
|
# check whether standard script.
|
160
184
|
def standard?
|
161
|
-
p2pkh? | p2sh? |
|
185
|
+
p2pkh? | p2sh? | multisig? | standard_op_return?
|
162
186
|
end
|
163
187
|
|
164
188
|
# whether this script is a P2PKH format script.
|
@@ -168,17 +192,6 @@ module Tapyrus
|
|
168
192
|
(chunks[0..1]+ chunks[3..4]).map(&:ord) && chunks[2].bytesize == 21
|
169
193
|
end
|
170
194
|
|
171
|
-
# whether this script is a P2WPKH format script.
|
172
|
-
def p2wpkh?
|
173
|
-
return false unless chunks.size == 2
|
174
|
-
chunks[0].ord == WITNESS_VERSION && chunks[1].bytesize == 21
|
175
|
-
end
|
176
|
-
|
177
|
-
def p2wsh?
|
178
|
-
return false unless chunks.size == 2
|
179
|
-
chunks[0].ord == WITNESS_VERSION && chunks[1].bytesize == 33
|
180
|
-
end
|
181
|
-
|
182
195
|
def p2sh?
|
183
196
|
return false unless chunks.size == 3
|
184
197
|
OP_HASH160 == chunks[0].ord && OP_EQUAL == chunks[2].ord && chunks[1].bytesize == 21
|
@@ -201,6 +214,23 @@ module Tapyrus
|
|
201
214
|
(chunks.size == 1 || chunks[1].opcode <= OP_16)
|
202
215
|
end
|
203
216
|
|
217
|
+
def cp2pkh?
|
218
|
+
return false unless chunks.size == 7
|
219
|
+
return false unless chunks[0].bytesize == 34
|
220
|
+
return false unless Tapyrus::Color::ColorIdentifier.parse_from_payload(chunks[0].pushed_data)&.valid?
|
221
|
+
return false unless chunks[1].ord == OP_COLOR
|
222
|
+
[OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG] ==
|
223
|
+
(chunks[2..3]+ chunks[5..6]).map(&:ord) && chunks[4].bytesize == 21
|
224
|
+
end
|
225
|
+
|
226
|
+
def cp2sh?
|
227
|
+
return false unless chunks.size == 5
|
228
|
+
return false unless chunks[0].bytesize == 34
|
229
|
+
return false unless Tapyrus::Color::ColorIdentifier.parse_from_payload(chunks[0].pushed_data)&.valid?
|
230
|
+
return false unless chunks[1].ord == OP_COLOR
|
231
|
+
OP_HASH160 == chunks[2].ord && OP_EQUAL == chunks[4].ord && chunks[3].bytesize == 21
|
232
|
+
end
|
233
|
+
|
204
234
|
def op_return_data
|
205
235
|
return nil unless op_return?
|
206
236
|
return nil if chunks.size == 1
|
@@ -221,50 +251,15 @@ module Tapyrus
|
|
221
251
|
chunks.select{|c|c.pushdata? && [33, 65].include?(c.pushed_data.bytesize) && [2, 3, 4, 6, 7].include?(c.pushed_data[0].bth.to_i(16))}.map{|c|c.pushed_data.bth}
|
222
252
|
end
|
223
253
|
|
224
|
-
#
|
225
|
-
def witness_program?
|
226
|
-
return false if size < 4 || size > 42 || chunks.size < 2
|
227
|
-
|
228
|
-
opcode = chunks[0].opcode
|
229
|
-
|
230
|
-
return false if opcode != OP_0 && (opcode < OP_1 || opcode > OP_16)
|
231
|
-
return false unless chunks[1].pushdata?
|
232
|
-
|
233
|
-
if size == (chunks[1][0].unpack('C').first + 2)
|
234
|
-
program_size = chunks[1].pushed_data.bytesize
|
235
|
-
return program_size >= 2 && program_size <= 40
|
236
|
-
end
|
237
|
-
|
238
|
-
false
|
239
|
-
end
|
240
|
-
|
241
|
-
# get witness commitment
|
242
|
-
def witness_commitment
|
243
|
-
return nil if !op_return? || op_return_data.bytesize < 36
|
244
|
-
buf = StringIO.new(op_return_data)
|
245
|
-
return nil unless buf.read(4).bth == WITNESS_COMMITMENT_HEADER
|
246
|
-
buf.read(32).bth
|
247
|
-
end
|
248
|
-
|
249
|
-
# If this script is witness program, return its script code,
|
250
|
-
# otherwise returns the self payload. ScriptInterpreter does not use this.
|
254
|
+
# returns the self payload. ScriptInterpreter does not use this.
|
251
255
|
def to_script_code(skip_separator_index = 0)
|
252
256
|
payload = to_payload
|
253
|
-
if
|
254
|
-
payload = Script.to_p2pkh(chunks[1].pushed_data.bth).to_payload
|
255
|
-
elsif skip_separator_index > 0
|
257
|
+
if skip_separator_index > 0
|
256
258
|
payload = subscript_codeseparator(skip_separator_index)
|
257
259
|
end
|
258
260
|
Tapyrus.pack_var_string(payload)
|
259
261
|
end
|
260
262
|
|
261
|
-
# get witness version and witness program
|
262
|
-
def witness_data
|
263
|
-
version = opcode_to_small_int(chunks[0].opcode)
|
264
|
-
program = chunks[1].pushed_data
|
265
|
-
[version, program]
|
266
|
-
end
|
267
|
-
|
268
263
|
# append object to payload
|
269
264
|
def <<(obj)
|
270
265
|
if obj.is_a?(Integer)
|
@@ -324,6 +319,7 @@ module Tapyrus
|
|
324
319
|
when Integer
|
325
320
|
opcode_to_name(c)
|
326
321
|
when String
|
322
|
+
return c if c.empty?
|
327
323
|
if c.pushdata?
|
328
324
|
v = Opcodes.opcode_to_small_int(c.ord)
|
329
325
|
if v
|
@@ -351,7 +347,7 @@ module Tapyrus
|
|
351
347
|
|
352
348
|
# generate hash160 hash for payload
|
353
349
|
def to_hash160
|
354
|
-
Tapyrus.hash160(
|
350
|
+
Tapyrus.hash160(to_hex)
|
355
351
|
end
|
356
352
|
|
357
353
|
# script size
|
@@ -482,13 +478,11 @@ module Tapyrus
|
|
482
478
|
return 'pubkeyhash' if p2pkh?
|
483
479
|
return 'scripthash' if p2sh?
|
484
480
|
return 'multisig' if multisig?
|
485
|
-
return 'witness_v0_keyhash' if p2wpkh?
|
486
|
-
return 'witness_v0_scripthash' if p2wsh?
|
487
481
|
'nonstandard'
|
488
482
|
end
|
489
483
|
|
490
484
|
def to_h
|
491
|
-
h = {asm: to_s, hex:
|
485
|
+
h = {asm: to_s, hex: to_hex, type: type}
|
492
486
|
addrs = addresses
|
493
487
|
unless addrs.empty?
|
494
488
|
h[:req_sigs] = multisig? ? Tapyrus::Opcodes.opcode_to_small_int(chunks[0].bth.to_i(16)) :addrs.size
|
@@ -504,48 +498,39 @@ module Tapyrus
|
|
504
498
|
(size > 0 && op_return?) || size > Tapyrus::MAX_SCRIPT_SIZE
|
505
499
|
end
|
506
500
|
|
507
|
-
# convert payload to hex data.
|
508
|
-
# @return [String] script with hex format.
|
509
|
-
def to_hex
|
510
|
-
to_payload.bth
|
511
|
-
end
|
512
|
-
|
513
501
|
private
|
514
502
|
|
515
503
|
# generate p2pkh address. if script dose not p2pkh, return nil.
|
516
504
|
def p2pkh_addr
|
517
505
|
return nil unless p2pkh?
|
518
506
|
hash160 = chunks[2].pushed_data.bth
|
519
|
-
return nil unless hash160.htb.bytesize == 20
|
520
507
|
Tapyrus.encode_base58_address(hash160, Tapyrus.chain_params.address_version)
|
521
508
|
end
|
522
509
|
|
523
|
-
# generate p2wpkh address. if script dose not p2wpkh, return nil.
|
524
|
-
def p2wpkh_addr
|
525
|
-
p2wpkh? ? bech32_addr : nil
|
526
|
-
end
|
527
|
-
|
528
510
|
# generate p2sh address. if script dose not p2sh, return nil.
|
529
511
|
def p2sh_addr
|
530
512
|
return nil unless p2sh?
|
531
513
|
hash160 = chunks[1].pushed_data.bth
|
532
|
-
return nil unless hash160.htb.bytesize == 20
|
533
514
|
Tapyrus.encode_base58_address(hash160, Tapyrus.chain_params.p2sh_version)
|
534
515
|
end
|
535
516
|
|
536
|
-
# generate
|
537
|
-
def
|
538
|
-
|
539
|
-
end
|
517
|
+
# generate cp2pkh address. if script dose not cp2pkh, return nil.
|
518
|
+
def cp2pkh_addr
|
519
|
+
return nil unless cp2pkh?
|
540
520
|
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
segwit_addr.hrp = Tapyrus.chain_params.bech32_hrp
|
545
|
-
segwit_addr.script_pubkey = to_payload.bth
|
546
|
-
segwit_addr.addr
|
521
|
+
color_id = chunks[0].pushed_data.bth
|
522
|
+
hash160 = chunks[4].pushed_data.bth
|
523
|
+
Tapyrus.encode_base58_address(color_id + hash160, Tapyrus.chain_params.cp2pkh_version)
|
547
524
|
end
|
548
525
|
|
526
|
+
# generate cp2sh address. if script dose not cp2sh, return nil.
|
527
|
+
def cp2sh_addr
|
528
|
+
return nil unless cp2sh?
|
529
|
+
|
530
|
+
color_id = chunks[0].pushed_data.bth
|
531
|
+
hash160 = chunks[3].pushed_data.bth
|
532
|
+
Tapyrus.encode_base58_address(color_id + hash160, Tapyrus.chain_params.cp2sh_version)
|
533
|
+
end
|
549
534
|
end
|
550
535
|
|
551
536
|
end
|