solace 0.1.7 → 0.1.9
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.
- checksums.yaml +4 -4
- data/lib/rubocop/cop/solace/exploded_hash.rb +82 -0
- data/lib/solace/accounts/address_lookup_table.rb +156 -0
- data/lib/solace/composers/address_lookup_table_program_create_composer.rb +95 -0
- data/lib/solace/composers/address_lookup_table_program_extend_composer.rb +87 -0
- data/lib/solace/composers/opaque_instruction_composer.rb +84 -0
- data/lib/solace/connection.rb +10 -0
- data/lib/solace/errors/address_lookup_table_not_found.rb +29 -0
- data/lib/solace/errors/rpc_error.rb +7 -1
- data/lib/solace/errors.rb +1 -0
- data/lib/solace/instructions/address_lookup_table_program/create_lookup_table_instruction.rb +80 -0
- data/lib/solace/instructions/address_lookup_table_program/extend_lookup_table_instruction.rb +69 -0
- data/lib/solace/transaction_composer.rb +195 -17
- data/lib/solace/transaction_decomposer.rb +250 -0
- data/lib/solace/utils/account_context.rb +73 -37
- data/lib/solace/utils/compute_budget.rb +85 -0
- data/lib/solace/version.rb +1 -1
- data/lib/solace.rb +9 -1
- metadata +12 -2
|
@@ -62,6 +62,7 @@ module Solace
|
|
|
62
62
|
def initialize
|
|
63
63
|
@header = []
|
|
64
64
|
@accounts = []
|
|
65
|
+
@loaded_accounts = []
|
|
65
66
|
@pubkey_account_map = {}
|
|
66
67
|
end
|
|
67
68
|
|
|
@@ -100,6 +101,27 @@ module Solace
|
|
|
100
101
|
merge_account(pubkey, signer: false, writable: false)
|
|
101
102
|
end
|
|
102
103
|
|
|
104
|
+
# Add or merge an account into the context
|
|
105
|
+
#
|
|
106
|
+
# The primitive the +add_*+ methods above name a role for; call it
|
|
107
|
+
# directly when the flags are data in hand. Permissions only ever widen:
|
|
108
|
+
# an account added twice keeps the union of what it was given.
|
|
109
|
+
#
|
|
110
|
+
# @param pubkey [#to_s, PublicKey] The public key of the account
|
|
111
|
+
# @param signer [Boolean] Whether the account is a signer
|
|
112
|
+
# @param writable [Boolean] Whether the account is writable
|
|
113
|
+
# @param fee_payer [Boolean] Whether the account pays the fee (see {#set_fee_payer})
|
|
114
|
+
def merge_account(pubkey, signer:, writable:, fee_payer: false)
|
|
115
|
+
pubkey_str = pubkey.to_s
|
|
116
|
+
|
|
117
|
+
@pubkey_account_map[pubkey_str] ||= DEFAULT_ACCOUNT.dup
|
|
118
|
+
@pubkey_account_map[pubkey_str][:signer] ||= signer
|
|
119
|
+
@pubkey_account_map[pubkey_str][:writable] ||= writable
|
|
120
|
+
@pubkey_account_map[pubkey_str][:fee_payer] ||= fee_payer
|
|
121
|
+
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
103
125
|
# Predicate to check if an account is a fee payer
|
|
104
126
|
#
|
|
105
127
|
# @param pubkey [String] The pubkey of the account
|
|
@@ -173,60 +195,69 @@ module Solace
|
|
|
173
195
|
# - Then writable accounts
|
|
174
196
|
# - Then readonly accounts
|
|
175
197
|
#
|
|
176
|
-
#
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
198
|
+
# For a v0 (versioned) transaction, accounts resolved through lookup tables
|
|
199
|
+
# leave the static account list entirely: the message carries only the
|
|
200
|
+
# static keys, and the runtime rebuilds the combined space
|
|
201
|
+
# [static..., loaded...] at execution time. Passing them keeps {#index_of}
|
|
202
|
+
# resolving against that combined space (so instructions index correctly)
|
|
203
|
+
# while dropping them from the static accounts and the header. They must be
|
|
204
|
+
# ordered writable-first to match the runtime's combined space. With no
|
|
205
|
+
# loaded accounts (the default) this is the legacy compilation, unchanged.
|
|
206
|
+
#
|
|
207
|
+
# @param loaded_accounts [Array<String>] Pubkeys resolved through lookup tables
|
|
208
|
+
# @return [AccountContext] Self
|
|
209
|
+
def compile(loaded_accounts: [])
|
|
210
|
+
@loaded_accounts = loaded_accounts
|
|
211
|
+
|
|
212
|
+
self.header = calculate_header(loaded_accounts)
|
|
213
|
+
self.accounts = order_accounts(loaded_accounts)
|
|
180
214
|
self
|
|
181
215
|
end
|
|
182
216
|
|
|
183
|
-
# Index of a pubkey in the
|
|
217
|
+
# Index of a pubkey in the combined account space
|
|
184
218
|
#
|
|
185
219
|
# @param pubkey_str [String] The public key of the account
|
|
186
|
-
# @return [Integer] The index
|
|
220
|
+
# @return [Integer] The index in the combined space, or -1 if not found
|
|
187
221
|
def index_of(pubkey_str)
|
|
188
222
|
indices[pubkey_str] || -1
|
|
189
223
|
end
|
|
190
224
|
|
|
191
|
-
#
|
|
225
|
+
# Map of pubkey => index across the combined space (static keys followed by
|
|
226
|
+
# any loaded accounts), so instruction indices resolve the same way the
|
|
227
|
+
# runtime does once lookup tables are expanded.
|
|
192
228
|
#
|
|
193
|
-
# @return [Hash{String => Integer}] The indices of the pubkeys
|
|
229
|
+
# @return [Hash{String => Integer}] The indices of the pubkeys
|
|
194
230
|
def indices
|
|
195
|
-
accounts.each_with_index.to_h
|
|
231
|
+
(accounts + @loaded_accounts).each_with_index.to_h
|
|
196
232
|
end
|
|
197
233
|
|
|
198
234
|
private
|
|
199
235
|
|
|
200
|
-
#
|
|
236
|
+
# Order the static accounts by signer, writable, readonly signer, readonly
|
|
201
237
|
#
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
# @param [
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
@pubkey_account_map[
|
|
211
|
-
@pubkey_account_map[pubkey_str][:writable] ||= writable
|
|
212
|
-
@pubkey_account_map[pubkey_str][:fee_payer] ||= fee_payer
|
|
213
|
-
|
|
214
|
-
self
|
|
238
|
+
# Loaded accounts are excluded — they leave the static account list and are
|
|
239
|
+
# resolved through lookup tables at runtime.
|
|
240
|
+
#
|
|
241
|
+
# @param loaded_accounts [Array<String>] Pubkeys resolved through lookup tables
|
|
242
|
+
# @return [Array<String>] The ordered static accounts
|
|
243
|
+
def order_accounts(loaded_accounts)
|
|
244
|
+
# Keyed on the position too: sort_by is not stable, and accounts of the
|
|
245
|
+
# same rank must keep the order they were added in
|
|
246
|
+
(@pubkey_account_map.keys - loaded_accounts).sort_by.with_index { |pubkey, index| [rank_of(pubkey), index] }
|
|
215
247
|
end
|
|
216
248
|
|
|
217
|
-
#
|
|
249
|
+
# The position of an account's segment in the static account list
|
|
218
250
|
#
|
|
219
|
-
# @
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
end
|
|
251
|
+
# @param pubkey [String] The pubkey of the account
|
|
252
|
+
# @return [Integer] The segment rank
|
|
253
|
+
def rank_of(pubkey)
|
|
254
|
+
if fee_payer?(pubkey) then 0
|
|
255
|
+
elsif writable_signer?(pubkey) then 1
|
|
256
|
+
elsif readonly_signer?(pubkey) then 2
|
|
257
|
+
elsif writable_nonsigner?(pubkey) then 3
|
|
258
|
+
elsif readonly_nonsigner?(pubkey) then 4
|
|
259
|
+
else
|
|
260
|
+
raise ArgumentError, "Unknown account type for pubkey: #{pubkey}"
|
|
230
261
|
end
|
|
231
262
|
end
|
|
232
263
|
|
|
@@ -237,9 +268,14 @@ module Solace
|
|
|
237
268
|
# - The number of readonly signers
|
|
238
269
|
# - The number of readonly unsigned accounts
|
|
239
270
|
#
|
|
271
|
+
# Loaded accounts no longer occupy the static account list, so they drop
|
|
272
|
+
# out of the header. They are never signers, so only the readonly-unsigned
|
|
273
|
+
# count changes.
|
|
274
|
+
#
|
|
275
|
+
# @param loaded_accounts [Array<String>] Pubkeys resolved through lookup tables
|
|
240
276
|
# @return [Array] The header for the transaction
|
|
241
|
-
def calculate_header
|
|
242
|
-
@pubkey_account_map.keys.each_with_object([0, 0, 0]) do |pubkey, acc|
|
|
277
|
+
def calculate_header(loaded_accounts)
|
|
278
|
+
(@pubkey_account_map.keys - loaded_accounts).each_with_object([0, 0, 0]) do |pubkey, acc|
|
|
243
279
|
acc[0] += 1 if signer?(pubkey)
|
|
244
280
|
|
|
245
281
|
if readonly_signer?(pubkey) then acc[1] += 1
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../composers/base'
|
|
4
|
+
require_relative '../composers/compute_budget_program_set_compute_unit_limit_composer'
|
|
5
|
+
require_relative '../composers/compute_budget_program_set_compute_unit_price_composer'
|
|
6
|
+
|
|
7
|
+
module Solace
|
|
8
|
+
module Utils
|
|
9
|
+
# The compute budget a transaction composer carries as a setting
|
|
10
|
+
#
|
|
11
|
+
# Holds the compute unit limit and price, answers the ComputeBudget composers
|
|
12
|
+
# they translate to (limit then price), and decides which directly added
|
|
13
|
+
# ComputeBudget composers the setting supersedes so the budget is never
|
|
14
|
+
# declared twice. Instances are immutable; {#merge} answers a new one.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# budget = Solace::Utils::ComputeBudget.new(units: 200_000, micro_lamports: 50_000)
|
|
18
|
+
# budget.composers # => [SetComputeUnitLimit composer, SetComputeUnitPrice composer]
|
|
19
|
+
#
|
|
20
|
+
# @see Solace::TransactionComposer#set_compute_budget
|
|
21
|
+
# @since 0.1.9
|
|
22
|
+
class ComputeBudget
|
|
23
|
+
# The composer a compute unit limit translates to
|
|
24
|
+
LIMIT_COMPOSER = Composers::ComputeBudgetProgramSetComputeUnitLimitComposer
|
|
25
|
+
private_constant :LIMIT_COMPOSER
|
|
26
|
+
|
|
27
|
+
# The composer a compute unit price translates to
|
|
28
|
+
PRICE_COMPOSER = Composers::ComputeBudgetProgramSetComputeUnitPriceComposer
|
|
29
|
+
private_constant :PRICE_COMPOSER
|
|
30
|
+
|
|
31
|
+
# @!attribute units
|
|
32
|
+
# The compute unit limit, or nil when none is set
|
|
33
|
+
attr_reader :units
|
|
34
|
+
|
|
35
|
+
# @!attribute micro_lamports
|
|
36
|
+
# The compute unit price in micro-lamports, or nil when none is set
|
|
37
|
+
attr_reader :micro_lamports
|
|
38
|
+
|
|
39
|
+
# Initialize the compute budget
|
|
40
|
+
#
|
|
41
|
+
# @param units [Integer, nil] The compute unit limit
|
|
42
|
+
# @param micro_lamports [Integer, nil] The compute unit price in micro-lamports
|
|
43
|
+
def initialize(units: nil, micro_lamports: nil)
|
|
44
|
+
@units = units
|
|
45
|
+
@micro_lamports = micro_lamports
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Whether any part of the budget is set
|
|
49
|
+
#
|
|
50
|
+
# @return [Boolean]
|
|
51
|
+
def set?
|
|
52
|
+
!(units.nil? && micro_lamports.nil?)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The ComputeBudget composers the budget translates to, limit then price
|
|
56
|
+
#
|
|
57
|
+
# @return [Array<Composers::Base>] The composers, empty when nothing is set
|
|
58
|
+
def composers
|
|
59
|
+
[
|
|
60
|
+
(LIMIT_COMPOSER.new(units: units) if units),
|
|
61
|
+
(PRICE_COMPOSER.new(micro_lamports: micro_lamports) if micro_lamports)
|
|
62
|
+
].compact
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Whether a directly added composer is replaced by a setting of the same kind
|
|
66
|
+
#
|
|
67
|
+
# @param composer [Composers::Base] The added composer
|
|
68
|
+
# @return [Boolean]
|
|
69
|
+
def supersedes?(composer)
|
|
70
|
+
(!units.nil? && composer.is_a?(LIMIT_COMPOSER)) || (!micro_lamports.nil? && composer.is_a?(PRICE_COMPOSER))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# A budget with the other's settings where it has them, and this one's otherwise
|
|
74
|
+
#
|
|
75
|
+
# @param other [ComputeBudget] The budget to fold in
|
|
76
|
+
# @return [ComputeBudget] The merged budget
|
|
77
|
+
def merge(other)
|
|
78
|
+
self.class.new(
|
|
79
|
+
units: other.units || units,
|
|
80
|
+
micro_lamports: other.micro_lamports || micro_lamports
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/solace/version.rb
CHANGED
data/lib/solace.rb
CHANGED
|
@@ -35,11 +35,14 @@ require_relative 'solace/version'
|
|
|
35
35
|
require_relative 'solace/errors'
|
|
36
36
|
require_relative 'solace/constants'
|
|
37
37
|
require_relative 'solace/connection'
|
|
38
|
+
require_relative 'solace/concerns/binary_serializable'
|
|
39
|
+
|
|
40
|
+
# Utils
|
|
38
41
|
require_relative 'solace/utils/codecs'
|
|
39
42
|
require_relative 'solace/utils/pda'
|
|
40
43
|
require_relative 'solace/utils/account_context'
|
|
44
|
+
require_relative 'solace/utils/compute_budget'
|
|
41
45
|
require_relative 'solace/utils/curve25519_dalek'
|
|
42
|
-
require_relative 'solace/concerns/binary_serializable'
|
|
43
46
|
|
|
44
47
|
# Tokens
|
|
45
48
|
require_relative 'solace/tokens'
|
|
@@ -55,7 +58,12 @@ require_relative 'solace/transaction'
|
|
|
55
58
|
require_relative 'solace/message'
|
|
56
59
|
require_relative 'solace/instruction'
|
|
57
60
|
require_relative 'solace/address_lookup_table'
|
|
61
|
+
|
|
62
|
+
# Accounts (on-chain account models)
|
|
63
|
+
require_relative 'solace/accounts/address_lookup_table'
|
|
64
|
+
|
|
58
65
|
require_relative 'solace/transaction_composer'
|
|
66
|
+
require_relative 'solace/transaction_decomposer'
|
|
59
67
|
|
|
60
68
|
# Base Classes (Abstract classes)
|
|
61
69
|
require_relative 'solace/programs/base'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solace
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sebastian Scholl
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07
|
|
11
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base58
|
|
@@ -201,13 +201,18 @@ executables: []
|
|
|
201
201
|
extensions: []
|
|
202
202
|
extra_rdoc_files: []
|
|
203
203
|
files:
|
|
204
|
+
- lib/rubocop/cop/solace/exploded_hash.rb
|
|
204
205
|
- lib/solace.rb
|
|
206
|
+
- lib/solace/accounts/address_lookup_table.rb
|
|
205
207
|
- lib/solace/address_lookup_table.rb
|
|
208
|
+
- lib/solace/composers/address_lookup_table_program_create_composer.rb
|
|
209
|
+
- lib/solace/composers/address_lookup_table_program_extend_composer.rb
|
|
206
210
|
- lib/solace/composers/associated_token_account_program_create_account_composer.rb
|
|
207
211
|
- lib/solace/composers/associated_token_account_program_create_idempotent_account_composer.rb
|
|
208
212
|
- lib/solace/composers/base.rb
|
|
209
213
|
- lib/solace/composers/compute_budget_program_set_compute_unit_limit_composer.rb
|
|
210
214
|
- lib/solace/composers/compute_budget_program_set_compute_unit_price_composer.rb
|
|
215
|
+
- lib/solace/composers/opaque_instruction_composer.rb
|
|
211
216
|
- lib/solace/composers/spl_token_program_close_account_composer.rb
|
|
212
217
|
- lib/solace/composers/spl_token_program_initialize_mint_composer.rb
|
|
213
218
|
- lib/solace/composers/spl_token_program_mint_to_composer.rb
|
|
@@ -224,6 +229,7 @@ files:
|
|
|
224
229
|
- lib/solace/connection.rb
|
|
225
230
|
- lib/solace/constants.rb
|
|
226
231
|
- lib/solace/errors.rb
|
|
232
|
+
- lib/solace/errors/address_lookup_table_not_found.rb
|
|
227
233
|
- lib/solace/errors/confirmation_timeout.rb
|
|
228
234
|
- lib/solace/errors/connection_error.rb
|
|
229
235
|
- lib/solace/errors/error.rb
|
|
@@ -231,6 +237,8 @@ files:
|
|
|
231
237
|
- lib/solace/errors/parse_error.rb
|
|
232
238
|
- lib/solace/errors/rpc_error.rb
|
|
233
239
|
- lib/solace/instruction.rb
|
|
240
|
+
- lib/solace/instructions/address_lookup_table_program/create_lookup_table_instruction.rb
|
|
241
|
+
- lib/solace/instructions/address_lookup_table_program/extend_lookup_table_instruction.rb
|
|
234
242
|
- lib/solace/instructions/associated_token_account/create_account_instruction.rb
|
|
235
243
|
- lib/solace/instructions/associated_token_account/create_idempotent_account_instruction.rb
|
|
236
244
|
- lib/solace/instructions/compute_budget/set_compute_unit_limit_instruction.rb
|
|
@@ -271,8 +279,10 @@ files:
|
|
|
271
279
|
- lib/solace/tokens/token.rb
|
|
272
280
|
- lib/solace/transaction.rb
|
|
273
281
|
- lib/solace/transaction_composer.rb
|
|
282
|
+
- lib/solace/transaction_decomposer.rb
|
|
274
283
|
- lib/solace/utils/account_context.rb
|
|
275
284
|
- lib/solace/utils/codecs.rb
|
|
285
|
+
- lib/solace/utils/compute_budget.rb
|
|
276
286
|
- lib/solace/utils/curve25519_dalek.rb
|
|
277
287
|
- lib/solace/utils/libcurve25519_dalek-linux-arm64/libcurve25519_dalek.so
|
|
278
288
|
- lib/solace/utils/libcurve25519_dalek-linux/libcurve25519_dalek.so
|