Module: Solana::Ruby::Kit::InstructionPlans
- Extended by:
- T::Sig
- Defined in:
- lib/solana/ruby/kit/instruction_plans/instruction_plan.rb,
lib/solana/ruby/kit/instruction_plans/max_instructions.rb,
lib/solana/ruby/kit/instruction_plans/transaction_plan.rb,
lib/solana/ruby/kit/instruction_plans/transaction_planner.rb,
lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb,
lib/solana/ruby/kit/instruction_plans/transaction_plan_executor.rb
Defined Under Namespace
Classes: CanceledStatus, FailedStatus, MessagePacker, MessagePackerInstructionPlan, ParallelInstructionPlan, ParallelTransactionPlan, ParallelTransactionPlanResult, SequentialInstructionPlan, SequentialTransactionPlan, SequentialTransactionPlanResult, SingleInstructionPlan, SingleTransactionPlan, SingleTransactionPlanResult, SuccessfulStatus
Constant Summary
collapse
- DEFAULT_MAX_INSTRUCTIONS_PER_TRANSACTION =
The default maximum number of top-level instructions per planned transaction message.
Intentionally lower than the transaction format's instruction limit to leave headroom
for inner instructions (CPIs), which are not visible at planning time.
T.let(16, Integer)
- TRANSACTION_INSTRUCTION_LIMIT =
The hard maximum number of top-level instructions the transaction format can encode.
T.let(64, Integer)
Class Method Summary
collapse
-
.assert_max_instructions_per_transaction(num_instructions, max_instructions) ⇒ Object
-
.assert_valid_max_instructions_per_transaction(max_instructions) ⇒ Object
-
.canceled_single_transaction_plan_result(message, context = {}) ⇒ Object
-
.create_transaction_plan_executor(execute_transaction_message:) ⇒ Object
-
.create_transaction_planner(create_transaction_message:, on_transaction_message_updated: ->(msg) { msg }, max_instructions_per_transaction: nil) ⇒ Object
-
.failed_single_transaction_plan_result(message, error, context = {}) ⇒ Object
-
.flatten_instruction_plan(plan) ⇒ Object
-
.get_all_single_transaction_plans(plan) ⇒ Object
-
.get_linear_message_packer_instruction_plan(total_length:, get_instruction:) ⇒ Object
-
.get_message_packer_instruction_plan_from_instructions(instructions) ⇒ Object
-
.get_realloc_message_packer_instruction_plan(total_size:, get_instruction:) ⇒ Object
-
.non_divisible_sequential_instruction_plan(plans) ⇒ Object
-
.non_divisible_sequential_transaction_plan(plans) ⇒ Object
-
.non_divisible_sequential_transaction_plan_result(plans) ⇒ Object
-
.parallel_instruction_plan(plans) ⇒ Object
-
.parallel_transaction_plan(plans) ⇒ Object
-
.parallel_transaction_plan_result(plans) ⇒ Object
-
.resolve_max_instructions(max_instructions) ⇒ Object
-
.sequential_instruction_plan(plans) ⇒ Object
-
.sequential_transaction_plan(plans) ⇒ Object
-
.sequential_transaction_plan_result(plans) ⇒ Object
-
.single_instruction_plan(instruction) ⇒ Object
-
.single_transaction_plan(message) ⇒ Object
-
.successful_single_transaction_plan_result(message, transaction = nil, context = {}) ⇒ Object
Class Method Details
.assert_max_instructions_per_transaction(num_instructions, max_instructions) ⇒ Object
.assert_valid_max_instructions_per_transaction(max_instructions) ⇒ Object
.canceled_single_transaction_plan_result(message, context = {}) ⇒ Object
144
145
146
147
148
149
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb', line 144
def canceled_single_transaction_plan_result(message, context = {})
SingleTransactionPlanResult.new(
message: message,
status: CanceledStatus.new(context: context.dup.freeze)
)
end
|
.create_transaction_plan_executor(execute_transaction_message:) ⇒ Object
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_executor.rb', line 40
def create_transaction_plan_executor(execute_transaction_message:)
->(transaction_plan) {
state = { canceled: false }
result = executor_traverse(transaction_plan, execute_transaction_message, state)
if state[:canceled]
cause = executor_find_error(result)
err = SolanaError.new(
SolanaError::INSTRUCTION_PLANS__FAILED_TO_EXECUTE_TRANSACTION_PLAN,
{ cause: cause }
)
err.instance_variable_set(:@transaction_plan_result, result)
err.define_singleton_method(:transaction_plan_result) { result }
Kernel.raise err
end
result
}
end
|
.create_transaction_planner(create_transaction_message:, on_transaction_message_updated: ->(msg) { msg }, max_instructions_per_transaction: nil) ⇒ Object
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_planner.rb', line 45
def create_transaction_planner(
create_transaction_message:,
on_transaction_message_updated: ->(msg) { msg },
max_instructions_per_transaction: nil
)
ctx = {
create_transaction_message: create_transaction_message,
on_transaction_message_updated: on_transaction_message_updated
}
config_max_instructions_per_transaction = max_instructions_per_transaction
->(instruction_plan, max_instructions_per_transaction: nil) {
resolved_max = max_instructions_per_transaction || config_max_instructions_per_transaction
InstructionPlans.assert_valid_max_instructions_per_transaction(resolved_max)
mutable = planner_traverse(
instruction_plan,
ctx.merge(parent: nil, parent_candidates: [], max_instructions_per_transaction: resolved_max)
)
Kernel.raise SolanaError.new(SolanaError::INSTRUCTION_PLANS__EMPTY_INSTRUCTION_PLAN) unless mutable
planner_freeze(mutable)
}
end
|
.failed_single_transaction_plan_result(message, error, context = {}) ⇒ Object
130
131
132
133
134
135
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb', line 130
def failed_single_transaction_plan_result(message, error, context = {})
SingleTransactionPlanResult.new(
message: message,
status: FailedStatus.new(error: error, context: context.dup.freeze)
)
end
|
.flatten_instruction_plan(plan) ⇒ Object
266
267
268
269
270
271
272
273
274
275
276
277
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 266
def flatten_instruction_plan(plan)
case plan
when SingleInstructionPlan
[plan.instruction]
when SequentialInstructionPlan, ParallelInstructionPlan
plan.plans.flat_map { |p| flatten_instruction_plan(p) }
when MessagePackerInstructionPlan
Kernel.raise ArgumentError, 'Cannot flatten a MessagePackerInstructionPlan (instructions are dynamically generated)'
else
Kernel.raise ArgumentError, "Unknown InstructionPlan type: #{plan.class}"
end
end
|
.get_all_single_transaction_plans(plan) ⇒ Object
79
80
81
82
83
84
85
86
87
88
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan.rb', line 79
def get_all_single_transaction_plans(plan)
case plan
when SingleTransactionPlan
[plan]
when SequentialTransactionPlan, ParallelTransactionPlan
plan.plans.flat_map { |p| get_all_single_transaction_plans(p) }
else
Kernel.raise ArgumentError, "Unknown TransactionPlan type: #{plan.class}"
end
end
|
.get_linear_message_packer_instruction_plan(total_length:, get_instruction:) ⇒ Object
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 140
def get_linear_message_packer_instruction_plan(total_length:, get_instruction:)
MessagePackerInstructionPlan.new(
get_message_packer: -> {
offset = T.let(0, Integer)
MessagePacker.new(
done_proc: -> { offset >= total_length },
pack_proc: ->(message, max_instructions) {
if offset >= total_length
Kernel.raise SolanaError.new(SolanaError::INSTRUCTION_PLANS__MESSAGE_PACKER_ALREADY_COMPLETE)
end
InstructionPlans.assert_valid_max_instructions_per_transaction(max_instructions)
resolved_max = InstructionPlans.resolve_max_instructions(max_instructions)
InstructionPlans.assert_max_instructions_per_transaction(message.instructions.length + 1, resolved_max)
base_ix = get_instruction.call(offset, 0)
with_base = TransactionMessages.append_instructions(message, [base_ix])
base_size = Transactions.get_transaction_message_size(with_base)
free_space = Transactions::TRANSACTION_SIZE_LIMIT - base_size - 1
if free_space <= 0
msg_size = Transactions.get_transaction_message_size(message)
Kernel.raise SolanaError.new(
SolanaError::INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN,
{
num_bytes_required: base_size - msg_size + 1,
num_free_bytes: Transactions::TRANSACTION_SIZE_LIMIT - msg_size - 1
}
)
end
length = [total_length - offset, free_space].min
ix = get_instruction.call(offset, length)
offset += length
TransactionMessages.append_instructions(message, [ix])
}
)
}
)
end
|
.get_message_packer_instruction_plan_from_instructions(instructions) ⇒ Object
.get_realloc_message_packer_instruction_plan(total_size:, get_instruction:) ⇒ Object
251
252
253
254
255
256
257
258
259
260
261
262
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 251
def get_realloc_message_packer_instruction_plan(total_size:, get_instruction:)
realloc_limit = 10_240
num_instructions = (total_size.to_f / realloc_limit).ceil
last_size = total_size % realloc_limit
instructions = num_instructions.times.map do |i|
chunk = (i == num_instructions - 1) ? last_size : realloc_limit
get_instruction.call(chunk)
end
get_message_packer_instruction_plan_from_instructions(instructions)
end
|
.non_divisible_sequential_instruction_plan(plans) ⇒ Object
120
121
122
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 120
def non_divisible_sequential_instruction_plan(plans)
SequentialInstructionPlan.new(plans: parse_single_instruction_plans(plans), divisible: false)
end
|
.non_divisible_sequential_transaction_plan(plans) ⇒ Object
64
65
66
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan.rb', line 64
def non_divisible_sequential_transaction_plan(plans)
SequentialTransactionPlan.new(plans: parse_single_transaction_plans(plans), divisible: false)
end
|
.non_divisible_sequential_transaction_plan_result(plans) ⇒ Object
89
90
91
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb', line 89
def non_divisible_sequential_transaction_plan_result(plans)
SequentialTransactionPlanResult.new(plans: plans, divisible: false)
end
|
.parallel_instruction_plan(plans) ⇒ Object
127
128
129
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 127
def parallel_instruction_plan(plans)
ParallelInstructionPlan.new(plans: parse_single_instruction_plans(plans))
end
|
.parallel_transaction_plan(plans) ⇒ Object
72
73
74
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan.rb', line 72
def parallel_transaction_plan(plans)
ParallelTransactionPlan.new(plans: parse_single_transaction_plans(plans))
end
|
.parallel_transaction_plan_result(plans) ⇒ Object
95
96
97
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb', line 95
def parallel_transaction_plan_result(plans)
ParallelTransactionPlanResult.new(plans: plans)
end
|
.resolve_max_instructions(max_instructions) ⇒ Object
.sequential_instruction_plan(plans) ⇒ Object
113
114
115
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 113
def sequential_instruction_plan(plans)
SequentialInstructionPlan.new(plans: parse_single_instruction_plans(plans), divisible: true)
end
|
.sequential_transaction_plan(plans) ⇒ Object
57
58
59
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan.rb', line 57
def sequential_transaction_plan(plans)
SequentialTransactionPlan.new(plans: parse_single_transaction_plans(plans), divisible: true)
end
|
.sequential_transaction_plan_result(plans) ⇒ Object
83
84
85
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb', line 83
def sequential_transaction_plan_result(plans)
SequentialTransactionPlanResult.new(plans: plans, divisible: true)
end
|
.single_instruction_plan(instruction) ⇒ Object
105
106
107
|
# File 'lib/solana/ruby/kit/instruction_plans/instruction_plan.rb', line 105
def single_instruction_plan(instruction)
SingleInstructionPlan.new(instruction: instruction)
end
|
.single_transaction_plan(message) ⇒ Object
49
50
51
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan.rb', line 49
def single_transaction_plan(message)
SingleTransactionPlan.new(message: message)
end
|
.successful_single_transaction_plan_result(message, transaction = nil, context = {}) ⇒ Object
112
113
114
115
116
117
118
119
120
|
# File 'lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb', line 112
def successful_single_transaction_plan_result(message, transaction = nil, context = {})
from_context = context[:transaction]
transaction ||= from_context if from_context.is_a?(Transactions::Transaction)
SingleTransactionPlanResult.new(
message: message,
status: SuccessfulStatus.new(transaction: transaction, context: context.dup.freeze)
)
end
|