bsv-sdk 0.24.0 → 0.26.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -0
  3. data/README.md +4 -2
  4. data/lib/bsv/kv_store/entry.rb +15 -0
  5. data/lib/bsv/kv_store/global.rb +210 -0
  6. data/lib/bsv/kv_store/interpreter.rb +109 -0
  7. data/lib/bsv/kv_store/token.rb +10 -0
  8. data/lib/bsv/kv_store.rb +10 -0
  9. data/lib/bsv/mcp/tools/helpers.rb +3 -3
  10. data/lib/bsv/overlay/admin_token_template.rb +2 -2
  11. data/lib/bsv/overlay/historian.rb +118 -0
  12. data/lib/bsv/overlay/topic_broadcaster.rb +1 -1
  13. data/lib/bsv/overlay.rb +1 -0
  14. data/lib/bsv/primitives/digest.rb +107 -13
  15. data/lib/bsv/primitives/ecies.rb +12 -3
  16. data/lib/bsv/registry/client.rb +43 -1
  17. data/lib/bsv/script/bip276.rb +143 -0
  18. data/lib/bsv/script/interpreter/error.rb +2 -0
  19. data/lib/bsv/script/interpreter/interpreter.rb +226 -7
  20. data/lib/bsv/script/interpreter/operations/flow_control.rb +30 -13
  21. data/lib/bsv/script/push_drop_template.rb +2 -2
  22. data/lib/bsv/script/script.rb +21 -2
  23. data/lib/bsv/script.rb +1 -0
  24. data/lib/bsv/storage/downloader.rb +174 -0
  25. data/lib/bsv/storage/errors.rb +8 -0
  26. data/lib/bsv/storage/utils.rb +90 -0
  27. data/lib/bsv/storage.rb +16 -0
  28. data/lib/bsv/transaction/beef.rb +168 -14
  29. data/lib/bsv/transaction/beef_party.rb +119 -0
  30. data/lib/bsv/transaction/chain_tracker.rb +1 -1
  31. data/lib/bsv/transaction/fee_model.rb +1 -1
  32. data/lib/bsv/transaction/fee_models/live_policy.rb +1 -1
  33. data/lib/bsv/transaction/fee_models/satoshis_per_kilobyte.rb +1 -1
  34. data/lib/bsv/transaction/merkle_path.rb +1 -1
  35. data/lib/bsv/transaction/p2pkh.rb +1 -1
  36. data/lib/bsv/transaction/transaction_input.rb +78 -14
  37. data/lib/bsv/transaction/transaction_output.rb +46 -6
  38. data/lib/bsv/transaction/tx.rb +370 -39
  39. data/lib/bsv/transaction/unlocking_script_template.rb +2 -2
  40. data/lib/bsv/transaction.rb +1 -0
  41. data/lib/bsv/version.rb +1 -1
  42. data/lib/bsv-sdk.rb +2 -0
  43. metadata +13 -2
  44. data/lib/bsv/secp256k1_native.bundle +0 -0
@@ -9,33 +9,111 @@ module BSV
9
9
  # Thin wrappers around +OpenSSL::Digest+ and +OpenSSL::HMAC+ providing
10
10
  # the hash algorithms used throughout the BSV protocol: SHA-1, SHA-256,
11
11
  # double-SHA-256, SHA-512, RIPEMD-160, Hash160, HMAC, and PBKDF2.
12
+ #
13
+ # @note **Per-fibre cached OpenSSL contexts (via +Thread.current+)**
14
+ #
15
+ # +sha256+, +sha256d+, +sha1+, and +sha512+ each cache one
16
+ # +OpenSSL::Digest+ instance per fibre in +Thread.current+ under a
17
+ # namespaced key (e.g. +:bsv_sdk_sha256_digest+). Because MRI has no
18
+ # fibres in this SDK's +lib/+ today, "per fibre" and "per thread" are
19
+ # the same in practice — but the primitive is fibre-local, so the more
20
+ # precise term is used throughout. On every call the context is reset
21
+ # with +OpenSSL::Digest#reset+, which calls +EVP_DigestInit_ex+ against
22
+ # the +EVP_MD*+ already stored on the context. This skips the
23
+ # +EVP_get_digestbyname+ namemap lookup that
24
+ # +OpenSSL::Digest::SHA256.new+ (or +.digest+) performs on every fresh
25
+ # allocation. The namemap cost is paid exactly once per fibre per
26
+ # algorithm.
27
+ #
28
+ # **Fibre-local semantics.** +Thread.current[:key]+ is *fibre-local*
29
+ # in MRI (documented since Ruby 2.0, verified on 3.3 / 3.4 / 4.0) — each
30
+ # Fibre gets its own cached context. This is stronger than the SDK
31
+ # currently requires (no Fibres in +lib/+) and is correctly safe if
32
+ # Fibres are introduced later. The HLR body's "GVL makes it safe"
33
+ # rationale is subtly wrong; the correct reason is fibre-local scope.
34
+ #
35
+ # **Do not touch the cached instances externally.** The keys
36
+ # +:bsv_sdk_sha256_digest+, +:bsv_sdk_sha1_digest+, and
37
+ # +:bsv_sdk_sha512_digest+ are technically reachable via +Thread.current+
38
+ # but must never have +update+ called on them outside this module.
39
+ # Calling +update+ out-of-band would corrupt the next call's input.
40
+ #
41
+ # **User-visible invariants are unchanged:** return values are always
42
+ # +ASCII-8BIT+ binary strings; identical inputs always produce identical
43
+ # outputs; successive calls return distinct +String+ objects (output
44
+ # buffers are never cached).
45
+ #
46
+ # **Prefix convention.** +:bsv_sdk_<algo>_digest+ is the SDK-wide
47
+ # naming convention for any future +Thread.current+ usage in this
48
+ # codebase — the prefix avoids collision with other libraries that may
49
+ # also use +Thread.current+.
50
+ #
51
+ # **FIPS.** SHA-1, SHA-256, and SHA-512 remain FIPS-approved algorithms
52
+ # under this pattern; the algorithm fetch happens once at +.new+, not per
53
+ # call.
54
+ #
55
+ # **CI matrix.** Verified on MRI 3.3, 3.4, and 4.0. JRuby and
56
+ # TruffleRuby are not in the CI matrix — per-thread caching is correct on
57
+ # true-parallel Rubies (each thread has independent +Thread.current+) but
58
+ # unverified here.
59
+ #
60
+ # **Why other SDKs do not do this.** The TypeScript, Go, and Python SDKs
61
+ # allocate fresh digest contexts per call because their OpenSSL bindings
62
+ # cache the algorithm handle internally. MRI's +openssl+ gem bridges
63
+ # through +EVP_get_digestbyname+ on every allocation — we are patching
64
+ # the Ruby binding overhead, not diverging from BSV protocol semantics.
65
+ #
66
+ # **Out of scope with rationale:**
67
+ # - +ripemd160+ — pure-Ruby implementation; no OpenSSL context.
68
+ # - +hmac_sha256+ / +hmac_sha512+ — HMAC key changes per call. A future
69
+ # cache *must* key on wrapper-object identity (+object_id+), never on
70
+ # key bytes — a key-bytes cache lookup would create a secret-dependent
71
+ # side-channel via cache-hit timing.
72
+ # - +pbkdf2_hmac_sha512+ — one-shot at BIP-39 seed derivation; not a
73
+ # hot path.
12
74
  module Digest
13
75
  module_function
14
76
 
15
77
  # Compute SHA-1 digest.
16
78
  #
17
79
  # @param data [String] binary data to hash
18
- # @return [String] 20-byte digest
80
+ # @return [String] 20-byte digest (ASCII-8BIT)
19
81
  def sha1(data)
20
- OpenSSL::Digest::SHA1.digest(data)
82
+ d = Thread.current[:bsv_sdk_sha1_digest] ||= OpenSSL::Digest.new('SHA1')
83
+ d.reset
84
+ d.update(data)
85
+ d.digest
21
86
  end
22
87
 
23
88
  # Compute SHA-256 digest.
24
89
  #
25
90
  # @param data [String] binary data to hash
26
- # @return [String] 32-byte digest
91
+ # @return [String] 32-byte digest (ASCII-8BIT)
27
92
  def sha256(data)
28
- OpenSSL::Digest::SHA256.digest(data)
93
+ d = Thread.current[:bsv_sdk_sha256_digest] ||= OpenSSL::Digest.new('SHA256')
94
+ d.reset
95
+ d.update(data)
96
+ d.digest
29
97
  end
30
98
 
31
99
  # Compute double-SHA-256 (SHA-256d) digest.
32
100
  #
33
101
  # Used extensively in Bitcoin for transaction and block hashing.
102
+ # Inlines the two-round chain against the same cached SHA-256 context,
103
+ # saving one context allocation, one namemap lookup, one intermediate
104
+ # +String+, and one +module_function+ dispatch per call compared with
105
+ # the naive +sha256(sha256(data))+ decomposition.
34
106
  #
35
107
  # @param data [String] binary data to hash
36
- # @return [String] 32-byte digest
108
+ # @return [String] 32-byte digest (ASCII-8BIT)
37
109
  def sha256d(data)
38
- sha256(sha256(data))
110
+ d = Thread.current[:bsv_sdk_sha256_digest] ||= OpenSSL::Digest.new('SHA256')
111
+ d.reset
112
+ d.update(data)
113
+ first = d.digest
114
+ d.reset # defensive: some Ruby versions internally reset after #digest
115
+ d.update(first)
116
+ d.digest
39
117
  end
40
118
 
41
119
  alias hash256 sha256d
@@ -44,15 +122,23 @@ module BSV
44
122
  # Compute SHA-512 digest.
45
123
  #
46
124
  # @param data [String] binary data to hash
47
- # @return [String] 64-byte digest
125
+ # @return [String] 64-byte digest (ASCII-8BIT)
48
126
  def sha512(data)
49
- OpenSSL::Digest::SHA512.digest(data)
127
+ d = Thread.current[:bsv_sdk_sha512_digest] ||= OpenSSL::Digest.new('SHA512')
128
+ d.reset
129
+ d.update(data)
130
+ d.digest
50
131
  end
51
132
 
52
133
  # Compute RIPEMD-160 digest.
53
134
  #
135
+ # @note Uses the pure-Ruby {BSV::Primitives::Ripemd160} implementation —
136
+ # no OpenSSL context is held or cached here. RIPEMD-160 is not in
137
+ # scope for the per-thread caching optimisation (different optimisation
138
+ # track; not currently a hot path).
139
+ #
54
140
  # @param data [String] binary data to hash
55
- # @return [String] 20-byte digest
141
+ # @return [String] 20-byte digest (ASCII-8BIT)
56
142
  def ripemd160(data)
57
143
  Ripemd160.digest(data)
58
144
  end
@@ -62,25 +148,32 @@ module BSV
62
148
  # Standard Bitcoin hash used for addresses and P2PKH script matching.
63
149
  #
64
150
  # @param data [String] binary data to hash
65
- # @return [String] 20-byte digest
151
+ # @return [String] 20-byte digest (ASCII-8BIT)
66
152
  def hash160(data)
67
153
  ripemd160(sha256(data))
68
154
  end
69
155
 
70
156
  # Compute HMAC-SHA-256.
71
157
  #
158
+ # @note HMAC context reuse is deferred — the key changes per call, so a
159
+ # future cache must key on wrapper-object identity (+object_id+), never
160
+ # on key bytes, to avoid a secret-dependent side-channel via cache-hit
161
+ # timing.
162
+ #
72
163
  # @param key [String] HMAC key
73
164
  # @param data [String] data to authenticate
74
- # @return [String] 32-byte MAC
165
+ # @return [String] 32-byte MAC (ASCII-8BIT)
75
166
  def hmac_sha256(key, data)
76
167
  OpenSSL::HMAC.digest('SHA256', key, data)
77
168
  end
78
169
 
79
170
  # Compute HMAC-SHA-512.
80
171
  #
172
+ # @note HMAC context reuse is deferred — see +hmac_sha256+ note.
173
+ #
81
174
  # @param key [String] HMAC key
82
175
  # @param data [String] data to authenticate
83
- # @return [String] 64-byte MAC
176
+ # @return [String] 64-byte MAC (ASCII-8BIT)
84
177
  def hmac_sha512(key, data)
85
178
  OpenSSL::HMAC.digest('SHA512', key, data)
86
179
  end
@@ -88,12 +181,13 @@ module BSV
88
181
  # Derive a key using PBKDF2-HMAC-SHA-512.
89
182
  #
90
183
  # Used by BIP-39 to convert mnemonic phrases into seeds.
184
+ # One-shot at key creation — not a hot path; no context reuse applied.
91
185
  #
92
186
  # @param password [String] the password (mnemonic phrase)
93
187
  # @param salt [String] the salt (+"mnemonic"+ + passphrase)
94
188
  # @param iterations [Integer] iteration count (default: 2048 per BIP-39)
95
189
  # @param key_length [Integer] desired output length in bytes (default: 64)
96
- # @return [String] derived key bytes
190
+ # @return [String] derived key bytes (ASCII-8BIT)
97
191
  def pbkdf2_hmac_sha512(password, salt, iterations: 2048, key_length: 64)
98
192
  OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, 'sha512')
99
193
  end
@@ -147,15 +147,24 @@ module BSV
147
147
  # @param message [String] the plaintext message
148
148
  # @param public_key [PublicKey] the recipient's public key
149
149
  # @param private_key [PrivateKey, nil] optional ephemeral key (random if omitted)
150
+ # @param iv [String, nil] optional 16-byte ASCII-8BIT IV. When omitted a random IV is
151
+ # generated via +SecureRandom+. Supply a fixed value only for deterministic test
152
+ # vectors — **never use a fixed IV in production**.
150
153
  # @return [String] encrypted payload
151
- def bitcore_encrypt(message, public_key, private_key: nil)
154
+ # @raise [ArgumentError] if +iv+ is supplied but is not exactly 16 bytes
155
+ def bitcore_encrypt(message, public_key, private_key: nil, iv: nil)
152
156
  message = message.b if message.encoding != Encoding::ASCII_8BIT
153
157
 
158
+ if iv
159
+ iv = iv.b if iv.encoding != Encoding::ASCII_8BIT
160
+ raise ArgumentError, 'iv must be exactly 16 bytes' unless iv.bytesize == 16
161
+ else
162
+ iv = SecureRandom.random_bytes(16)
163
+ end
164
+
154
165
  ephemeral = private_key || PrivateKey.generate
155
166
  key_e, key_m = derive_bitcore_keys(ephemeral, public_key)
156
167
 
157
- iv = SecureRandom.random_bytes(16)
158
-
159
168
  cipher = OpenSSL::Cipher.new('aes-256-cbc')
160
169
  cipher.encrypt
161
170
  cipher.key = key_e
@@ -112,6 +112,48 @@ module BSV
112
112
  end
113
113
  end
114
114
 
115
+ # Resolves basket registry definitions.
116
+ #
117
+ # Thin wrapper around {#resolve} for cross-SDK parity with the Go SDK's
118
+ # +ResolveBasket+ method.
119
+ #
120
+ # @param query [Hash] optional filter criteria:
121
+ # - +:basket_id+ [String] exact basket identifier
122
+ # - +:name+ [String] human-readable basket name
123
+ # - +:registry_operators+ [Array<String>] operator public key hexes
124
+ # @return [Array<RegisteredDefinition>] matching registered basket definitions
125
+ def resolve_basket(query = {})
126
+ resolve(DefinitionType::BASKET, query)
127
+ end
128
+
129
+ # Resolves protocol registry definitions.
130
+ #
131
+ # Thin wrapper around {#resolve} for cross-SDK parity with the Go SDK's
132
+ # +ResolveProtocol+ method.
133
+ #
134
+ # @param query [Hash] optional filter criteria:
135
+ # - +:name+ [String] human-readable protocol name
136
+ # - +:protocol_id+ [Array] BRC-43 two-element protocol ID, e.g. +[1, 'protomap']+
137
+ # - +:registry_operators+ [Array<String>] operator public key hexes
138
+ # @return [Array<RegisteredDefinition>] matching registered protocol definitions
139
+ def resolve_protocol(query = {})
140
+ resolve(DefinitionType::PROTOCOL, query)
141
+ end
142
+
143
+ # Resolves certificate type registry definitions.
144
+ #
145
+ # Thin wrapper around {#resolve} for cross-SDK parity with the Go SDK's
146
+ # +ResolveCertificate+ method.
147
+ #
148
+ # @param query [Hash] optional filter criteria:
149
+ # - +:type+ [String] Base64-encoded certificate type identifier
150
+ # - +:name+ [String] human-readable certificate type name
151
+ # - +:registry_operators+ [Array<String>] operator public key hexes
152
+ # @return [Array<RegisteredDefinition>] matching registered certificate type definitions
153
+ def resolve_certificate(query = {})
154
+ resolve(DefinitionType::CERTIFICATE, query)
155
+ end
156
+
115
157
  # Lists the registry operator's own published definitions for the given type.
116
158
  #
117
159
  # Queries the wallet for spendable outputs in the appropriate basket,
@@ -430,7 +472,7 @@ module BSV
430
472
  #
431
473
  # @param definition_type [String]
432
474
  # @param output [Hash] wallet output with :outpoint, :satoshis keys
433
- # @param beef [BSV::Transaction::Beef] parsed BEEF
475
+ # @param beef [Transaction::Beef] parsed BEEF
434
476
  # @param beef_raw [String] raw BEEF bytes
435
477
  # @return [RegisteredDefinition, nil]
436
478
  def parse_own_output_to_registered_definition(definition_type, output, beef, beef_raw)
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bsv/primitives/digest'
4
+
5
+ module BSV
6
+ module Script
7
+ # BIP-276 text encoding for scripts and templates.
8
+ #
9
+ # Encodes and decodes typed bitcoin data using the scheme described in
10
+ # https://github.com/moneybutton/bips/blob/master/bip-0276.mediawiki
11
+ #
12
+ # Format: `<prefix>:<version-byte><network-byte><hex-payload><checksum>`
13
+ # where version and network are each one byte (two hex digits), and
14
+ # checksum is the first 4 bytes of double-SHA256 over the full preimage
15
+ # (the string up to and including the payload), hex-encoded.
16
+ #
17
+ # @note Field order is version-then-network, matching the BIP-276 spec
18
+ # and the Go SDK reference. The Python SDK has these reversed — a known
19
+ # py-sdk bug that is invisible at default v=1, n=1.
20
+ module BIP276
21
+ # Returned by {decode}; immutable value object.
22
+ Result = Data.define(:prefix, :version, :network, :data)
23
+
24
+ # Custom exception hierarchy.
25
+ class Error < StandardError; end
26
+ class InvalidFormat < Error; end
27
+ class InvalidChecksum < Error; end
28
+
29
+ PREFIX_SCRIPT = 'bitcoin-script'
30
+ PREFIX_TEMPLATE = 'bitcoin-template'
31
+ CURRENT_VERSION = 1
32
+ NETWORK_MAINNET = 1
33
+ NETWORK_TESTNET = 2
34
+
35
+ # Regex: prefix(:)(version 2 hex)(network 2 hex)(data hex*)(checksum 8 hex)
36
+ VALID_BIP276 = /\A(.+?):([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]*)([0-9A-Fa-f]{8})\z/
37
+
38
+ module_function
39
+
40
+ # Encode a binary payload as a BIP-276 string.
41
+ #
42
+ # @param data [String] binary payload (e.g. a {Script::Script}'s binary form)
43
+ # @param prefix [String] {PREFIX_SCRIPT} or {PREFIX_TEMPLATE} (or any custom prefix)
44
+ # @param version [Integer] 1..255 — {CURRENT_VERSION} by default
45
+ # @param network [Integer] 1..255 — {NETWORK_MAINNET} by default
46
+ # @return [String] BIP-276 encoded string
47
+ # @raise [ArgumentError] if version or network is out of the range 1..255
48
+ def encode(data, prefix: PREFIX_SCRIPT, network: NETWORK_MAINNET, version: CURRENT_VERSION)
49
+ raise ArgumentError, "version must be 1..255, got #{version}" unless (1..255).cover?(version)
50
+ raise ArgumentError, "network must be 1..255, got #{network}" unless (1..255).cover?(network)
51
+
52
+ preimage = build_preimage(prefix, version, network, data)
53
+ preimage + checksum(preimage)
54
+ end
55
+
56
+ # Decode a BIP-276 string.
57
+ #
58
+ # @param str [String] BIP-276 encoded string
59
+ # @return [Result] value object with +:prefix+, +:version+, +:network+, +:data+
60
+ # @raise [InvalidFormat] if the string is structurally malformed
61
+ # @raise [InvalidChecksum] if the checksum does not match the payload
62
+ def decode(str)
63
+ match = VALID_BIP276.match(str)
64
+ raise InvalidFormat, 'not a valid BIP-276 string' unless match
65
+
66
+ prefix = match[1]
67
+ version = match[2].to_i(16)
68
+ network = match[3].to_i(16)
69
+
70
+ raise InvalidFormat, 'data payload has odd number of hex digits' if match[4].length.odd?
71
+
72
+ data = [match[4]].pack('H*')
73
+
74
+ # Compute the checksum over the EXACT input bytes (everything except
75
+ # the trailing 8-hex-digit checksum) rather than rebuilding the
76
+ # preimage from parsed fields. Rebuilding via build_preimage would
77
+ # lowercase the payload hex, causing valid mixed-case input to fail.
78
+ preimage = str[0..-9]
79
+ expected = checksum(preimage)
80
+ raise InvalidChecksum, 'checksum mismatch' unless match[5].downcase == expected
81
+
82
+ Result.new(prefix: prefix, version: version, network: network, data: data)
83
+ end
84
+
85
+ # Encode a script payload using the {PREFIX_SCRIPT} prefix.
86
+ #
87
+ # @param (see encode)
88
+ # @return [String] BIP-276 encoded string with +bitcoin-script+ prefix
89
+ def encode_script(data, network: NETWORK_MAINNET, version: CURRENT_VERSION)
90
+ encode(data, prefix: PREFIX_SCRIPT, network: network, version: version)
91
+ end
92
+
93
+ # Encode a template payload using the {PREFIX_TEMPLATE} prefix.
94
+ #
95
+ # @param (see encode)
96
+ # @return [String] BIP-276 encoded string with +bitcoin-template+ prefix
97
+ def encode_template(data, network: NETWORK_MAINNET, version: CURRENT_VERSION)
98
+ encode(data, prefix: PREFIX_TEMPLATE, network: network, version: version)
99
+ end
100
+
101
+ # Decode a BIP-276 string that must have the {PREFIX_SCRIPT} prefix.
102
+ #
103
+ # @param str [String] BIP-276 encoded string
104
+ # @return [Result]
105
+ # @raise [InvalidFormat] if prefix is not +bitcoin-script+
106
+ # @raise [InvalidChecksum] if the checksum does not match
107
+ def decode_script(str)
108
+ result = decode(str)
109
+ raise InvalidFormat, "expected prefix '#{PREFIX_SCRIPT}', got '#{result.prefix}'" \
110
+ unless result.prefix == PREFIX_SCRIPT
111
+
112
+ result
113
+ end
114
+
115
+ # Decode a BIP-276 string that must have the {PREFIX_TEMPLATE} prefix.
116
+ #
117
+ # @param str [String] BIP-276 encoded string
118
+ # @return [Result]
119
+ # @raise [InvalidFormat] if prefix is not +bitcoin-template+
120
+ # @raise [InvalidChecksum] if the checksum does not match
121
+ def decode_template(str)
122
+ result = decode(str)
123
+ raise InvalidFormat, "expected prefix '#{PREFIX_TEMPLATE}', got '#{result.prefix}'" \
124
+ unless result.prefix == PREFIX_TEMPLATE
125
+
126
+ result
127
+ end
128
+
129
+ # @api private
130
+ def build_preimage(prefix, version, network, data)
131
+ format('%<prefix>s:%<version>02x%<network>02x%<payload>s',
132
+ prefix: prefix, version: version, network: network, payload: data.unpack1('H*'))
133
+ end
134
+ private_class_method :build_preimage
135
+
136
+ # @api private
137
+ def checksum(preimage)
138
+ BSV::Primitives::Digest.sha256d(preimage)[0, 4].unpack1('H*')
139
+ end
140
+ private_class_method :checksum
141
+ end
142
+ end
143
+ end
@@ -52,6 +52,8 @@ module BSV
52
52
  STACK_MEMORY_EXCEEDED = :stack_memory_exceeded
53
53
  UNIMPLEMENTED_OPCODE = :unimplemented_opcode
54
54
  MISSING_TX_CONTEXT = :missing_tx_context
55
+ SIG_PUSHONLY = :sig_pushonly
56
+ CLEAN_STACK = :clean_stack
55
57
  end
56
58
  end
57
59
  end