bsv-wallet-postgres 0.5.0 → 0.100.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -115
  3. data/LICENSE +23 -80
  4. data/db/migrations/001_create_schema.rb +261 -0
  5. data/db/migrations/002_action_id_cascade.rb +66 -0
  6. data/db/migrations/003_schema_constraints.rb +297 -0
  7. data/db/migrations/004_drop_tx_reqs.rb +32 -0
  8. data/lib/bsv/wallet/postgres/action.rb +80 -0
  9. data/lib/bsv/wallet/postgres/action_label.rb +14 -0
  10. data/lib/bsv/wallet/postgres/arc_adapter.rb +32 -0
  11. data/lib/bsv/wallet/postgres/basket.rb +13 -0
  12. data/lib/bsv/wallet/postgres/block.rb +13 -0
  13. data/lib/bsv/wallet/postgres/broadcast.rb +87 -0
  14. data/lib/bsv/wallet/postgres/broadcast_callback.rb +54 -0
  15. data/lib/bsv/wallet/postgres/broadcast_queue.rb +98 -0
  16. data/lib/bsv/wallet/postgres/certificate.rb +13 -0
  17. data/lib/bsv/wallet/postgres/certificate_field.rb +13 -0
  18. data/lib/bsv/wallet/postgres/display_txid.rb +25 -0
  19. data/lib/bsv/wallet/postgres/input.rb +14 -0
  20. data/lib/bsv/wallet/postgres/label.rb +15 -0
  21. data/lib/bsv/wallet/postgres/output.rb +64 -0
  22. data/lib/bsv/wallet/postgres/output_basket.rb +15 -0
  23. data/lib/bsv/wallet/postgres/output_detail.rb +12 -0
  24. data/lib/bsv/wallet/postgres/output_tag.rb +14 -0
  25. data/lib/bsv/wallet/postgres/proof_store.rb +109 -0
  26. data/lib/bsv/wallet/postgres/setting.rb +32 -0
  27. data/lib/bsv/wallet/postgres/spendable.rb +12 -0
  28. data/lib/bsv/wallet/postgres/store.rb +580 -0
  29. data/lib/bsv/wallet/postgres/tag.rb +15 -0
  30. data/lib/bsv/wallet/postgres/tx_proof.rb +16 -0
  31. data/lib/bsv/wallet/postgres/utxo_pool.rb +58 -0
  32. data/lib/bsv/wallet/postgres/version.rb +9 -0
  33. data/lib/bsv/wallet/postgres.rb +77 -0
  34. data/lib/bsv-wallet-postgres.rb +1 -1
  35. metadata +49 -35
  36. data/lib/bsv/wallet_postgres/migrations/001_create_wallet_tables.rb +0 -58
  37. data/lib/bsv/wallet_postgres/migrations/002_add_output_state.rb +0 -33
  38. data/lib/bsv/wallet_postgres/migrations/003_add_wallet_settings.rb +0 -20
  39. data/lib/bsv/wallet_postgres/migrations/004_add_pending_metadata.rb +0 -69
  40. data/lib/bsv/wallet_postgres/migrations/005_add_txid_unique_index.rb +0 -27
  41. data/lib/bsv/wallet_postgres/migrations/006_create_broadcast_jobs.rb +0 -68
  42. data/lib/bsv/wallet_postgres/postgres_store.rb +0 -482
  43. data/lib/bsv/wallet_postgres/solid_queue_adapter.rb +0 -328
  44. data/lib/bsv/wallet_postgres/version.rb +0 -7
  45. data/lib/bsv/wallet_postgres.rb +0 -13
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ # PostgreSQL adapter for bsv-wallet.
6
+ #
7
+ # Call {.connect} before using any models. Loads the pg_enum and pg_array
8
+ # Sequel extensions and sets Sequel::Model.db for all models in this namespace.
9
+ module Postgres
10
+ autoload :VERSION, 'bsv/wallet/postgres/version'
11
+
12
+ # Component services (Layer 2a)
13
+ autoload :Store, 'bsv/wallet/postgres/store'
14
+ autoload :UTXOPool, 'bsv/wallet/postgres/utxo_pool'
15
+ autoload :BroadcastQueue, 'bsv/wallet/postgres/broadcast_queue'
16
+ autoload :BroadcastCallback, 'bsv/wallet/postgres/broadcast_callback'
17
+ autoload :ProofStore, 'bsv/wallet/postgres/proof_store'
18
+ autoload :ArcAdapter, 'bsv/wallet/postgres/arc_adapter'
19
+
20
+ # Shared concerns
21
+ require_relative 'postgres/display_txid'
22
+
23
+ # Models (Layer 2b — atomic services)
24
+ autoload :Block, 'bsv/wallet/postgres/block'
25
+ autoload :TxProof, 'bsv/wallet/postgres/tx_proof'
26
+ autoload :Action, 'bsv/wallet/postgres/action'
27
+ autoload :Broadcast, 'bsv/wallet/postgres/broadcast'
28
+ autoload :Basket, 'bsv/wallet/postgres/basket'
29
+ autoload :Output, 'bsv/wallet/postgres/output'
30
+ autoload :Spendable, 'bsv/wallet/postgres/spendable'
31
+ autoload :OutputDetail, 'bsv/wallet/postgres/output_detail'
32
+ autoload :OutputBasket, 'bsv/wallet/postgres/output_basket'
33
+ autoload :Input, 'bsv/wallet/postgres/input'
34
+ autoload :Label, 'bsv/wallet/postgres/label'
35
+ autoload :ActionLabel, 'bsv/wallet/postgres/action_label'
36
+ autoload :Tag, 'bsv/wallet/postgres/tag'
37
+ autoload :OutputTag, 'bsv/wallet/postgres/output_tag'
38
+ autoload :Certificate, 'bsv/wallet/postgres/certificate'
39
+ autoload :CertificateField, 'bsv/wallet/postgres/certificate_field'
40
+
41
+ autoload :Setting, 'bsv/wallet/postgres/setting'
42
+
43
+ class << self
44
+ # @return [Sequel::Database, nil] the connected database
45
+ attr_reader :db
46
+
47
+ # Establish a database connection for all models.
48
+ #
49
+ # @param url_or_db [String, Sequel::Database] connection URL or existing database
50
+ # @return [Sequel::Database]
51
+ def connect(url_or_db)
52
+ @db = url_or_db.is_a?(Sequel::Database) ? url_or_db : Sequel.connect(url_or_db)
53
+ @db.extension :pg_enum
54
+ @db.extension :pg_array
55
+ @db.extension :pg_json
56
+ Sequel::Model.db = @db
57
+ @db
58
+ end
59
+
60
+ # Disconnect and clear the database reference.
61
+ def disconnect
62
+ @db&.disconnect
63
+ @db = nil
64
+ end
65
+
66
+ # Run pending migrations against the connected database.
67
+ #
68
+ # @param target [Integer, nil] optional target migration version
69
+ def migrate!(target: nil)
70
+ Sequel.extension :migration
71
+ migrations_path = File.expand_path('../../db/migrations', __dir__)
72
+ Sequel::Migrator.run(@db, migrations_path, target: target)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -2,4 +2,4 @@
2
2
 
3
3
  require 'sequel'
4
4
  require 'bsv-wallet'
5
- require_relative 'bsv/wallet_postgres'
5
+ require_relative 'bsv/wallet/postgres'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bsv-wallet-postgres
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.100.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Bettison
@@ -15,74 +15,88 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 0.9.0
19
- - - "<"
20
- - !ruby/object:Gem::Version
21
- version: '1.0'
18
+ version: '0'
22
19
  type: :runtime
23
20
  prerelease: false
24
21
  version_requirements: !ruby/object:Gem::Requirement
25
22
  requirements:
26
23
  - - ">="
27
24
  - !ruby/object:Gem::Version
28
- version: 0.9.0
29
- - - "<"
30
- - !ruby/object:Gem::Version
31
- version: '1.0'
25
+ version: '0'
32
26
  - !ruby/object:Gem::Dependency
33
- name: pg
27
+ name: sequel
34
28
  requirement: !ruby/object:Gem::Requirement
35
29
  requirements:
36
30
  - - "~>"
37
31
  - !ruby/object:Gem::Version
38
- version: '1'
32
+ version: '5.0'
39
33
  type: :runtime
40
34
  prerelease: false
41
35
  version_requirements: !ruby/object:Gem::Requirement
42
36
  requirements:
43
37
  - - "~>"
44
38
  - !ruby/object:Gem::Version
45
- version: '1'
39
+ version: '5.0'
46
40
  - !ruby/object:Gem::Dependency
47
- name: sequel
41
+ name: pg
48
42
  requirement: !ruby/object:Gem::Requirement
49
43
  requirements:
50
- - - "~>"
44
+ - - ">="
51
45
  - !ruby/object:Gem::Version
52
- version: '5'
46
+ version: '0'
53
47
  type: :runtime
54
48
  prerelease: false
55
49
  version_requirements: !ruby/object:Gem::Requirement
56
50
  requirements:
57
- - - "~>"
51
+ - - ">="
58
52
  - !ruby/object:Gem::Version
59
- version: '5'
60
- description: Persistent Sequel/Postgres-backed BSV::Wallet::StorageAdapter implementation
61
- for production BSV wallet deployments.
53
+ version: '0'
54
+ description: Sequel models, migrations, and concrete Store/BroadcastQueue/ProofStore
55
+ implementations for the bsv-wallet gem, backed by PostgreSQL.
62
56
  executables: []
63
57
  extensions: []
64
58
  extra_rdoc_files: []
65
59
  files:
66
60
  - CHANGELOG.md
67
61
  - LICENSE
62
+ - db/migrations/001_create_schema.rb
63
+ - db/migrations/002_action_id_cascade.rb
64
+ - db/migrations/003_schema_constraints.rb
65
+ - db/migrations/004_drop_tx_reqs.rb
68
66
  - lib/bsv-wallet-postgres.rb
69
- - lib/bsv/wallet_postgres.rb
70
- - lib/bsv/wallet_postgres/migrations/001_create_wallet_tables.rb
71
- - lib/bsv/wallet_postgres/migrations/002_add_output_state.rb
72
- - lib/bsv/wallet_postgres/migrations/003_add_wallet_settings.rb
73
- - lib/bsv/wallet_postgres/migrations/004_add_pending_metadata.rb
74
- - lib/bsv/wallet_postgres/migrations/005_add_txid_unique_index.rb
75
- - lib/bsv/wallet_postgres/migrations/006_create_broadcast_jobs.rb
76
- - lib/bsv/wallet_postgres/postgres_store.rb
77
- - lib/bsv/wallet_postgres/solid_queue_adapter.rb
78
- - lib/bsv/wallet_postgres/version.rb
79
- homepage: https://github.com/sgbett/bsv-ruby-sdk
67
+ - lib/bsv/wallet/postgres.rb
68
+ - lib/bsv/wallet/postgres/action.rb
69
+ - lib/bsv/wallet/postgres/action_label.rb
70
+ - lib/bsv/wallet/postgres/arc_adapter.rb
71
+ - lib/bsv/wallet/postgres/basket.rb
72
+ - lib/bsv/wallet/postgres/block.rb
73
+ - lib/bsv/wallet/postgres/broadcast.rb
74
+ - lib/bsv/wallet/postgres/broadcast_callback.rb
75
+ - lib/bsv/wallet/postgres/broadcast_queue.rb
76
+ - lib/bsv/wallet/postgres/certificate.rb
77
+ - lib/bsv/wallet/postgres/certificate_field.rb
78
+ - lib/bsv/wallet/postgres/display_txid.rb
79
+ - lib/bsv/wallet/postgres/input.rb
80
+ - lib/bsv/wallet/postgres/label.rb
81
+ - lib/bsv/wallet/postgres/output.rb
82
+ - lib/bsv/wallet/postgres/output_basket.rb
83
+ - lib/bsv/wallet/postgres/output_detail.rb
84
+ - lib/bsv/wallet/postgres/output_tag.rb
85
+ - lib/bsv/wallet/postgres/proof_store.rb
86
+ - lib/bsv/wallet/postgres/setting.rb
87
+ - lib/bsv/wallet/postgres/spendable.rb
88
+ - lib/bsv/wallet/postgres/store.rb
89
+ - lib/bsv/wallet/postgres/tag.rb
90
+ - lib/bsv/wallet/postgres/tx_proof.rb
91
+ - lib/bsv/wallet/postgres/utxo_pool.rb
92
+ - lib/bsv/wallet/postgres/version.rb
93
+ homepage: https://github.com/sgbett/bsv-wallet
80
94
  licenses:
81
95
  - LicenseRef-OpenBSV
82
96
  metadata:
83
- homepage_uri: https://github.com/sgbett/bsv-ruby-sdk
84
- source_code_uri: https://github.com/sgbett/bsv-ruby-sdk
85
- changelog_uri: https://github.com/sgbett/bsv-ruby-sdk/blob/master/gem/bsv-wallet-postgres/CHANGELOG.md
97
+ homepage_uri: https://github.com/sgbett/bsv-wallet
98
+ source_code_uri: https://github.com/sgbett/bsv-wallet
99
+ changelog_uri: https://github.com/sgbett/bsv-wallet/blob/master/gem/bsv-wallet-postgres/CHANGELOG.md
86
100
  rubygems_mfa_required: 'true'
87
101
  rdoc_options: []
88
102
  require_paths:
@@ -91,7 +105,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
105
  requirements:
92
106
  - - ">="
93
107
  - !ruby/object:Gem::Version
94
- version: '2.7'
108
+ version: '3.0'
95
109
  required_rubygems_version: !ruby/object:Gem::Requirement
96
110
  requirements:
97
111
  - - ">="
@@ -100,5 +114,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
114
  requirements: []
101
115
  rubygems_version: 4.0.10
102
116
  specification_version: 4
103
- summary: PostgreSQL storage adapter for bsv-wallet
117
+ summary: PostgreSQL adapter for bsv-wallet
104
118
  test_files: []
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Initial wallet schema for BSV::Wallet::PostgresStore.
4
- #
5
- # Five tables, all indexed for the query patterns the StorageAdapter
6
- # interface exposes. JSONB blobs hold the full hash the SDK stored so
7
- # adding fields to bsv-wallet's output/action/certificate records does
8
- # not require a schema change — only the fields we actively filter on
9
- # get dedicated indexed columns.
10
- Sequel.migration do
11
- change do
12
- create_table(:wallet_outputs) do
13
- primary_key :id
14
- String :outpoint, null: false, unique: true
15
- String :basket
16
- column :tags, 'text[]'
17
- TrueClass :spendable, null: false, default: true
18
- jsonb :data, null: false
19
- DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
20
- index %i[basket spendable]
21
- index :tags, type: :gin
22
- end
23
-
24
- create_table(:wallet_actions) do
25
- primary_key :id
26
- String :txid, null: false
27
- column :labels, 'text[]'
28
- jsonb :data, null: false
29
- DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
30
- index :labels, type: :gin
31
- end
32
-
33
- create_table(:wallet_certificates) do
34
- primary_key :id
35
- String :type, null: false
36
- String :serial_number, null: false
37
- String :certifier, null: false
38
- String :subject
39
- jsonb :data, null: false
40
- DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
41
- unique %i[type serial_number certifier], name: :wallet_certificates_natural_key
42
- index :certifier
43
- index :subject
44
- end
45
-
46
- create_table(:wallet_proofs) do
47
- String :txid, primary_key: true
48
- String :bump_hex, text: true, null: false
49
- DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
50
- end
51
-
52
- create_table(:wallet_transactions) do
53
- String :txid, primary_key: true
54
- String :tx_hex, text: true, null: false
55
- DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
56
- end
57
- end
58
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Add output lifecycle state column to wallet_outputs.
4
- #
5
- # Introduces a nullable +state+ text column alongside the existing boolean
6
- # +spendable+ column. The two fields are kept in sync by the application
7
- # layer (+PostgresStore#update_output_state+).
8
- #
9
- # === State values
10
- #
11
- # * +spendable+ — the output is available for coin selection
12
- # * +pending+ — the output has been selected but the spending transaction
13
- # has not yet been broadcast or confirmed
14
- # * +spent+ — the output has been consumed by a confirmed transaction
15
- #
16
- # === Backward compatibility
17
- #
18
- # Rows written before this migration have +state = NULL+. The application
19
- # treats +state IS NULL AND spendable = TRUE+ as equivalent to
20
- # +state = 'spendable'+ so that existing data continues to behave
21
- # correctly without a backfill.
22
- #
23
- # The migration is intentionally non-destructive: +state+ is nullable
24
- # so the migration itself applies instantly on large tables (no rewrite,
25
- # no default scan). A backfill can be run offline if required.
26
- Sequel.migration do
27
- change do
28
- alter_table(:wallet_outputs) do
29
- add_column :state, String, null: true
30
- add_index :state
31
- end
32
- end
33
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Add wallet settings table to BSV::Wallet::PostgresStore.
4
- #
5
- # Provides key-value persistence for wallet configuration (e.g. change
6
- # output parameters). Keys are short strings (e.g. 'change_params');
7
- # values are JSON-serialised strings so the schema never needs to change
8
- # when setting shapes evolve.
9
- #
10
- # The table uses +key+ as its primary key so +store_setting+ is a simple
11
- # upsert (insert-or-replace on conflict).
12
- Sequel.migration do
13
- change do
14
- create_table(:wallet_settings) do
15
- String :key, primary_key: true
16
- String :value, text: true, null: false
17
- DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
18
- end
19
- end
20
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Add pending lock metadata columns and satoshis to wallet_outputs.
4
- #
5
- # Introduces dedicated columns to support the auto-fund UTXO management
6
- # methods (+find_spendable_outputs+, +lock_utxos+, +update_output_state+,
7
- # +release_stale_pending!+) without requiring expensive JSONB extraction
8
- # on every query.
9
- #
10
- # === Columns added
11
- #
12
- # * +satoshis+ — bigint, nullable. Mirrors the value stored inside
13
- # the JSONB +data+ blob so that +find_spendable_outputs+
14
- # can +ORDER BY satoshis+ without casting. New writes
15
- # populate this column; existing rows leave it NULL
16
- # and queries fall back to +COALESCE(satoshis, (data->>'satoshis')::bigint, 0)+.
17
- #
18
- # * +pending_since+ — timestamp (UTC), nullable. Set to +NOW()+ when a
19
- # UTXO is locked via +lock_utxos+. Used by
20
- # +release_stale_pending!+ to identify stale locks.
21
- #
22
- # * +pending_reference+ — text, nullable. Caller-supplied label passed to
23
- # +lock_utxos+. Carried through for observability.
24
- #
25
- # * +no_send+ — boolean, default +false+. When +true+ the lock is
26
- # exempt from automatic stale recovery by
27
- # +release_stale_pending!+.
28
- #
29
- # === Index added
30
- #
31
- # A partial index on +(state, basket)+ filtered to rows where
32
- # +state IS NULL OR state = 'spendable'+ accelerates the hot path of
33
- # +find_spendable_outputs+: the vast majority of rows in a live wallet
34
- # are spendable, not pending or spent.
35
- #
36
- # === Backward compatibility
37
- #
38
- # All new columns are nullable (or carry a safe default). No existing rows
39
- # are modified. The application layer handles NULL values via +COALESCE+ or
40
- # explicit IS NULL checks.
41
- Sequel.migration do
42
- up do
43
- alter_table(:wallet_outputs) do
44
- add_column :satoshis, :bigint, null: true
45
- add_column :pending_since, :timestamptz, null: true
46
- add_column :pending_reference, String, null: true
47
- add_column :no_send, :boolean, null: false, default: false
48
- end
49
-
50
- # Partial index on spendable rows only — keeps the index small and
51
- # fast for the typical coin-selection scan.
52
- run <<~SQL
53
- CREATE INDEX wallet_outputs_spendable_basket_idx
54
- ON wallet_outputs (state, basket)
55
- WHERE (state IS NULL OR state = 'spendable');
56
- SQL
57
- end
58
-
59
- down do
60
- run 'DROP INDEX IF EXISTS wallet_outputs_spendable_basket_idx;'
61
-
62
- alter_table(:wallet_outputs) do
63
- drop_column :no_send
64
- drop_column :pending_reference
65
- drop_column :pending_since
66
- drop_column :satoshis
67
- end
68
- end
69
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Add a unique index on wallet_actions.txid.
4
- #
5
- # Within a single wallet there should be at most one action per transaction.
6
- # Without this constraint, concurrent inserts or retries could create duplicate
7
- # rows sharing the same txid, causing +update_action_status+ to update multiple
8
- # rows unintentionally.
9
- #
10
- # The index also accelerates the +where(txid:)+ lookups performed by
11
- # +update_action_status+ and +delete_action+.
12
- #
13
- # === Backward compatibility
14
- #
15
- # The migration will fail if duplicate txids already exist in the table. Clean
16
- # up any duplicates before running this migration:
17
- #
18
- # DELETE FROM wallet_actions a
19
- # USING wallet_actions b
20
- # WHERE a.id > b.id AND a.txid = b.txid;
21
- Sequel.migration do
22
- change do
23
- alter_table(:wallet_actions) do
24
- add_index :txid, unique: true, name: :wallet_actions_txid_unique
25
- end
26
- end
27
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Broadcast job queue table for the SolidQueueAdapter.
4
- #
5
- # Tracks outbound transactions that need to be broadcast to the network,
6
- # with state machine, retry counters, and advisory locking support so that
7
- # multiple worker processes can poll the queue without double-processing.
8
- #
9
- # === Columns
10
- #
11
- # * +txid+ — TEXT NOT NULL UNIQUE. Prevents duplicate queue entries
12
- # for the same transaction.
13
- #
14
- # * +status+ — TEXT NOT NULL DEFAULT 'unsent'. State machine values:
15
- # 'unsent', 'sending', 'completed', 'failed'.
16
- #
17
- # * +beef_hex+ — TEXT NOT NULL. Serialised BEEF payload to broadcast.
18
- #
19
- # * +input_outpoints+ — text[], nullable. Outpoints consumed by the tx, used
20
- # to release UTXOs on success or rollback on failure.
21
- #
22
- # * +change_outpoints+ — text[], nullable. Change outpoints created by the tx,
23
- # used to mark outputs spendable after confirmation.
24
- #
25
- # * +fund_ref+ — TEXT, nullable. Caller-supplied funding reference for
26
- # observability and reconciliation.
27
- #
28
- # * +attempts+ — INTEGER NOT NULL DEFAULT 0. Incremented on each
29
- # broadcast attempt; gates retry logic.
30
- #
31
- # * +last_error+ — TEXT, nullable. Message from the last failed attempt.
32
- #
33
- # * +locked_at+ — TIMESTAMPTZ, nullable. Set when a worker claims the
34
- # job; cleared on completion or stale-lock recovery.
35
- #
36
- # * +created_at+ — TIMESTAMPTZ NOT NULL DEFAULT NOW().
37
- #
38
- # * +updated_at+ — TIMESTAMPTZ NOT NULL DEFAULT NOW().
39
- #
40
- # === Index
41
- #
42
- # A composite index on +(status, locked_at)+ (named +broadcast_jobs_poll_idx+)
43
- # supports the hot-path poll query:
44
- #
45
- # WHERE status = 'unsent'
46
- # OR (status = 'sending' AND locked_at < NOW() - interval '300 seconds'
47
- # AND attempts < 5)
48
- # ORDER BY created_at
49
- # FOR UPDATE SKIP LOCKED
50
- Sequel.migration do
51
- change do
52
- create_table(:wallet_broadcast_jobs) do
53
- primary_key :id, type: :Bignum
54
- String :txid, null: false, unique: true
55
- String :status, null: false, default: 'unsent'
56
- String :beef_hex, text: true, null: false
57
- column :input_outpoints, 'text[]'
58
- column :change_outpoints, 'text[]'
59
- String :fund_ref
60
- Integer :attempts, null: false, default: 0
61
- String :last_error, text: true
62
- column :locked_at, :timestamptz
63
- column :created_at, :timestamptz, null: false, default: Sequel::CURRENT_TIMESTAMP
64
- column :updated_at, :timestamptz, null: false, default: Sequel::CURRENT_TIMESTAMP
65
- index %i[status locked_at], name: :broadcast_jobs_poll_idx
66
- end
67
- end
68
- end