bsv-sdk 0.18.1 → 0.19.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.
@@ -19,7 +19,7 @@ module BSV
19
19
  # auth: { api_key: 'mainnet_your_key_here' }
20
20
  # )
21
21
  # result = protocol.call(:broadcast, tx)
22
- # puts result.data[:txid] if result.success?
22
+ # puts result.data[:txid] if result.http_success?
23
23
  #
24
24
  # @see https://docs.taal.com TAAL API documentation
25
25
  class TAALBinary < BSV::Network::Protocol
@@ -42,7 +42,7 @@ module BSV
42
42
  # TAAL-specific headers and applies TAAL-specific response quirk handling.
43
43
  #
44
44
  # @param tx [#to_binary, String] transaction object or raw binary string
45
- # @return [Result::Success, Result::Error]
45
+ # @return [ProtocolResponse]
46
46
  def call_broadcast(tx)
47
47
  body = tx.respond_to?(:to_binary) ? tx.to_binary : tx
48
48
 
@@ -57,27 +57,26 @@ module BSV
57
57
  parse_broadcast_response(response)
58
58
  end
59
59
 
60
- # Maps the HTTP response from TAAL broadcast to a Result, applying the
61
- # +txn-already-known+ idempotency quirk.
60
+ # Maps the HTTP response from TAAL broadcast to a ProtocolResponse, applying
61
+ # the +txn-already-known+ idempotency quirk.
62
62
  #
63
63
  # @param response [Net::HTTPResponse]
64
- # @return [Result::Success, Result::Error]
64
+ # @return [ProtocolResponse]
65
65
  def parse_broadcast_response(response)
66
66
  code = response.code.to_i
67
67
  body = parse_json_body(response.body)
68
68
 
69
- # TAAL API boundary: display-order hex txid from the TAAL broadcast response
70
- return Result::Success.new(data: { txid: body['txid'] }) if already_known?(body) && body['txid']
71
-
72
- retryable = code == 429 || (500..599).cover?(code)
69
+ # TAAL API boundary: display-order hex txid from the TAAL broadcast response.
70
+ # The HTTP response class is non-2xx here, so we must pass http_success: true explicitly.
71
+ return ProtocolResponse.new(response, data: { txid: body['txid'] }, http_success: true) if already_known?(body) && body['txid']
73
72
 
74
73
  if (200..299).cover?(code)
75
- return Result::Error.new(message: 'TAAL returned a malformed 2xx response', retryable: false) unless body['txid']
74
+ return ProtocolResponse.new(response, http_success: false, error_message: 'TAAL returned a malformed 2xx response') unless body['txid']
76
75
 
77
- Result::Success.new(data: { txid: body['txid'] })
76
+ ProtocolResponse.new(response, data: { txid: body['txid'] })
78
77
  else
79
78
  message = (body.is_a?(Hash) && body['error']) || "HTTP #{code}"
80
- Result::Error.new(message: message, retryable: retryable)
79
+ ProtocolResponse.new(response, http_success: false, error_message: message)
81
80
  end
82
81
  end
83
82
 
@@ -21,7 +21,7 @@ module BSV
21
21
  #
22
22
  # woc = BSV::Network::Protocols::WoCREST.new(network: :main)
23
23
  # result = woc.call(:get_tx, 'abc123...')
24
- # puts result.data if result.success?
24
+ # puts result.data if result.http_success?
25
25
  #
26
26
  # @see https://developers.whatsonchain.com/ WhatsOnChain API documentation
27
27
  class WoCREST < Protocol
@@ -169,18 +169,18 @@ module BSV
169
169
  # @param txid [String] WoC API boundary: display-order hex transaction ID
170
170
  # @param vout [Integer] output index
171
171
  # @param script_hash [String, nil] ignored
172
- # @return [Result::Success<Boolean>, Result::Error]
172
+ # @return [ProtocolResponse<Boolean>]
173
173
  def call_is_utxo(txid, vout, script_hash: nil) # rubocop:disable Lint/UnusedMethodArgument
174
174
  result = default_call(:is_utxo, txid, vout)
175
175
 
176
176
  # 404 = no spending tx found = output is unspent
177
- return Result::Success.new(data: true) if result.not_found?
177
+ return result.with(data: true, http_success: true, error_message: nil) if result.http_not_found?
178
178
 
179
179
  # Non-success, non-404 = genuine error
180
- return result unless result.success?
180
+ return result unless result.http_success?
181
181
 
182
182
  # 200 with spending tx details = output is spent
183
- Result::Success.new(data: false)
183
+ result.with(data: false)
184
184
  end
185
185
 
186
186
  # Bulk-checks whether a set of outputs are unspent.
@@ -192,15 +192,15 @@ module BSV
192
192
  # Entries absent from the response (unknown outputs) are treated as spent.
193
193
  #
194
194
  # @param outpoints [Array<Hash>] array of +{ txid:, vout: }+ hashes
195
- # @return [Result::Success<Hash{String => Boolean}>, Result::Error]
195
+ # @return [ProtocolResponse<Hash{String => Boolean}>]
196
196
  # On success, data is a hash mapping +"txid.vout"+ keys to booleans
197
197
  # (+true+ = unspent, +false+ = spent).
198
198
  def call_is_utxo_bulk(outpoints)
199
- return Result::Success.new(data: {}) if outpoints.empty?
199
+ return ProtocolResponse.new(nil, data: {}, http_success: true) if outpoints.empty?
200
200
 
201
201
  body = JSON.generate(utxos: outpoints.map { |op| { 'txid' => op[:txid].to_s, 'vout' => op[:vout].to_i } })
202
202
  result = default_call(:is_utxo_bulk, body: body)
203
- return result unless result.success?
203
+ return result unless result.http_success?
204
204
 
205
205
  # Build a lookup from the response entries
206
206
  # spentIn present and non-empty → spent (false); absent or empty → unspent (true)
@@ -219,7 +219,7 @@ module BSV
219
219
  normalised[key] = false unless normalised.key?(key)
220
220
  end
221
221
 
222
- Result::Success.new(data: normalised)
222
+ result.with(data: normalised)
223
223
  end
224
224
 
225
225
  # Broadcasts a raw transaction to WhatsOnChain.
@@ -229,17 +229,17 @@ module BSV
229
229
  # stripped and wrapped in a Hash for caller convenience.
230
230
  #
231
231
  # @param tx [#to_hex, String] transaction object or raw hex string
232
- # @return [Result::Success<{ txid: String }>, Result::Error]
232
+ # @return [ProtocolResponse<{ txid: String }>]
233
233
  def call_broadcast(tx)
234
234
  hex = tx.respond_to?(:to_hex) ? tx.to_hex : tx.to_s
235
235
  body = JSON.generate(txhex: hex)
236
236
 
237
237
  result = default_call(:broadcast, body: body)
238
- return result unless result.success?
238
+ return result unless result.http_success?
239
239
 
240
240
  # WoC returns plain-text txid — result.data is the raw body string
241
241
  # WoC API boundary: display-order hex txid returned as plain text
242
- Result::Success.new(data: { txid: result.data.to_s.strip })
242
+ result.with(data: { txid: result.data.to_s.strip })
243
243
  end
244
244
 
245
245
  # Decodes a raw transaction hex by posting to the WoC decode endpoint.
@@ -248,7 +248,7 @@ module BSV
248
248
  # full decoded transaction object.
249
249
  #
250
250
  # @param txhex [String] raw transaction hex string
251
- # @return [Result::Success<Hash>, Result::Error]
251
+ # @return [ProtocolResponse]
252
252
  def call_decode_tx(txhex)
253
253
  body = JSON.generate(txhex: txhex.to_s)
254
254
  default_call(:decode_tx, body: body)
@@ -259,7 +259,7 @@ module BSV
259
259
  # WoC expects +{ "txids": [...] }+ as the request body.
260
260
  #
261
261
  # @param txids [Array<String>] list of transaction IDs
262
- # @return [Result::Success<Array>, Result::Error]
262
+ # @return [ProtocolResponse]
263
263
  def call_get_tx_hex_bulk(txids)
264
264
  body = JSON.generate(txids: txids)
265
265
  default_call(:get_tx_hex_bulk, body: body)
@@ -270,7 +270,7 @@ module BSV
270
270
  # WoC expects +{ "scripts": [...] }+ as the request body.
271
271
  #
272
272
  # @param script_hashes [Array<String>] list of script hashes
273
- # @return [Result::Success<Hash>, Result::Error]
273
+ # @return [ProtocolResponse]
274
274
  def call_get_script_unspent_bulk(script_hashes)
275
275
  body = JSON.generate(scripts: script_hashes)
276
276
  default_call(:get_script_unspent_bulk, body: body)
@@ -281,7 +281,7 @@ module BSV
281
281
  # WoC expects +{ "txids": [...] }+ as the request body.
282
282
  #
283
283
  # @param txids [Array<String>] list of transaction IDs
284
- # @return [Result::Success<Array>, Result::Error]
284
+ # @return [ProtocolResponse]
285
285
  def call_get_bulk_tx_details(txids)
286
286
  body = JSON.generate(txids: txids)
287
287
  default_call(:get_bulk_tx_details, body: body)
@@ -292,7 +292,7 @@ module BSV
292
292
  # WoC expects +{ "txids": [{ "txid": "...", "vouts": [0, 1] }, ...] }+ as the request body.
293
293
  #
294
294
  # @param tx_vouts [Array<Hash>] array of +{ txid:, vouts: [Integer] }+ hashes
295
- # @return [Result::Success<Array>, Result::Error]
295
+ # @return [ProtocolResponse]
296
296
  def call_get_bulk_output_scripts(tx_vouts)
297
297
  body = JSON.generate(txids: tx_vouts.map { |tv| { 'txid' => tv[:txid].to_s, 'vouts' => tv[:vouts] } })
298
298
  default_call(:get_bulk_output_scripts, body: body)
@@ -303,7 +303,7 @@ module BSV
303
303
  # WoC expects +{ "addresses": [...] }+ as the request body.
304
304
  #
305
305
  # @param addresses [Array<String>] list of addresses
306
- # @return [Result::Success<Array>, Result::Error]
306
+ # @return [ProtocolResponse]
307
307
  def call_get_bulk_address_utxos(addresses)
308
308
  body = JSON.generate(addresses: addresses)
309
309
  default_call(:get_bulk_address_utxos, body: body)
@@ -314,7 +314,7 @@ module BSV
314
314
  # WoC expects +{ "addresses": [...] }+ as the request body.
315
315
  #
316
316
  # @param addresses [Array<String>] list of addresses
317
- # @return [Result::Success<Array>, Result::Error]
317
+ # @return [ProtocolResponse]
318
318
  def call_get_bulk_address_unconfirmed_utxos(addresses)
319
319
  body = JSON.generate(addresses: addresses)
320
320
  default_call(:get_bulk_address_unconfirmed_utxos, body: body)
@@ -325,7 +325,7 @@ module BSV
325
325
  # WoC expects +{ "scripts": [...] }+ as the request body.
326
326
  #
327
327
  # @param script_hashes [Array<String>] list of script hashes
328
- # @return [Result::Success<Hash>, Result::Error]
328
+ # @return [ProtocolResponse]
329
329
  def call_get_bulk_script_unconfirmed_unspent(script_hashes)
330
330
  body = JSON.generate(scripts: script_hashes)
331
331
  default_call(:get_bulk_script_unconfirmed_unspent, body: body)
@@ -336,7 +336,7 @@ module BSV
336
336
  # WoC expects +{ "query": "..." }+ as the request body.
337
337
  #
338
338
  # @param query [String] search term
339
- # @return [Result::Success<Hash>, Result::Error]
339
+ # @return [ProtocolResponse]
340
340
  def call_search_links(query)
341
341
  body = JSON.generate(query: query)
342
342
  default_call(:search_links, body: body)
@@ -351,7 +351,7 @@ module BSV
351
351
  #
352
352
  # @param txids [Array<String>, nil] list of transaction IDs (positional)
353
353
  # @param body [String, nil] pre-serialised request body (keyword)
354
- # @return [Result::Success<Array>, Result::Error]
354
+ # @return [ProtocolResponse]
355
355
  # @raise [ArgumentError] when neither txids nor body is provided
356
356
  def call_get_tx_status(txids = nil, body: nil)
357
357
  raise ArgumentError, 'provide txids array or body: keyword' if txids.nil? && body.nil?
@@ -368,13 +368,13 @@ module BSV
368
368
  #
369
369
  # @param root [String] expected merkle root as hex
370
370
  # @param height [Integer] block height
371
- # @return [Result::Success<Boolean>, Result::Error, Result::NotFound]
371
+ # @return [ProtocolResponse<Boolean>]
372
372
  def call_valid_root(root, height)
373
373
  result = default_call(:valid_root, height)
374
- return result unless result.success?
374
+ return result unless result.http_success?
375
375
 
376
376
  actual = result.data['merkleroot']
377
- Result::Success.new(data: actual.to_s.downcase == root.to_s.downcase)
377
+ result.with(data: actual.to_s.downcase == root.to_s.downcase)
378
378
  end
379
379
  end
380
380
  end
@@ -20,7 +20,7 @@ module BSV
20
20
  # end
21
21
  #
22
22
  # result = gorillapool.call(:broadcast, tx)
23
- # result.success? # => true
23
+ # result.http_success? # => true
24
24
  class Provider
25
25
  attr_reader :name, :auth, :rate_limit
26
26
 
@@ -124,7 +124,7 @@ module BSV
124
124
  # @param command_name [Symbol, String] command to invoke
125
125
  # @param args [Array] positional arguments forwarded to the protocol
126
126
  # @param kwargs [Hash] keyword arguments forwarded to the protocol
127
- # @return [Result::Success, Result::Error, Result::NotFound]
127
+ # @return [ProtocolResponse]
128
128
  # @raise [ArgumentError] when no registered protocol serves the command
129
129
  def call(command_name, *args, **kwargs)
130
130
  sym = command_name.to_sym
data/lib/bsv/network.rb CHANGED
@@ -2,16 +2,11 @@
2
2
 
3
3
  module BSV
4
4
  module Network
5
- autoload :Result, 'bsv/network/result'
5
+ autoload :ProtocolResponse, 'bsv/network/protocol_response'
6
6
  autoload :Protocol, 'bsv/network/protocol'
7
7
  autoload :Protocols, 'bsv/network/protocols'
8
8
  autoload :Providers, 'bsv/network/providers'
9
9
  autoload :Provider, 'bsv/network/provider'
10
- autoload :BroadcastError, 'bsv/network/broadcast_error'
11
- autoload :BroadcastResponse, 'bsv/network/broadcast_response'
12
- autoload :ChainProviderError, 'bsv/network/chain_provider_error'
13
10
  autoload :UTXO, 'bsv/network/utxo'
14
- autoload :ARC, 'bsv/network/arc'
15
- autoload :WhatsOnChain, 'bsv/network/whats_on_chain'
16
11
  end
17
12
  end
@@ -2,22 +2,40 @@
2
2
 
3
3
  module BSV
4
4
  module Transaction
5
- # Base class for chain trackers that verify merkle roots against the blockchain.
5
+ # Duck type for block header lookups used by the SDK's verify methods.
6
6
  #
7
- # Chain trackers confirm that a given merkle root corresponds to a valid block
8
- # at a specific height. This is essential for SPV verification without it,
9
- # merkle proofs cannot be validated against the actual blockchain.
7
+ # {Beef#verify}, {MerklePath#verify}, and {Transaction#verify} define
8
+ # what a valid structure *is* they walk trees, check proofs, and
9
+ # compare roots. But they have no data source of their own. The
10
+ # chain tracker is the data source: an object the consumer provides
11
+ # that can answer "is this merkle root valid for this block height?"
10
12
  #
11
- # Subclasses must implement {#valid_root_for_height?} and {#current_height}.
13
+ # The SDK is deliberately unopinionated about where that answer comes
14
+ # from. A chain tracker backed by an in-memory hash is declarative.
15
+ # One that fetches from the network on cache miss and writes to a
16
+ # database is imperative. The verify methods don't care — they just
17
+ # ask the question. All imperative behaviour (fetching, caching,
18
+ # persisting) lives in the consumer's chain tracker implementation,
19
+ # not in the SDK.
12
20
  #
13
- # @example Implementing a custom chain tracker
14
- # class MyTracker < BSV::Transaction::ChainTracker
15
- # def valid_root_for_height?(root, height)
16
- # # query your block header source
17
- # end
21
+ # Any object responding to +valid_root_for_height?+ and
22
+ # +current_height+ satisfies this interface. Inheriting from this
23
+ # class is optional — it exists to document the contract and provide
24
+ # clear error messages when methods are missing.
18
25
  #
19
- # def current_height
20
- # # return current chain tip height
26
+ # @example In-memory chain tracker (test / declarative)
27
+ # class HashTracker < BSV::Transaction::ChainTracker
28
+ # def initialize(headers) @headers = headers end
29
+ # def valid_root_for_height?(root, h) @headers[h] == root end
30
+ # def current_height() @headers.keys.max end
31
+ # end
32
+ # tracker = HashTracker.new(800_000 => 'abcd...')
33
+ #
34
+ # @example Cache-aware chain tracker (production / imperative)
35
+ # class WalletChainTracker < BSV::Transaction::ChainTracker
36
+ # def valid_root_for_height?(root, height)
37
+ # header = @db.find_header(height) || fetch_and_store(height)
38
+ # header.merkle_root == root
21
39
  # end
22
40
  # end
23
41
  class ChainTracker
@@ -54,17 +54,12 @@ module BSV
54
54
  # @param root [String] merkle root as a hex string
55
55
  # @param height [Integer] block height
56
56
  # @return [Boolean]
57
- # @raise [BSV::Network::ChainProviderError] on network or API error
57
+ # @raise [StandardError] on network or API error
58
58
  def valid_root_for_height?(root, height)
59
59
  result = @protocol.call(:get_block_header, height)
60
- return false if result.not_found?
60
+ return false if result.http_not_found?
61
61
 
62
- if result.error?
63
- raise BSV::Network::ChainProviderError.new(
64
- result.message.to_s,
65
- status_code: result.metadata[:status_code]
66
- )
67
- end
62
+ raise result.message.to_s unless result.http_success?
68
63
 
69
64
  merkle_root = result.data['merkleRoot']
70
65
  return false unless merkle_root
@@ -75,15 +70,12 @@ module BSV
75
70
  # Return the current blockchain height.
76
71
  #
77
72
  # @return [Integer]
78
- # @raise [BSV::Network::ChainProviderError] on network or API error
73
+ # @raise [StandardError] on network or API error
79
74
  def current_height
80
75
  result = @protocol.call(:current_height)
81
- return result.data if result.success?
76
+ return result.data if result.http_success?
82
77
 
83
- raise BSV::Network::ChainProviderError.new(
84
- result.message.to_s,
85
- status_code: result.metadata[:status_code]
86
- )
78
+ raise result.message.to_s
87
79
  end
88
80
  end
89
81
  end
@@ -47,17 +47,12 @@ module BSV
47
47
  # @param root [String] merkle root as a hex string
48
48
  # @param height [Integer] block height
49
49
  # @return [Boolean]
50
- # @raise [BSV::Network::ChainProviderError] on network or API error
50
+ # @raise [StandardError] on network or API error
51
51
  def valid_root_for_height?(root, height)
52
52
  result = @protocol.call(:valid_root, root, height)
53
- return false if result.not_found?
53
+ return false if result.http_not_found?
54
54
 
55
- if result.error?
56
- raise BSV::Network::ChainProviderError.new(
57
- result.message.to_s,
58
- status_code: result.metadata[:status_code]
59
- )
60
- end
55
+ raise result.message.to_s unless result.http_success?
61
56
 
62
57
  result.data == true
63
58
  end
@@ -65,15 +60,12 @@ module BSV
65
60
  # Return the current blockchain height.
66
61
  #
67
62
  # @return [Integer]
68
- # @raise [BSV::Network::ChainProviderError] on network or API error
63
+ # @raise [StandardError] on network or API error
69
64
  def current_height
70
65
  result = @protocol.call(:current_height)
71
- return result.data if result.success?
66
+ return result.data if result.http_success?
72
67
 
73
- raise BSV::Network::ChainProviderError.new(
74
- result.message.to_s,
75
- status_code: result.metadata[:status_code]
76
- )
68
+ raise result.message.to_s
77
69
  end
78
70
 
79
71
  # Wraps an injectable HTTP client to set a raw Authorization header value
data/lib/bsv/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BSV
4
- VERSION = '0.18.1'
4
+ VERSION = '0.19.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bsv-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.1
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Bettison
@@ -96,11 +96,8 @@ files:
96
96
  - lib/bsv/mcp/tools/generate_key.rb
97
97
  - lib/bsv/mcp/tools/helpers.rb
98
98
  - lib/bsv/network.rb
99
- - lib/bsv/network/arc.rb
100
- - lib/bsv/network/broadcast_error.rb
101
- - lib/bsv/network/broadcast_response.rb
102
- - lib/bsv/network/chain_provider_error.rb
103
99
  - lib/bsv/network/protocol.rb
100
+ - lib/bsv/network/protocol_response.rb
104
101
  - lib/bsv/network/protocols.rb
105
102
  - lib/bsv/network/protocols/arc.rb
106
103
  - lib/bsv/network/protocols/chaintracks.rb
@@ -113,9 +110,7 @@ files:
113
110
  - lib/bsv/network/providers/gorilla_pool.rb
114
111
  - lib/bsv/network/providers/taal.rb
115
112
  - lib/bsv/network/providers/whats_on_chain.rb
116
- - lib/bsv/network/result.rb
117
113
  - lib/bsv/network/utxo.rb
118
- - lib/bsv/network/whats_on_chain.rb
119
114
  - lib/bsv/overlay.rb
120
115
  - lib/bsv/overlay/admin_token_template.rb
121
116
  - lib/bsv/overlay/broadcast_facilitator.rb
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BSV
4
- module Network
5
- # @deprecated Use {BSV::Network::Protocols::ARC} directly instead.
6
- # The facade converted clean Result objects into exceptions — every
7
- # consumer immediately caught them and converted back to data.
8
- # Use the protocol layer, which returns Result objects natively.
9
- class ARC
10
- # Raised when deprecated facade classes are instantiated.
11
- class DeprecationError < StandardError; end
12
-
13
- MESSAGE = 'BSV::Network::ARC is deprecated. ' \
14
- 'Use BSV::Network::Protocols::ARC directly — it returns Result objects ' \
15
- 'instead of raising exceptions. See BSV::Network::Protocols::ARC for usage.'
16
-
17
- def self.default(**)
18
- raise DeprecationError, MESSAGE
19
- end
20
-
21
- def initialize(*)
22
- raise DeprecationError, MESSAGE
23
- end
24
- end
25
- end
26
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BSV
4
- module Network
5
- class BroadcastError < StandardError
6
- # ARC API boundary: display-order hex txid as returned by the ARC error response.
7
- attr_reader :status_code, :txid, :arc_status
8
-
9
- def initialize(message, status_code: nil, txid: nil, arc_status: nil)
10
- @status_code = status_code
11
- BSV::Primitives::Hex.validate_dtxid_hex!(txid, name: 'ARC error txid') if txid
12
- @txid = txid
13
- @arc_status = arc_status
14
- super(message)
15
- end
16
- end
17
- end
18
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BSV
4
- module Network
5
- class BroadcastResponse
6
- # ARC API boundary: display-order hex txid as returned by the ARC broadcast endpoint.
7
- attr_reader :txid, :tx_status, :message, :extra_info, :block_hash, :block_height, :timestamp, :competing_txs
8
-
9
- def initialize(attrs = {})
10
- txid = attrs[:txid]
11
- BSV::Primitives::Hex.validate_dtxid_hex!(txid, name: 'ARC broadcast txid') if txid
12
- @txid = txid
13
- @tx_status = attrs[:tx_status]
14
- @message = attrs[:message]
15
- @extra_info = attrs[:extra_info]
16
- @block_hash = attrs[:block_hash]
17
- @block_height = attrs[:block_height]
18
- @timestamp = attrs[:timestamp]
19
- @competing_txs = attrs[:competing_txs]
20
- end
21
-
22
- def success?
23
- true
24
- end
25
-
26
- def mined?
27
- tx_status == 'MINED'
28
- end
29
- end
30
- end
31
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BSV
4
- module Network
5
- class ChainProviderError < StandardError
6
- attr_reader :status_code
7
-
8
- def initialize(message, status_code: nil)
9
- @status_code = status_code
10
- super(message)
11
- end
12
- end
13
- end
14
- end
@@ -1,119 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BSV
4
- module Network
5
- # Result module provides three immutable value types for Protocol dispatch outcomes.
6
- #
7
- # All three types share a Predicates mixin with default false implementations.
8
- # Each type overrides only the predicate that returns true for that type.
9
- module Result
10
- # Mixin providing default false implementations for all query predicates.
11
- module Predicates
12
- def success?
13
- false
14
- end
15
-
16
- def error?
17
- false
18
- end
19
-
20
- def not_found?
21
- false
22
- end
23
- end
24
-
25
- # Represents a successful outcome. Carries the response payload in +data+
26
- # and optional protocol-specific extras in +metadata+.
27
- class Success
28
- include Predicates
29
-
30
- attr_reader :data, :metadata
31
-
32
- def initialize(data:, metadata: {})
33
- @data = data
34
- @metadata = metadata.freeze
35
- freeze
36
- end
37
-
38
- def success?
39
- true
40
- end
41
-
42
- def ==(other)
43
- other.is_a?(Success) && data == other.data && metadata == other.metadata
44
- end
45
-
46
- alias eql? ==
47
-
48
- def hash
49
- [self.class, data, metadata].hash
50
- end
51
- end
52
-
53
- # Represents a failed outcome. Carries a human-readable +message+, a boolean
54
- # +retryable+ flag indicating whether the caller should retry, and optional
55
- # +metadata+ for structured protocol-specific details (e.g. +arc_status+).
56
- class Error
57
- include Predicates
58
-
59
- attr_reader :message, :retryable, :metadata
60
-
61
- def initialize(message:, retryable: false, metadata: {})
62
- @message = message
63
- @retryable = retryable
64
- @metadata = metadata.freeze
65
- freeze
66
- end
67
-
68
- def error?
69
- true
70
- end
71
-
72
- def retryable?
73
- @retryable
74
- end
75
-
76
- def ==(other)
77
- other.is_a?(Error) &&
78
- message == other.message &&
79
- retryable == other.retryable &&
80
- metadata == other.metadata
81
- end
82
-
83
- alias eql? ==
84
-
85
- def hash
86
- [self.class, message, retryable, metadata].hash
87
- end
88
- end
89
-
90
- # Represents a resource-not-found outcome. Carries an optional human-readable
91
- # +message+ and optional +metadata+.
92
- class NotFound
93
- include Predicates
94
-
95
- attr_reader :message, :metadata
96
-
97
- def initialize(message: nil, metadata: {})
98
- @message = message
99
- @metadata = metadata.freeze
100
- freeze
101
- end
102
-
103
- def not_found?
104
- true
105
- end
106
-
107
- def ==(other)
108
- other.is_a?(NotFound) && message == other.message && metadata == other.metadata
109
- end
110
-
111
- alias eql? ==
112
-
113
- def hash
114
- [self.class, message, metadata].hash
115
- end
116
- end
117
- end
118
- end
119
- end