Refactor - `BuiltinPrograms` (#31324)

* Moves BuiltinProgram of the program runtime into its own file.

* Unifies the runtimes Builtin and program runtimes BuiltinProgram definitions.

* Moves BuiltinPrograms from bank.rs into the program runtime.
This commit is contained in:
Alexander Meißner 2023-04-24 19:01:40 +02:00 committed by GitHub
parent 1b08d01a80
commit 4b0e16d06f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 175 additions and 193 deletions

View File

@ -1,13 +1,20 @@
use solana_runtime::builtins::{Builtin, BuiltinFeatureTransition, Builtins};
use {
solana_program_runtime::builtin_program::BuiltinProgram,
solana_runtime::builtins::{BuiltinFeatureTransition, Builtins},
};
macro_rules! to_builtin {
($b:expr) => {
Builtin::new(&$b.0, $b.1, $b.2)
BuiltinProgram {
name: $b.0.to_string(),
program_id: $b.1,
process_instruction: $b.2,
}
};
}
/// Builtin programs that are always available
fn genesis_builtins(bpf_jit: bool) -> Vec<Builtin> {
fn genesis_builtins(bpf_jit: bool) -> Vec<BuiltinProgram> {
// Currently JIT is not supported on the SBF VM:
// !x86_64: https://github.com/qmonnet/rbpf/issues/48
// Windows: https://github.com/solana-labs/rbpf/issues/217

View File

@ -0,0 +1,64 @@
#[cfg(RUSTC_WITH_SPECIALIZATION)]
use {crate::declare_process_instruction, solana_frozen_abi::abi_example::AbiExample};
use {
crate::invoke_context::InvokeContext, solana_rbpf::vm::BuiltInFunction,
solana_sdk::pubkey::Pubkey,
};
pub type ProcessInstructionWithContext = BuiltInFunction<InvokeContext<'static>>;
#[derive(Clone)]
pub struct BuiltinProgram {
pub name: String,
pub program_id: Pubkey,
pub process_instruction: ProcessInstructionWithContext,
}
impl std::fmt::Debug for BuiltinProgram {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Builtin [name={}, id={}]", self.name, self.program_id)
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for BuiltinProgram {
fn example() -> Self {
declare_process_instruction!(empty_mock_process_instruction, 1, |_invoke_context| {
// Do nothing
Ok(())
});
Self {
name: String::default(),
program_id: Pubkey::default(),
process_instruction: empty_mock_process_instruction,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct BuiltinPrograms {
pub vec: Vec<BuiltinProgram>,
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for BuiltinPrograms {
fn example() -> Self {
Self::default()
}
}
impl BuiltinPrograms {
pub fn new_mock(
program_id: Pubkey,
process_instruction: ProcessInstructionWithContext,
) -> Self {
Self {
vec: vec![BuiltinProgram {
name: "mock instruction processor".to_string(),
program_id,
process_instruction,
}],
}
}
}

View File

@ -1,6 +1,7 @@
use {
crate::{
accounts_data_meter::AccountsDataMeter,
builtin_program::{BuiltinPrograms, ProcessInstructionWithContext},
compute_budget::ComputeBudget,
executor_cache::TransactionExecutorCache,
ic_logger_msg, ic_msg,
@ -14,7 +15,7 @@ use {
solana_rbpf::{
ebpf::MM_HEAP_START,
memory_region::MemoryMapping,
vm::{BuiltInFunction, Config, ContextObject, ProgramResult},
vm::{Config, ContextObject, ProgramResult},
},
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
@ -82,24 +83,6 @@ macro_rules! declare_process_instruction {
};
}
pub type ProcessInstructionWithContext = BuiltInFunction<InvokeContext<'static>>;
#[derive(Clone)]
pub struct BuiltinProgram {
pub program_id: Pubkey,
pub process_instruction: ProcessInstructionWithContext,
}
impl std::fmt::Debug for BuiltinProgram {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}: {:p}",
self.program_id, self.process_instruction as *const ProcessInstructionWithContext,
)
}
}
impl<'a> ContextObject for InvokeContext<'a> {
fn trace(&mut self, state: [u64; 12]) {
self.syscall_context
@ -169,7 +152,7 @@ pub struct InvokeContext<'a> {
pub transaction_context: &'a mut TransactionContext,
rent: Rent,
pre_accounts: Vec<PreAccount>,
builtin_programs: &'a [BuiltinProgram],
builtin_programs: &'a BuiltinPrograms,
sysvar_cache: &'a SysvarCache,
log_collector: Option<Rc<RefCell<LogCollector>>>,
compute_budget: ComputeBudget,
@ -189,7 +172,7 @@ impl<'a> InvokeContext<'a> {
pub fn new(
transaction_context: &'a mut TransactionContext,
rent: Rent,
builtin_programs: &'a [BuiltinProgram],
builtin_programs: &'a BuiltinPrograms,
sysvar_cache: &'a SysvarCache,
log_collector: Option<Rc<RefCell<LogCollector>>>,
compute_budget: ComputeBudget,
@ -731,7 +714,7 @@ impl<'a> InvokeContext<'a> {
}
};
for entry in self.builtin_programs {
for entry in self.builtin_programs.vec.iter() {
if entry.program_id == builtin_id {
let program_id =
*instruction_context.get_last_program_key(self.transaction_context)?;
@ -894,9 +877,9 @@ macro_rules! with_mock_invoke_context {
},
std::{cell::RefCell, rc::Rc, sync::Arc},
$crate::{
compute_budget::ComputeBudget, executor_cache::TransactionExecutorCache,
invoke_context::InvokeContext, log_collector::LogCollector,
sysvar_cache::SysvarCache,
builtin_program::BuiltinPrograms, compute_budget::ComputeBudget,
executor_cache::TransactionExecutorCache, invoke_context::InvokeContext,
log_collector::LogCollector, sysvar_cache::SysvarCache,
},
};
let compute_budget = ComputeBudget::default();
@ -907,6 +890,7 @@ macro_rules! with_mock_invoke_context {
compute_budget.max_instruction_trace_length,
);
$transaction_context.enable_cap_accounts_data_allocations_per_transaction();
let builtin_programs = BuiltinPrograms::default();
let mut sysvar_cache = SysvarCache::default();
sysvar_cache.fill_missing_entries(|pubkey, callback| {
for index in 0..$transaction_context.get_number_of_accounts() {
@ -928,7 +912,7 @@ macro_rules! with_mock_invoke_context {
let mut $invoke_context = InvokeContext::new(
&mut $transaction_context,
Rent::default(),
&[],
&builtin_programs,
&sysvar_cache,
Some(LogCollector::new_ref()),
compute_budget,
@ -980,11 +964,8 @@ pub fn mock_process_instruction<F: FnMut(&mut InvokeContext), G: FnMut(&mut Invo
let processor_account = AccountSharedData::new(0, 0, &native_loader::id());
transaction_accounts.push((*loader_id, processor_account));
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let builtin_programs = &[BuiltinProgram {
program_id: *loader_id,
process_instruction,
}];
invoke_context.builtin_programs = builtin_programs;
let builtin_programs = BuiltinPrograms::new_mock(*loader_id, process_instruction);
invoke_context.builtin_programs = &builtin_programs;
pre_adjustments(&mut invoke_context);
let result = invoke_context.process_instruction(
instruction_data,
@ -1233,11 +1214,8 @@ mod tests {
})
.collect::<Vec<_>>();
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let builtin_programs = &[BuiltinProgram {
program_id: callee_program_id,
process_instruction,
}];
invoke_context.builtin_programs = builtin_programs;
let builtin_programs = BuiltinPrograms::new_mock(callee_program_id, process_instruction);
invoke_context.builtin_programs = &builtin_programs;
// Account modification tests
let cases = vec![
@ -1378,11 +1356,8 @@ mod tests {
},
];
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let builtin_programs = &[BuiltinProgram {
program_id: program_key,
process_instruction,
}];
invoke_context.builtin_programs = builtin_programs;
let builtin_programs = BuiltinPrograms::new_mock(program_key, process_instruction);
invoke_context.builtin_programs = &builtin_programs;
// Test: Resize the account to *the same size*, so not consuming any additional size; this must succeed
{

View File

@ -11,6 +11,7 @@ extern crate solana_metrics;
pub use solana_rbpf;
pub mod accounts_data_meter;
pub mod builtin_program;
pub mod compute_budget;
pub mod executor_cache;
pub mod invoke_context;

View File

@ -11,14 +11,15 @@ use {
solana_banks_server::banks_server::start_local_server,
solana_bpf_loader_program::serialization::serialize_parameters,
solana_program_runtime::{
compute_budget::ComputeBudget, ic_msg, invoke_context::ProcessInstructionWithContext,
stable_log, timings::ExecuteTimings,
builtin_program::{BuiltinProgram, BuiltinPrograms, ProcessInstructionWithContext},
compute_budget::ComputeBudget,
ic_msg, stable_log,
timings::ExecuteTimings,
},
solana_runtime::{
accounts_background_service::{AbsRequestSender, SnapshotRequestType},
bank::Bank,
bank_forks::BankForks,
builtins::Builtin,
commitment::BlockCommitmentCache,
epoch_accounts_hash::EpochAccountsHash,
genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo},
@ -436,7 +437,7 @@ pub fn read_file<P: AsRef<Path>>(path: P) -> Vec<u8> {
pub struct ProgramTest {
accounts: Vec<(Pubkey, AccountSharedData)>,
builtins: Vec<Builtin>,
builtin_programs: BuiltinPrograms,
compute_max_units: Option<u64>,
prefer_bpf: bool,
use_bpf_jit: bool,
@ -474,7 +475,7 @@ impl Default for ProgramTest {
Self {
accounts: vec![],
builtins: vec![],
builtin_programs: BuiltinPrograms::default(),
compute_max_units: None,
prefer_bpf,
use_bpf_jit: false,
@ -628,12 +629,6 @@ impl ProgramTest {
);
};
let add_native = |this: &mut ProgramTest, process_fn: ProcessInstructionWithContext| {
info!("\"{}\" program loaded as native code", program_name);
this.builtins
.push(Builtin::new(program_name, program_id, process_fn));
};
let warn_invalid_program_name = || {
let valid_program_names = default_shared_object_dirs()
.iter()
@ -679,7 +674,9 @@ impl ProgramTest {
// processor function as is.
//
// TODO: figure out why tests hang if a processor panics when running native code.
(false, _, Some(process)) => add_native(self, process),
(false, _, Some(process)) => {
self.add_builtin_program(program_name, program_id, process)
}
// Invalid: `test-sbf` invocation with no matching SBF shared object.
(true, None, _) => {
@ -704,8 +701,11 @@ impl ProgramTest {
process_instruction: ProcessInstructionWithContext,
) {
info!("\"{}\" builtin program", program_name);
self.builtins
.push(Builtin::new(program_name, program_id, process_instruction));
self.builtin_programs.vec.push(BuiltinProgram {
name: program_name.to_string(),
program_id,
process_instruction,
});
}
/// Deactivate a runtime feature.
@ -816,11 +816,11 @@ impl ProgramTest {
}
// User-supplied additional builtins
for builtin in self.builtins.iter() {
for builtin in self.builtin_programs.vec.iter() {
bank.add_builtin(
&builtin.name,
&builtin.id,
builtin.process_instruction_with_context,
&builtin.program_id,
builtin.process_instruction,
);
}

View File

@ -94,9 +94,9 @@ use {
solana_perf::perf_libs,
solana_program_runtime::{
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
builtin_program::{BuiltinProgram, BuiltinPrograms, ProcessInstructionWithContext},
compute_budget::{self, ComputeBudget},
executor_cache::{BankExecutorCache, TransactionExecutorCache, MAX_CACHED_EXECUTORS},
invoke_context::{BuiltinProgram, ProcessInstructionWithContext},
loaded_programs::{LoadedProgram, LoadedProgramType, LoadedPrograms, WorkingSlot},
log_collector::LogCollector,
sysvar_cache::SysvarCache,
@ -887,18 +887,6 @@ impl AbiExample for OptionalDropCallback {
}
}
#[derive(Debug, Clone, Default)]
pub struct BuiltinPrograms {
pub vec: Vec<BuiltinProgram>,
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for BuiltinPrograms {
fn example() -> Self {
Self::default()
}
}
/// Manager for the state of all accounts and programs after processing its entries.
/// AbiExample is needed even without Serialize/Deserialize; actual (de-)serialization
/// are implemented elsewhere for versioning
@ -4282,7 +4270,7 @@ impl Bank {
let mut process_message_time = Measure::start("process_message_time");
let process_result = MessageProcessor::process_message(
&self.builtin_programs.vec,
&self.builtin_programs,
tx.message(),
&loaded_transaction.program_indices,
&mut transaction_context,
@ -6631,8 +6619,8 @@ impl Bank {
for builtin in builtins.genesis_builtins {
self.add_builtin(
&builtin.name,
&builtin.id,
builtin.process_instruction_with_context,
&builtin.program_id,
builtin.process_instruction,
);
}
for precompile in get_precompiles() {
@ -7674,6 +7662,7 @@ impl Bank {
entry.process_instruction = process_instruction;
} else {
self.builtin_programs.vec.push(BuiltinProgram {
name: name.to_string(),
program_id: *program_id,
process_instruction,
});
@ -7944,8 +7933,8 @@ impl Bank {
match builtin_action {
BuiltinAction::Add(builtin) => self.add_builtin(
&builtin.name,
&builtin.id,
builtin.process_instruction_with_context,
&builtin.program_id,
builtin.process_instruction,
),
BuiltinAction::Remove(program_id) => self.remove_builtin(&program_id),
}

View File

@ -1,60 +1,12 @@
#[cfg(RUSTC_WITH_SPECIALIZATION)]
use {
solana_frozen_abi::abi_example::AbiExample, solana_program_runtime::declare_process_instruction,
};
use {
solana_program_runtime::invoke_context::ProcessInstructionWithContext,
solana_program_runtime::builtin_program::BuiltinProgram,
solana_sdk::{feature_set, pubkey::Pubkey, stake},
std::fmt,
};
#[derive(Clone)]
pub struct Builtin {
pub name: String,
pub id: Pubkey,
pub process_instruction_with_context: ProcessInstructionWithContext,
}
impl Builtin {
pub fn new(
name: &str,
id: Pubkey,
process_instruction_with_context: ProcessInstructionWithContext,
) -> Self {
Self {
name: name.to_string(),
id,
process_instruction_with_context,
}
}
}
impl fmt::Debug for Builtin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Builtin [name={}, id={}]", self.name, self.id)
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for Builtin {
fn example() -> Self {
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
// Do nothing
Ok(())
});
Self {
name: String::default(),
id: Pubkey::default(),
process_instruction_with_context: process_instruction,
}
}
}
#[derive(Clone, Debug)]
pub struct Builtins {
/// Builtin programs that are always available
pub genesis_builtins: Vec<Builtin>,
pub genesis_builtins: Vec<BuiltinProgram>,
/// Dynamic feature transitions for builtin programs
pub feature_transitions: Vec<BuiltinFeatureTransition>,
@ -63,7 +15,7 @@ pub struct Builtins {
/// Actions taken by a bank when managing the list of active builtin programs.
#[derive(Debug, Clone)]
pub enum BuiltinAction {
Add(Builtin),
Add(BuiltinProgram),
Remove(Pubkey),
}
@ -73,13 +25,13 @@ pub enum BuiltinAction {
pub enum BuiltinFeatureTransition {
/// Add a builtin program if a feature is activated.
Add {
builtin: Builtin,
builtin: BuiltinProgram,
feature_id: Pubkey,
},
/// Remove a builtin program if a feature is activated or
/// retain a previously added builtin.
RemoveOrRetain {
previously_added_builtin: Builtin,
previously_added_builtin: BuiltinProgram,
addition_feature_id: Pubkey,
removal_feature_id: Pubkey,
},
@ -107,7 +59,7 @@ impl BuiltinFeatureTransition {
removal_feature_id,
} => {
if should_apply_action_for_feature(removal_feature_id) {
Some(BuiltinAction::Remove(previously_added_builtin.id))
Some(BuiltinAction::Remove(previously_added_builtin.program_id))
} else if should_apply_action_for_feature(addition_feature_id) {
// Retaining is no different from adding a new builtin.
Some(BuiltinAction::Add(previously_added_builtin.clone()))
@ -119,29 +71,29 @@ impl BuiltinFeatureTransition {
}
}
/// Builtin programs that are always available
fn genesis_builtins() -> Vec<Builtin> {
/// Built-in programs that are always available
fn genesis_builtins() -> Vec<BuiltinProgram> {
vec![
Builtin::new(
"system_program",
solana_system_program::id(),
solana_system_program::system_processor::process_instruction,
),
Builtin::new(
"vote_program",
solana_vote_program::id(),
solana_vote_program::vote_processor::process_instruction,
),
Builtin::new(
"stake_program",
stake::program::id(),
solana_stake_program::stake_instruction::process_instruction,
),
Builtin::new(
"config_program",
solana_config_program::id(),
solana_config_program::config_processor::process_instruction,
),
BuiltinProgram {
name: "system_program".to_string(),
program_id: solana_system_program::id(),
process_instruction: solana_system_program::system_processor::process_instruction,
},
BuiltinProgram {
name: "vote_program".to_string(),
program_id: solana_vote_program::id(),
process_instruction: solana_vote_program::vote_processor::process_instruction,
},
BuiltinProgram {
name: "stake_program".to_string(),
program_id: stake::program::id(),
process_instruction: solana_stake_program::stake_instruction::process_instruction,
},
BuiltinProgram {
name: "config_program".to_string(),
program_id: solana_config_program::id(),
process_instruction: solana_config_program::config_processor::process_instruction,
},
]
}
@ -149,27 +101,28 @@ fn genesis_builtins() -> Vec<Builtin> {
fn builtin_feature_transitions() -> Vec<BuiltinFeatureTransition> {
vec![
BuiltinFeatureTransition::Add {
builtin: Builtin::new(
"compute_budget_program",
solana_sdk::compute_budget::id(),
solana_compute_budget_program::process_instruction,
),
builtin: BuiltinProgram {
name: "compute_budget_program".to_string(),
program_id: solana_sdk::compute_budget::id(),
process_instruction: solana_compute_budget_program::process_instruction,
},
feature_id: feature_set::add_compute_budget_program::id(),
},
BuiltinFeatureTransition::Add {
builtin: Builtin::new(
"address_lookup_table_program",
solana_address_lookup_table_program::id(),
solana_address_lookup_table_program::processor::process_instruction,
),
builtin: BuiltinProgram {
name: "address_lookup_table_program".to_string(),
program_id: solana_address_lookup_table_program::id(),
process_instruction:
solana_address_lookup_table_program::processor::process_instruction,
},
feature_id: feature_set::versioned_tx_message_enabled::id(),
},
BuiltinFeatureTransition::Add {
builtin: Builtin::new(
"zk_token_proof_program",
solana_zk_token_sdk::zk_token_proof_program::id(),
solana_zk_token_proof_program::process_instruction,
),
builtin: BuiltinProgram {
name: "zk_token_proof_program".to_string(),
program_id: solana_zk_token_sdk::zk_token_proof_program::id(),
process_instruction: solana_zk_token_proof_program::process_instruction,
},
feature_id: feature_set::zk_token_sdk_enabled::id(),
},
]
@ -187,9 +140,9 @@ pub fn get_pubkeys() -> Vec<Pubkey> {
let builtins = get();
let mut pubkeys = Vec::new();
pubkeys.extend(builtins.genesis_builtins.iter().map(|b| b.id));
pubkeys.extend(builtins.genesis_builtins.iter().map(|b| b.program_id));
pubkeys.extend(builtins.feature_transitions.iter().filter_map(|f| match f {
BuiltinFeatureTransition::Add { builtin, .. } => Some(builtin.id),
BuiltinFeatureTransition::Add { builtin, .. } => Some(builtin.program_id),
BuiltinFeatureTransition::RemoveOrRetain { .. } => None,
}));
pubkeys

View File

@ -2,9 +2,10 @@ use {
serde::{Deserialize, Serialize},
solana_measure::measure::Measure,
solana_program_runtime::{
builtin_program::BuiltinPrograms,
compute_budget::ComputeBudget,
executor_cache::TransactionExecutorCache,
invoke_context::{BuiltinProgram, InvokeContext},
invoke_context::InvokeContext,
log_collector::LogCollector,
sysvar_cache::SysvarCache,
timings::{ExecuteDetailsTimings, ExecuteTimings},
@ -51,7 +52,7 @@ impl MessageProcessor {
/// The accounts are committed back to the bank only if every instruction succeeds.
#[allow(clippy::too_many_arguments)]
pub fn process_message(
builtin_programs: &[BuiltinProgram],
builtin_programs: &BuiltinPrograms,
message: &SanitizedMessage,
program_indices: &[Vec<IndexOfAccount>],
transaction_context: &mut TransactionContext,
@ -251,10 +252,8 @@ mod tests {
let mock_system_program_id = Pubkey::new_unique();
let rent_collector = RentCollector::default();
let builtin_programs = &[BuiltinProgram {
program_id: mock_system_program_id,
process_instruction,
}];
let builtin_programs =
BuiltinPrograms::new_mock(mock_system_program_id, process_instruction);
let accounts = vec![
(
@ -303,7 +302,7 @@ mod tests {
)));
let sysvar_cache = SysvarCache::default();
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -353,7 +352,7 @@ mod tests {
]),
)));
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -393,7 +392,7 @@ mod tests {
]),
)));
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -478,10 +477,7 @@ mod tests {
let mock_program_id = Pubkey::from([2u8; 32]);
let rent_collector = RentCollector::default();
let builtin_programs = &[BuiltinProgram {
program_id: mock_program_id,
process_instruction,
}];
let builtin_programs = BuiltinPrograms::new_mock(mock_program_id, process_instruction);
let accounts = vec![
(
@ -527,7 +523,7 @@ mod tests {
)));
let sysvar_cache = SysvarCache::default();
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -561,7 +557,7 @@ mod tests {
Some(transaction_context.get_key_of_account_at_index(0).unwrap()),
)));
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -592,7 +588,7 @@ mod tests {
Some(transaction_context.get_key_of_account_at_index(0).unwrap()),
)));
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -641,10 +637,7 @@ mod tests {
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
Err(InstructionError::Custom(0xbabb1e))
});
let builtin_programs = &[BuiltinProgram {
program_id: mock_program_id,
process_instruction,
}];
let builtin_programs = BuiltinPrograms::new_mock(mock_program_id, process_instruction);
let mut secp256k1_account = AccountSharedData::new(1, 0, &native_loader::id());
secp256k1_account.set_executable(true);
@ -669,7 +662,7 @@ mod tests {
)));
let sysvar_cache = SysvarCache::default();
let result = MessageProcessor::process_message(
builtin_programs,
&builtin_programs,
&message,
&[vec![0], vec![1]],
&mut transaction_context,