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

Gerenciado por

© 2026 Fundação Solana.
Todos os direitos reservados.
Conecte-se
  • Blog