Modelo de custo de CPI e sincronização de dados

Resumo

Cada CPI custa ~1.000 CUs base mais custos de serialização. Os dados da conta são sincronizados antes e depois da execução do chamado. A assinatura de PDA usa o ID do programa chamador. Os dados de retorno são limitados a 1.024 bytes.

Modelo de custo de CPI

Os custos de CPI são retirados do mesmo orçamento computacional da transação (medidor partilhado). A fórmula de custo completa para cada chamada invoke / invoke_signed:

total_cpi_cost = invocation_cost
+ instruction_data_cost
+ account_meta_cost (SIMD-0339 only)
+ account_info_cost (SIMD-0339 only)
+ per_account_data_cost (for each non-executable account)
+ callee_execution_cost

Discriminação de custos

Componente de custoFórmulaFonte
Invocação (fixo)invoke_units = 1.000 CUs (946 com SIMD-0339)Cobrado na entrada de CPI
Serialização de instruction datainstruction_data_len / cpi_bytes_per_unitcpi_bytes_per_unit = 250. Cobrado em translate_instruction.
Serialização de metadados de conta (SIMD-0339)(num_account_metas * 34) / cpi_bytes_per_unitCada AccountMeta tem 34 bytes (32 pubkey + 1 is_signer + 1 is_writable). Cobrado em translate_instruction.
Tradução de informações de conta (SIMD-0339)(num_account_infos * 80) / cpi_bytes_per_unitACCOUNT_INFO_BYTE_SIZE = 80 bytes (32 key + 32 owner + 8 lamports + 8 data_len). Cobrado em translate_account_infos.
Dados por contaaccount_data_len / cpi_bytes_per_unitCobrado por conta em CallerAccount::from_account_info e para contas executáveis.
Execução do chamadoQuaisquer CUs que o programa chamado consumirDeduzido do medidor partilhado durante a execução do chamado.

Exemplo de cálculo de custo

Uma CPI com 100 bytes de instruction data, 5 metadados de conta, 5 informações de conta (cada uma com 1.000 bytes de dados), SIMD-0339 ativo:

invocation_cost = 946
instruction_data_cost = 100 / 250 = 0 (integer division)
account_meta_cost = (5 * 34) / 250 = 0
account_info_cost = (5 * 80) / 250 = 1
per_account_data_cost = 5 * (1000 / 250) = 20
total (before callee) = 967 CUs

Sincronização de dados da conta

O estado da conta é sincronizado entre o chamador e o chamado em dois pontos durante uma CPI. Isso garante que ambos os lados vejam uma visão consistente dos dados da conta.

Sincronização pré-CPI (chamador para chamado)

Antes da execução do chamado, update_callee_account copia as modificações em andamento do chamador para a visão da conta do chamado:

CampoDireçãoQuando
LamportsChamador -> ChamadoSe o valor difere da visão atual do chamado
Tamanho dos dadosChamador -> ChamadoSe o chamador redimensionou a conta. Não deve exceder original_data_len + MAX_PERMITTED_DATA_INCREASE (10 KiB).
Conteúdo dos dadosChamador -> ChamadoSe os dados da conta são modificáveis (can_data_be_changed passa)
ProprietárioChamador -> ChamadoDefinido por último, para que alterações de dados/lamports sejam permitidas sob o proprietário antigo

Sincronização pós-CPI (chamado para chamador)

Após o retorno do chamado, update_caller_account copia as modificações do chamado de volta para a visão do chamador. Isso só é executado para contas marcadas como graváveis:

CampoDireçãoQuando
LamportsChamado -> ChamadorSempre copiado de volta
ProprietárioChamado -> ChamadorSempre copiado de volta
Tamanho dos dadosChamado -> ChamadorSe alterado. O ponteiro da fatia de dados da VM e o campo de comprimento serializado são atualizados. Se a conta foi reduzida, a memória liberada é zerada. Se o novo comprimento exceder original_data_len + MAX_PERMITTED_DATA_INCREASE, retorna InvalidRealloc.
Conteúdo dos dadosChamado -> ChamadorCopiado do buffer de dados do chamado para a região de dados serializados do chamador

Limites de realloc

Os dados da conta podem ser redimensionados durante CPI até MAX_PERMITTED_DATA_INCREASE = 10.240 bytes (10 KiB) além do comprimento dos dados da conta no início da instrução de nível superior atual. Este limite é aplicado tanto em update_callee_account (pré-CPI) quanto em update_caller_account (pós-CPI). Excedê-lo retorna InvalidRealloc.

Assinatura PDA

Quando invoke_signed é chamado, o runtime deriva endereços PDA a partir das seeds fornecidas e do ID do programa do chamador. Isto acontece em translate_signers_rust:

  1. O array de seeds de assinante é validado: no máximo MAX_SIGNERS (16) conjuntos de seeds de assinante.
  2. Cada conjunto de seeds é validado: no máximo MAX_SEEDS (16) seeds por conjunto, cada seed com no máximo MAX_SEED_LEN (32) bytes.
  3. Pubkey::create_program_address é chamado com as seeds e o ID do programa do chamador (não o do chamado).
  4. Se as seeds não produzirem um PDA válido (ou seja, o ponto resultante está na curva ed25519), o CPI falha com BadSeeds.
  5. As pubkeys PDA derivadas são coletadas e passadas para prepare_next_instruction como assinantes válidos. Durante a verificação de privilégios, se uma conta do chamado estiver marcada como assinante e sua pubkey corresponder a um desses PDAs derivados, a verificação de assinante passa.

O PDA é derivado usando o ID do programa do chamador, não o do chamado. Isto significa que apenas o programa que possui o PDA (aquele cujo ID foi usado para derivá-lo) pode assinar em seu nome. Um programa não pode assinar por PDAs derivados de outros programas.

Dados de retorno

Os programas podem passar dados de volta aos chamadores usando o mecanismo de dados de retorno. Isto usa duas syscalls:

  • sol_set_return_data: Define até MAX_RETURN_DATA (1.024) bytes de dados de retorno para a instrução atual. O custo é data_len / cpi_bytes_per_unit + syscall_base_cost CUs.
  • sol_get_return_data: Lê os dados de retorno definidos pela instrução executada mais recentemente. Retorna os dados juntamente com o ID do programa que os definiu. O custo é (data_len + 32) / cpi_bytes_per_unit + syscall_base_cost CUs (32 bytes para o ID do programa).

Os dados de retorno são armazenados por transação e são substituídos por cada instrução que chama sol_set_return_data. No início de cada invocação de programa, o runtime redefine os dados de retorno para vazio. Após um CPI retornar, o chamador pode ler quaisquer dados de retorno que o chamado (ou qualquer programa que o chamado tenha chamado) definiu por último.

Os dados de retorno são limitados a 1.024 bytes. Apenas o último programa a chamar sol_set_return_data na cadeia de chamadas determina o que o chamador vê. Se um chamado fizer CPIs adicionais que definam dados de retorno, os próprios dados de retorno do chamado são substituídos.

Is this page helpful?

Índice

Editar Página
© 2026 Fundação Solana. Todos os direitos reservados.