Class: Bitcoin::Descriptor::Expression

Inherits:
Object
  • Object
show all
Defined in:
lib/bitcoin/descriptor/expression.rb

Overview

Expression for descriptor.

Direct Known Subclasses

Addr, KeyExpression, Multi, Raw, ScriptExpression, Tr

Instance Method Summary collapse

Instance Method Details

#==(other) ⇒ Object



116
117
118
119
# File 'lib/bitcoin/descriptor/expression.rb', line 116

def ==(other)
  return false unless other.is_a?(Expression)
  type == other.type && to_script == other.to_script
end

#argsString

Get args for this expression.

Returns:

Raises:

  • (NotImplementedError)


26
27
28
# File 'lib/bitcoin/descriptor/expression.rb', line 26

def args
  raise NotImplementedError
end

#compressed_key?(key) ⇒ Boolean

Check whether key is compressed public key or not.

Returns:

  • (Boolean)


46
47
48
# File 'lib/bitcoin/descriptor/expression.rb', line 46

def compressed_key?(key)
  %w(02 03).include?(key[0..1]) && [key].pack("H*").bytesize == 33
end

#derive_path(key, paths) ⇒ Bitcoin::Key

Derive key using paths.

Parameters:

Returns:



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/bitcoin/descriptor/expression.rb', line 97

def derive_path(key, paths)
  is_private = key.is_a?(Bitcoin::ExtKey)
  paths.each do |path|
    raise ArgumentError, 'xpub can not derive hardened key.' if !is_private && path.end_with?("'")
    if is_private
      hardened = path.end_with?("'")
      path = hardened ? path[0..-2] : path
      raise ArgumentError, 'Key path value is not a valid value.' unless path =~ /^[0-9]+$/
      raise ArgumentError, 'Key path value is out of range.' if !hardened && path.to_i >= Bitcoin::HARDENED_THRESHOLD
      key = key.derive(path.to_i, hardened)
    else
      raise ArgumentError, 'Key path value is not a valid value.' unless path =~ /^[0-9]+$/
      raise ArgumentError, 'Key path value is out of range.' if path.to_i >= Bitcoin::HARDENED_THRESHOLD
      key = key.derive(path.to_i)
    end
  end
  key
end

#extract_pubkey(key) ⇒ Bitcoin::Key

Extract public key from KEY format.

Parameters:

  • key (String)

    KEY string.

Returns:

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/bitcoin/descriptor/expression.rb', line 53

def extract_pubkey(key)
  if key.start_with?('[') # BIP32 fingerprint
    raise ArgumentError, "Multiple ']' characters found for a single pubkey." if key.count('[') > 1 || key.count(']') > 1
    info = key[1...key.index(']')]
    fingerprint, *paths = info.split('/')
    raise ArgumentError, "Fingerprint '#{fingerprint}' is not hex." unless fingerprint.valid_hex?
    raise ArgumentError, "Fingerprint '#{fingerprint}' is not 4 bytes." unless fingerprint.size == 8
    key = key[(key.index(']') + 1)..-1]
  else
    raise ArgumentError, 'Invalid key origin.' if key.include?(']')
  end

  # check BIP32 derivation path
  key, *paths = key.split('/')

  raise ArgumentError, "No key provided." unless key

  if key.start_with?('xprv')
    key = Bitcoin::ExtKey.from_base58(key)
    key = derive_path(key, paths) if paths
  elsif key.start_with?('xpub')
    key = Bitcoin::ExtPubkey.from_base58(key)
    key = derive_path(key, paths) if paths
  else
    begin
      key = Bitcoin::Key.from_wif(key)
    rescue ArgumentError
      key = if key.length == 64
              Bitcoin::Key.from_xonly_pubkey(key)
            else
              key_type = compressed_key?(key) ? Bitcoin::Key::TYPES[:compressed] : Bitcoin::Key::TYPES[:uncompressed]
              Bitcoin::Key.new(pubkey: key, key_type: key_type)
            end
    end
  end
  key = key.is_a?(Bitcoin::Key) ? key : key.key
  raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless key.fully_valid_pubkey?
  key
end

#to_hexString

Convert to bitcoin script as hex string.

Returns:



40
41
42
# File 'lib/bitcoin/descriptor/expression.rb', line 40

def to_hex
  to_script.to_hex
end

#to_s(checksum: false) ⇒ String

Get descriptor string.

Parameters:

  • checksum (Boolean) (defaults to: false)

    If true, append checksum.

Returns:

  • (String)

    Descriptor string.



33
34
35
36
# File 'lib/bitcoin/descriptor/expression.rb', line 33

def to_s(checksum: false)
  desc = "#{type.to_s}(#{args})"
  checksum ? Checksum.descsum_create(desc) : desc
end

#to_scriptBitcoin::Script

Convert to bitcoin script

Returns:

Raises:

  • (NotImplementedError)


14
15
16
# File 'lib/bitcoin/descriptor/expression.rb', line 14

def to_script
  raise NotImplementedError
end

#top_level?Boolean

Whether this is top level or not.

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


20
21
22
# File 'lib/bitcoin/descriptor/expression.rb', line 20

def top_level?
  raise NotImplementedError
end

#typeSymbol

Get expression type.

Returns:

  • (Symbol)

Raises:

  • (NotImplementedError)


8
9
10
# File 'lib/bitcoin/descriptor/expression.rb', line 8

def type
  raise NotImplementedError
end