Module: OpenReceive::Payments
- Defined in:
- lib/openreceive/core.rb
Overview
Ruby port of the JS core wallet-history walk (listIncomingTransactions in packages/js/core/src/payments.ts): pages list_transactions until every expected hash is seen, the wallet runs out of rows, or the page cap is reached. A walk that ended before the wallet ran out of rows is TRUNCATED — a hash such a walk did not see is unproven, never proven absent.
Class Method Summary collapse
-
.list_incoming_transactions(client:, expected:, from: nil, until_time: nil, max_pages: nil, include_unpaid: false) ⇒ Object
clientmust respond to list_transactions(request) with an OpenReceive request hash; raw NIP-47 and already-normalized responses both work. - .normalize_max_pages(value) ⇒ Object
- .normalize_payment_hash(value) ⇒ Object
- .normalize_unix(value, field) ⇒ Object
-
.row_payment_hash(row) ⇒ Object
The scan key for one wallet row, or nil when the row can never match an attempt — a wallet-supplied row with a missing or malformed hash is skipped rather than rejected, so one quirky row cannot livelock reconciliation.
Class Method Details
.list_incoming_transactions(client:, expected:, from: nil, until_time: nil, max_pages: nil, include_unpaid: false) ⇒ Object
client must respond to list_transactions(request) with an OpenReceive
request hash; raw NIP-47 and already-normalized responses both work.
Returns { rows: { "<payment_hash>" =>
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 |
# File 'lib/openreceive/core.rb', line 482 def list_incoming_transactions(client:, expected:, from: nil, until_time: nil, max_pages: nil, include_unpaid: false) pages = normalize_max_pages(max_pages) outstanding = Array(expected).map { |value| normalize_payment_hash(value) } scan_from = from.nil? ? nil : normalize_unix(from, "from") scan_until = until_time.nil? ? nil : normalize_unix(until_time, "until") rows = {} offset = 0 previous_page = nil # Proven false the moment the wallet runs out of rows or every expected # hash is accounted for; otherwise the walk hit its cap with rows still # to come. truncated = true pages.times do request = { "type" => "incoming", "limit" => TRANSACTION_PAGE_LIMIT, "offset" => offset } request["unpaid"] = true if include_unpaid request["from"] = scan_from unless scan_from.nil? request["until"] = scan_until unless scan_until.nil? page = Nwc.normalize_list_transactions_response(client.list_transactions(request)).fetch("transactions") page.each do |row| next unless row["type"].nil? || row["type"] == "incoming" payment_hash = row_payment_hash(row) next if payment_hash.nil? rows[payment_hash] = row outstanding.delete(payment_hash) end if outstanding.empty? || page.length < TRANSACTION_PAGE_LIMIT truncated = false break end # A wallet that ignores `offset` serves the same page forever; stop # instead of paging to the cap, and keep the scan marked incomplete. page_key = page.map { |row| row["payment_hash"].to_s }.join(",") break if page_key == previous_page previous_page = page_key offset += TRANSACTION_PAGE_LIMIT end { rows: rows, truncated: truncated } end |
.normalize_max_pages(value) ⇒ Object
521 522 523 524 525 526 |
# File 'lib/openreceive/core.rb', line 521 def normalize_max_pages(value) return 10_000 if value.nil? pages = Integer(value) raise ArgumentError, "max_pages must be a positive integer" unless pages.positive? pages end |
.normalize_payment_hash(value) ⇒ Object
528 529 530 531 532 533 534 |
# File 'lib/openreceive/core.rb', line 528 def normalize_payment_hash(value) normalized = value.to_s.strip.downcase unless /\A[0-9a-f]{64}\z/.match?(normalized) raise ArgumentError, "payment_hash must be 64 hexadecimal characters" end normalized end |
.normalize_unix(value, field) ⇒ Object
545 546 547 548 549 |
# File 'lib/openreceive/core.rb', line 545 def normalize_unix(value, field) number = Integer(value) raise ArgumentError, "#{field} must be a non-negative integer" if number.negative? number end |
.row_payment_hash(row) ⇒ Object
The scan key for one wallet row, or nil when the row can never match an attempt — a wallet-supplied row with a missing or malformed hash is skipped rather than rejected, so one quirky row cannot livelock reconciliation.
540 541 542 543 |
# File 'lib/openreceive/core.rb', line 540 def row_payment_hash(row) payment_hash = row["payment_hash"].to_s.strip.downcase /\A[0-9a-f]{64}\z/.match?(payment_hash) ? payment_hash : nil end |