Module: Bitcoin::Descriptor
- Includes:
- Opcodes
- Defined in:
- lib/bitcoin/descriptor.rb,
lib/bitcoin/descriptor/pk.rb,
lib/bitcoin/descriptor/sh.rb,
lib/bitcoin/descriptor/sp.rb,
lib/bitcoin/descriptor/tr.rb,
lib/bitcoin/descriptor/pkh.rb,
lib/bitcoin/descriptor/raw.rb,
lib/bitcoin/descriptor/wsh.rb,
lib/bitcoin/descriptor/addr.rb,
lib/bitcoin/descriptor/wpkh.rb,
lib/bitcoin/descriptor/combo.rb,
lib/bitcoin/descriptor/multi.rb,
lib/bitcoin/descriptor/musig.rb,
lib/bitcoin/descriptor/raw_tr.rb,
lib/bitcoin/descriptor/multi_a.rb,
lib/bitcoin/descriptor/checksum.rb,
lib/bitcoin/descriptor/expression.rb,
lib/bitcoin/descriptor/sorted_multi.rb,
lib/bitcoin/descriptor/key_expression.rb,
lib/bitcoin/descriptor/sorted_multi_a.rb,
lib/bitcoin/descriptor/script_expression.rb
Defined Under Namespace
Modules: Checksum Classes: Addr, Combo, Expression, KeyExpression, MuSig, Multi, MultiA, Pk, Pkh, Raw, RawTr, ScriptExpression, Sh, SortedMulti, SortedMultiA, Sp, Tr, Wpkh, Wsh
Constant Summary
Constants included from Opcodes
Opcodes::DUPLICATE_KEY, Opcodes::NAME_MAP, Opcodes::OPCODES_MAP, Opcodes::OP_0, Opcodes::OP_0NOTEQUAL, Opcodes::OP_1, Opcodes::OP_10, Opcodes::OP_11, Opcodes::OP_12, Opcodes::OP_13, Opcodes::OP_14, Opcodes::OP_15, Opcodes::OP_16, Opcodes::OP_1ADD, Opcodes::OP_1NEGATE, Opcodes::OP_1SUB, Opcodes::OP_2, Opcodes::OP_2DIV, Opcodes::OP_2DROP, Opcodes::OP_2DUP, Opcodes::OP_2MUL, Opcodes::OP_2OVER, Opcodes::OP_2ROT, Opcodes::OP_2SWAP, Opcodes::OP_3, Opcodes::OP_3DUP, Opcodes::OP_4, Opcodes::OP_5, Opcodes::OP_6, Opcodes::OP_7, Opcodes::OP_8, Opcodes::OP_9, Opcodes::OP_ABS, Opcodes::OP_ADD, Opcodes::OP_AND, Opcodes::OP_BOOLAND, Opcodes::OP_BOOLOR, Opcodes::OP_CAT, Opcodes::OP_CHECKMULTISIG, Opcodes::OP_CHECKMULTISIGVERIFY, Opcodes::OP_CHECKSIG, Opcodes::OP_CHECKSIGADD, Opcodes::OP_CHECKSIGVERIFY, Opcodes::OP_CODESEPARATOR, Opcodes::OP_DEPTH, Opcodes::OP_DIV, Opcodes::OP_DROP, Opcodes::OP_DUP, Opcodes::OP_ELSE, Opcodes::OP_ENDIF, Opcodes::OP_EQUAL, Opcodes::OP_EQUALVERIFY, Opcodes::OP_FROMALTSTACK, Opcodes::OP_GREATERTHAN, Opcodes::OP_GREATERTHANOREQUAL, Opcodes::OP_HASH160, Opcodes::OP_HASH256, Opcodes::OP_IF, Opcodes::OP_IFDUP, Opcodes::OP_INVALIDOPCODE, Opcodes::OP_INVERT, Opcodes::OP_LEFT, Opcodes::OP_LESSTHAN, Opcodes::OP_LESSTHANOREQUAL, Opcodes::OP_LSHIFT, Opcodes::OP_MAX, Opcodes::OP_MIN, Opcodes::OP_MOD, Opcodes::OP_MUL, Opcodes::OP_NEGATE, Opcodes::OP_NIP, Opcodes::OP_NOP, Opcodes::OP_NOP1, Opcodes::OP_NOP10, Opcodes::OP_NOP2, Opcodes::OP_NOP3, Opcodes::OP_NOP4, Opcodes::OP_NOP5, Opcodes::OP_NOP6, Opcodes::OP_NOP7, Opcodes::OP_NOP8, Opcodes::OP_NOP9, Opcodes::OP_NOT, Opcodes::OP_NOTIF, Opcodes::OP_NUMEQUAL, Opcodes::OP_NUMEQUALVERIFY, Opcodes::OP_NUMNOTEQUAL, Opcodes::OP_OR, Opcodes::OP_OVER, Opcodes::OP_PICK, Opcodes::OP_PUBKEY, Opcodes::OP_PUBKEYHASH, Opcodes::OP_PUSHDATA1, Opcodes::OP_PUSHDATA2, Opcodes::OP_PUSHDATA4, Opcodes::OP_RESERVED, Opcodes::OP_RESERVED1, Opcodes::OP_RESERVED2, Opcodes::OP_RETURN, Opcodes::OP_RIGHT, Opcodes::OP_RIPEMD160, Opcodes::OP_ROLL, Opcodes::OP_ROT, Opcodes::OP_RSHIFT, Opcodes::OP_SHA1, Opcodes::OP_SHA256, Opcodes::OP_SIZE, Opcodes::OP_SUB, Opcodes::OP_SUBSTR, Opcodes::OP_SUCCESSES, Opcodes::OP_SWAP, Opcodes::OP_TOALTSTACK, Opcodes::OP_TUCK, Opcodes::OP_VER, Opcodes::OP_VERIF, Opcodes::OP_VERIFY, Opcodes::OP_VERNOTIF, Opcodes::OP_WITHIN, Opcodes::OP_XOR
Class Method Summary collapse
-
.addr(addr) ⇒ Bitcoin::Descriptor::Addr
Generate addr() descriptor.
-
.combo(key) ⇒ Bitcoin::Descriptor::Combo
Generate combo() descriptor.
-
.multi(threshold, *keys) ⇒ Bitcoin::Descriptor::Multi
Generate multi() descriptor.
-
.multi_a(threshold, *keys) ⇒ Bitcoin::Descriptor::MultiA
Generate multi_a() descriptor.
-
.musig(*keys, path: nil) ⇒ Bitcoin::Descriptor::MuSig
Generate musig() descriptor.
-
.parse(string, top_level = true) ⇒ Bitcoin::Descriptor::Expression
Parse descriptor string.
- .parse_nested_string(string) ⇒ Object
-
.pk(key) ⇒ Bitcoin::Descriptor::Pk
Generate pk() descriptor.
-
.pkh(key) ⇒ Bitcoin::Descriptor::Pkh
Generate pkh() descriptor.
-
.raw(hex) ⇒ Bitcoin::Descriptor::Raw
Generate raw() descriptor.
-
.rawtr(key) ⇒ Bitcoin::Descriptor::RawTr
Generate rawtr() descriptor.
-
.sh(exp) ⇒ Bitcoin::Descriptor::Sh
Generate sh() descriptor.
-
.sortedmulti(threshold, *keys) ⇒ Bitcoin::Descriptor::SortedMulti
Generate sortedmulti() descriptor.
-
.sortedmulti_a(threshold, *keys) ⇒ Bitcoin::Descriptor::SortedMulti
Generate sortedmulti_a() descriptor.
-
.sp(key_or_scan_key, spend_key = nil) ⇒ Bitcoin::Descriptor::Sp
Generate sp() descriptor for Silent Payment.
- .split_two(content) ⇒ Object
-
.tr(key, tree = nil) ⇒ Bitcoin::Descriptor::Tr
Generate tr() descriptor.
-
.validate_checksum!(descriptor) ⇒ Object
Validate descriptor checksum.
-
.wpkh(key) ⇒ Bitcoin::Descriptor::Wpkh
Generate wpkh() descriptor.
-
.wsh(exp) ⇒ Bitcoin::Descriptor::Wsh
Generate wsh() descriptor.
Methods included from Opcodes
defined?, name_to_opcode, op_success?, opcode_to_name, opcode_to_small_int, small_int_to_opcode
Class Method Details
.addr(addr) ⇒ Bitcoin::Descriptor::Addr
Generate addr() descriptor.
98 99 100 |
# File 'lib/bitcoin/descriptor.rb', line 98 def addr(addr) Addr.new(addr) end |
.combo(key) ⇒ Bitcoin::Descriptor::Combo
Generate combo() descriptor.
If the key is compressed, it also includes wpkh(KEY) and sh(wpkh(KEY)).
68 69 70 |
# File 'lib/bitcoin/descriptor.rb', line 68 def combo(key) Combo.new(key) end |
.multi(threshold, *keys) ⇒ Bitcoin::Descriptor::Multi
Generate multi() descriptor.
76 77 78 |
# File 'lib/bitcoin/descriptor.rb', line 76 def multi(threshold, *keys) Multi.new(threshold, keys) end |
.multi_a(threshold, *keys) ⇒ Bitcoin::Descriptor::MultiA
Generate multi_a() descriptor.
121 122 123 |
# File 'lib/bitcoin/descriptor.rb', line 121 def multi_a(threshold, *keys) MultiA.new(threshold, keys) end |
.musig(*keys, path: nil) ⇒ Bitcoin::Descriptor::MuSig
Generate musig() descriptor.
137 138 139 |
# File 'lib/bitcoin/descriptor.rb', line 137 def musig(*keys, path: nil) MuSig.new(keys, path) end |
.parse(string, top_level = true) ⇒ Bitcoin::Descriptor::Expression
Parse descriptor string.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/bitcoin/descriptor.rb', line 153 def parse(string, top_level = true) validate_checksum!(string) content, _ = string.split('#') exp, args_str, path = content.match(/(\w+)\((.+)\)(.*)/).captures # split "tag(10, 20)/0/1" raise ArgumentError, 'Invalid format.' if exp != 'musig' && !path.empty? case exp when 'pk' if args_str.include?('(') pk(parse(args_str)) else pk(args_str) end when 'pkh' pkh(args_str) when 'wpkh' wpkh(args_str) when 'sh' sh(parse(args_str, false)) when 'wsh' wsh(parse(args_str, false)) when 'combo' combo(args_str) when 'multi', 'sortedmulti', 'multi_a', 'sortedmulti_a' args = args_str.split(',') threshold = args[0].to_i keys = args[1..-1] case exp when 'multi' multi(threshold, *keys) when 'sortedmulti' sortedmulti(threshold, *keys) when 'multi_a' raise ArgumentError, "Can only have multi_a/sortedmulti_a inside tr()." if top_level multi_a(threshold, *keys) when 'sortedmulti_a' raise ArgumentError, "Can only have multi_a/sortedmulti_a inside tr()." if top_level sortedmulti_a(threshold, *keys) end when 'raw' raw(args_str) when 'addr' addr(args_str) when 'tr' key, tree = split_two(args_str) key = parse(key) if key.include?('(') if tree.nil? tr(key) elsif tree.start_with?('{') tr(key, parse_nested_string(tree)) else tr(key, parse(tree, false)) end when 'rawtr' if args_str.include?('(') rawtr(parse(args_str, false)) else rawtr(args_str) end when 'musig' keys = args_str.split(',') path.empty? ? musig(*keys) : musig(*keys, path: path) when 'sp' scan_key, spend_key_str = split_two(args_str) if spend_key_str.nil? # Single argument form: spscan or spspend encoded key sp(scan_key) else # Two argument form: separate scan and spend keys spend_key = spend_key_str.include?('(') ? parse(spend_key_str, false) : spend_key_str sp(scan_key, spend_key) end else raise ArgumentError, "Parse failed: #{string}" end end |
.parse_nested_string(string) ⇒ Object
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/bitcoin/descriptor.rb', line 245 def parse_nested_string(string) return nil if string.nil? stack = [] current = [] buffer = "" string.each_char do |c| case c when '{' stack << current current = [] when '}' unless buffer.empty? current << parse(buffer, false) buffer = "" end nested = current current = stack.pop current << nested when ',' unless buffer.empty? current << parse(buffer, false) buffer = "" end else buffer << c end end current << parse(buffer, false) unless buffer.empty? current.first end |
.pk(key) ⇒ Bitcoin::Descriptor::Pk
Generate pk() descriptor.
32 33 34 |
# File 'lib/bitcoin/descriptor.rb', line 32 def pk(key) Pk.new(key) end |
.pkh(key) ⇒ Bitcoin::Descriptor::Pkh
Generate pkh() descriptor.
39 40 41 |
# File 'lib/bitcoin/descriptor.rb', line 39 def pkh(key) Pkh.new(key) end |
.raw(hex) ⇒ Bitcoin::Descriptor::Raw
Generate raw() descriptor.
91 92 93 |
# File 'lib/bitcoin/descriptor.rb', line 91 def raw(hex) Raw.new(hex) end |
.rawtr(key) ⇒ Bitcoin::Descriptor::RawTr
Generate rawtr() descriptor.
113 114 115 |
# File 'lib/bitcoin/descriptor.rb', line 113 def rawtr(key) RawTr.new(key) end |
.sh(exp) ⇒ Bitcoin::Descriptor::Sh
Generate sh() descriptor.
53 54 55 |
# File 'lib/bitcoin/descriptor.rb', line 53 def sh(exp) Sh.new(exp) end |
.sortedmulti(threshold, *keys) ⇒ Bitcoin::Descriptor::SortedMulti
Generate sortedmulti() descriptor.
84 85 86 |
# File 'lib/bitcoin/descriptor.rb', line 84 def sortedmulti(threshold, *keys) SortedMulti.new(threshold, keys) end |
.sortedmulti_a(threshold, *keys) ⇒ Bitcoin::Descriptor::SortedMulti
Generate sortedmulti_a() descriptor.
129 130 131 |
# File 'lib/bitcoin/descriptor.rb', line 129 def sortedmulti_a(threshold, *keys) SortedMultiA.new(threshold, keys) end |
.sp(key_or_scan_key, spend_key = nil) ⇒ Bitcoin::Descriptor::Sp
Generate sp() descriptor for Silent Payment.
146 147 148 |
# File 'lib/bitcoin/descriptor.rb', line 146 def sp(key_or_scan_key, spend_key = nil) Sp.new(key_or_scan_key, spend_key) end |
.split_two(content) ⇒ Object
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/bitcoin/descriptor.rb', line 276 def split_two(content) paren_depth = 0 split_pos = content.chars.find_index do |char| case char when '(' then paren_depth += 1; false when ')' then paren_depth -= 1; false when ',' then paren_depth == 0 else false end end if split_pos [content[0...split_pos], content[split_pos+1..-1]] else [content, nil] end end |
.tr(key, tree = nil) ⇒ Bitcoin::Descriptor::Tr
Generate tr() descriptor.
106 107 108 |
# File 'lib/bitcoin/descriptor.rb', line 106 def tr(key, tree = nil) Tr.new(key, tree) end |
.validate_checksum!(descriptor) ⇒ Object
Validate descriptor checksum.
232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/bitcoin/descriptor.rb', line 232 def validate_checksum!(descriptor) return unless descriptor.include?("#") content, *checksums = descriptor.split("#") raise ArgumentError, "Multiple '#' symbols." if checksums.length > 1 checksum = checksums.first len = checksum.nil? ? 0 : checksum.length raise ArgumentError, "Expected 8 character checksum, not #{len} characters." unless len == 8 _, calc_checksum = Checksum.descsum_create(content).split('#') unless calc_checksum == checksum raise ArgumentError, "Provided checksum '#{checksum}' does not match computed checksum '#{calc_checksum}'." end end |
.wpkh(key) ⇒ Bitcoin::Descriptor::Wpkh
Generate wpkh() descriptor.
46 47 48 |
# File 'lib/bitcoin/descriptor.rb', line 46 def wpkh(key) Wpkh.new(key) end |
.wsh(exp) ⇒ Bitcoin::Descriptor::Wsh
Generate wsh() descriptor.
60 61 62 |
# File 'lib/bitcoin/descriptor.rb', line 60 def wsh(exp) Wsh.new(exp) end |