Module: Bitcoin::Descriptor

Includes:
Opcodes
Defined in:
lib/bitcoin/descriptor.rb,
lib/bitcoin/descriptor/pk.rb,
lib/bitcoin/descriptor/sh.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/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, Multi, MultiA, Pk, Pkh, Raw, RawTr, ScriptExpression, Sh, SortedMulti, SortedMultiA, 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

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 raw output script about hex.

Parameters:

  • addr (String)

    Bitcoin address.

Returns:



96
97
98
# File 'lib/bitcoin/descriptor.rb', line 96

def addr(addr)
  Addr.new(addr)
end

.combo(key) ⇒ Bitcoin::Descriptor::Combo

An alias for the collection of ‘pk(KEY)` and `pkh(KEY)`. If the key is compressed, it also includes `wpkh(KEY)` and `sh(wpkh(KEY))`.

Parameters:

  • key (String)

    private key or public key with hex format.

Returns:



66
67
68
# File 'lib/bitcoin/descriptor.rb', line 66

def combo(key)
  Combo.new(key)
end

.multi(threshold, *keys) ⇒ Bitcoin::Descriptor::Multi

Generate multisig output for given keys.

Parameters:

  • threshold (Integer)

    the threshold of multisig.

  • keys (Array[String])

    an array of keys.

Returns:



74
75
76
# File 'lib/bitcoin/descriptor.rb', line 74

def multi(threshold, *keys)
  Multi.new(threshold, keys)
end

.multi_a(threshold, *keys) ⇒ Bitcoin::Descriptor::MultiA

Generate tapscript multisig output for given keys.

Parameters:

  • threshold (Integer)

    the threshold of multisig.

  • keys (Array[String])

    an array of keys.

Returns:



119
120
121
# File 'lib/bitcoin/descriptor.rb', line 119

def multi_a(threshold, *keys)
  MultiA.new(threshold, keys)
end

.parse(string, top_level = true) ⇒ Bitcoin::Descriptor::Expression

Parse descriptor string.

Parameters:

  • string (String)

    Descriptor string.

Returns:



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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
# File 'lib/bitcoin/descriptor.rb', line 134

def parse(string, top_level = true)
  validate_checksum!(string)
  content, _ = string.split('#')
  exp, args_str = content.match(/(\w+)\((.+)\)/).captures
  case exp
  when 'pk'
    pk(args_str)
  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, rest = args_str.split(',', 2)
    if rest.nil?
      tr(key)
    elsif rest.start_with?('{')
      tr(key, parse_nested_string(rest))
    else
      tr(key, parse(rest, false))
    end
  when 'rawtr'
    rawtr(args_str)
  else
    raise ArgumentError, "Parse failed: #{string}"
  end
end

.parse_nested_string(string) ⇒ Object



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
229
230
231
# File 'lib/bitcoin/descriptor.rb', line 202

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 P2PK output for the given public key.

Parameters:

  • key (String)

    private key or public key with hex format

Returns:



30
31
32
# File 'lib/bitcoin/descriptor.rb', line 30

def pk(key)
  Pk.new(key)
end

.pkh(key) ⇒ Bitcoin::Descriptor::Pkh

Generate P2PKH output for the given public key.

Parameters:

  • key (String)

    private key or public key with hex format.

Returns:



37
38
39
# File 'lib/bitcoin/descriptor.rb', line 37

def pkh(key)
  Pkh.new(key)
end

.raw(hex) ⇒ Bitcoin::Descriptor::Raw

Generate raw output script about hex.

Parameters:

  • hex (String)

    Hex string of bitcoin script.

Returns:



89
90
91
# File 'lib/bitcoin/descriptor.rb', line 89

def raw(hex)
  Raw.new(hex)
end

.rawtr(key) ⇒ Bitcoin::Descriptor::RawTr

Generate taproot output script descriptor.

Parameters:

Returns:



111
112
113
# File 'lib/bitcoin/descriptor.rb', line 111

def rawtr(key)
  RawTr.new(key)
end

.sh(exp) ⇒ Bitcoin::Descriptor::Sh

Generate P2SH embed the argument.

Parameters:

  • exp (Bitcoin::Descriptor::Base)

    script expression to be embed.

Returns:



51
52
53
# File 'lib/bitcoin/descriptor.rb', line 51

def sh(exp)
  Sh.new(exp)
end

.sortedmulti(threshold, *keys) ⇒ Bitcoin::Descriptor::SortedMulti

Generate sorted multisig output for given keys.

Parameters:

  • threshold (Integer)

    the threshold of multisig.

  • keys (Array[String])

    an array of keys.

Returns:



82
83
84
# File 'lib/bitcoin/descriptor.rb', line 82

def sortedmulti(threshold, *keys)
  SortedMulti.new(threshold, keys)
end

.sortedmulti_a(threshold, *keys) ⇒ Bitcoin::Descriptor::SortedMulti

Generate tapscript sorted multisig output for given keys.

Parameters:

  • threshold (Integer)

    the threshold of multisig.

  • keys (Array[String])

    an array of keys.

Returns:



127
128
129
# File 'lib/bitcoin/descriptor.rb', line 127

def sortedmulti_a(threshold, *keys)
  SortedMultiA.new(threshold, keys)
end

.tr(key, tree = nil) ⇒ Bitcoin::Descriptor::Tr

Generate taproot output script descriptor.

Parameters:

Returns:



104
105
106
# File 'lib/bitcoin/descriptor.rb', line 104

def tr(key, tree = nil)
  Tr.new(key, tree)
end

.validate_checksum!(descriptor) ⇒ Object

Validate descriptor checksum.

Raises:

  • (ArgumentError)

    If descriptor has invalid checksum.



189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/bitcoin/descriptor.rb', line 189

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 P2PKH output for the given public key.

Parameters:

  • key (String)

    private key or public key with hex format.

Returns:



44
45
46
# File 'lib/bitcoin/descriptor.rb', line 44

def wpkh(key)
  Wpkh.new(key)
end

.wsh(exp) ⇒ Bitcoin::Descriptor::Wsh

Generate P2WSH embed the argument.

Parameters:

Returns:



58
59
60
# File 'lib/bitcoin/descriptor.rb', line 58

def wsh(exp)
  Wsh.new(exp)
end