Resumo
A simulação de transações é crítica para a segurança da carteira. Os usuários precisam visualizar o que uma transação fará antes de assinar. Mas as atuais abordagens de simulação exigem confiança cega nos fornecedores de RPC para dados de estado, criando um perigoso ponto único de falha. Exploramos uma abordagem de simulação de confiança minimizada usando provas Merkle Patricia Trie e consenso de vários nós para verificar criptograficamente o pré-estado antes da execução, eliminando a necessidade de confiar em qualquer provedor RPC único, permanecendo prático para carteiras de produção.
O problema da confiança na simulação
Os usuários não podem ler dados brutos de transações. Uma transação é composta por calldata codificados: bytes que especificam chamadas de contrato, parâmetros e alterações de estado. Os usuários não têm como verificar o que uma transação realmente faz apenas olhando para ela. Este é o problema de assinatura cega: os usuários devem confiar em sua carteira para saber o que estão assinando.
A simulação de transações surgiu como a solução. Antes de os usuários assinarem, as carteiras simulam a transação para mostrar quais tokens serão transferidos, quais aprovações serão concedidas, quais mudanças no estado do contrato ocorrerão e se a transação será revertida. Isso evita que os usuários assinem transações maliciosas que drenam fundos, concedem aprovações perigosas ou se comportam de forma inesperada. A simulação transforma a assinatura cega em assinatura informada, onde os usuários veem resultados decodificados e legíveis antes de assinar.
Mas há uma questão fundamental de confiança: A maioria das carteiras não executa simulações. Em vez disso, eles contam com APIs de simulação de terceiros: serviços de caixa preta onde você envia uma transação e recebe resultados decodificados mostrando o que acontecerá. Mas aqui está o que realmente acontece nos bastidores: esses serviços normalmente chamam APIs de rastreamento (como debug_traceTransaction ou trace_call) de provedores de RPC terceirizados (Infura, Alchemy, etc.), receba rastreamentos de execução desses provedores, decodifique e formate os resultados e, em seguida, devolva-os à carteira.
Isso cria múltiplas camadas de confiança: você confia na lógica de decodificação e exibição do serviço de simulação, que confia nos dados de estado do provedor RPC, que confia na execução de EVM e na geração de rastreamento. O serviço de simulação normalmente não executa seus próprios nós ou execução – ele agrega e formata dados de infraestrutura de terceiros. Não há como verificar nada disso. Mesmo as carteiras que executam simulações localmente ainda enfrentam o problema central: elas buscam rastreamentos de estado e execução de provedores de RPC e confiam neles completamente.
A camada de infraestrutura foi centralizada em torno de alguns provedores de RPC (Infura, Alchemy, QuickNode) que atendem à maioria dos usuários. Enquanto isso, executar seu próprio nó consome muitos recursos e as carteiras móveis/navegador não conseguem executar nós completos. Essa centralização acelera à medida que as carteiras móveis dominam a adoção e os usuários priorizam a conveniência.
Um ataque concreto
Alice envia a Bob uma transação para aprovação: supostamente uma transferência de 50.000 USDC para instituições de caridade. Bob não consegue ler os bytes codificados da transação, então ele confia na simulação de sua carteira.
A carteira de Bob usa uma API de simulação comprometida. A API retorna resultados mostrando “Transferir 50.000 USDC para caridade (0x1234…)”. Bob analisa, vê sua doação para uma instituição de caridade reconhecida e assina.
Mas a simulação mentiu. Os dados de chamada da transação real drenam todo o saldo USDC de Bob para o endereço de um invasor (0xabcd…). O serviço malicioso mostrou traços de execução falsos, enquanto a transação real faz algo completamente diferente.
Bob estava assinando às cegas com etapas extras. Mesmo uma carteira de hardware não ajudaria porque só pode verificar se Bob está assinando o que foi enviado para ela, e não se a simulação representa com precisão o que a transação fará. O ataque funciona porque o serviço de simulação é uma caixa preta completa, sem forma de verificar os resultados.
Isso não é teórico. Os provedores de RPC são comprometidos por violações de infraestrutura, sequestro de DNS, ataques MitM e extensões maliciosas de navegador. Um único serviço de simulação comprometido poderia mostrar simulações falsas para milhões de usuários em centenas de carteiras.
Por que não clientes leves?
Os clientes leves são a solução baseada em princípios: verificar o estado sem baixar a cadeia completa. Mas eles enfrentam barreiras práticas significativas, incluindo requisitos de recursos proibitivos para dispositivos móveis, longos tempos de sincronização, compilação complexa de WASM para suporte de navegador e protocolos ainda em desenvolvimento ativo. Muitos L2s carecem totalmente de implementações de clientes leves maduros. Precisamos hoje de uma solução prática para carteiras de produção.
Nossa abordagem: simulação de prestação verificada
Verifique o pré-estado criptograficamente usando provas Merkle Patricia Trie e consenso de vários nós e, em seguida, execute a transação localmente com revm para gerar nossos próprios rastreamentos de execução.
O mecanismo:
-
Buscar prestação: Usar
debug_traceCallcomprestateTracerpara descobrir o estado necessário -
Estabeleça consenso: Consulte vários nós RPC para obter a raiz do estado no bloco de simulação
-
Exigir acordo unânime: Todos os nós devem concordar com a raiz do estado, caso contrário, rejeite a simulação
-
Solicitar provas: Chamar
eth_getProofpara todas as contas e armazenamento em prestações -
Verifique as provas localmente: Faça provas de MPT, verifique hashes, confirme valores
-
Execute localmente com revm: Somente se todas as provas forem validadas, execute a transação com estado verificado usando revm (implementação Rust EVM)
-
Gerar nossos próprios rastros: Produzir rastreamentos de execução, mudanças de estado e resultados de nossa própria execução EVM
Implementação Técnica
Etapa 1: descobrir o estado necessário
Usar debug_traceCall com o prestateTracer para descobrir exatamente qual estado a transação acessará. Isso retorna o pré-estado completo: todas as contas que serão tocadas, seus saldos e nonces, todos os slots de armazenamento que serão lidos e o código de quaisquer contratos executados.
Esta descoberta permite a simulação local sem um nó completo e nos informa qual estado verificar usando provas MPT.
Etapa 2: Estabelecer um consenso geral estadual
Consulte N nós RPC independentes para estabelecer consenso sobre a raiz do estado no bloco de simulação. Para cada nó de verificação, chame eth_getBlockByNumber e extrair o stateRoot. Todos os nós de verificação devem concordar com a raiz do estado. Se pelo menos um nó discordar, rejeite totalmente a simulação, pois a discordância indica que você está sendo o alvo.
Este mecanismo de consenso evita que um nó de simulação malicioso minta sobre o pré-estado. Como o pré-estado é verificado usando a raiz do estado de consenso, para mentir sobre o pré-estado ele precisa controlar todos os seus nós de verificação.
Etapa 3: solicitar e verificar provas criptográficas
Para cada conta e slot de armazenamento no prestastate, ligue eth_getProof. A resposta contém provas Merkle Patricia Trie que verificamos localmente percorrendo os nós de prova, fazendo hash de cada nó e confirmando que os valores correspondem ao que foi reivindicado. As provas da conta são verificadas em relação à raiz do estado global; as provas de armazenamento são verificadas em relação ao storageHash da conta. Para contas que ainda não existem, verificamos se elas realmente não estão implantadas e confiamos na execução local do REVM para seu estado.
Etapa 4: execute localmente com Revm
Somente depois que todas as provas forem validadas com sucesso, execute a transação localmente usando revm (implementação Rust EVM) com o pré-estado verificado. Isto é fundamental: não apenas verificamos o estado e confiamos na execução de outra pessoa. Executamos nosso próprio EVM para gerar rastreamentos de execução, alterações de estado e logs de eventos.
A execução acontece inteiramente no dispositivo do usuário com entradas verificadas. O REVM é fixado em uma versão conhecida com atualizações auditáveis, diferentemente das APIs de provedores de nós opacos, nas quais você não tem visibilidade sobre qual código está em execução ou quando ele é alterado.
Se alguma prova não for verificada, rejeite toda a simulação e tente novamente com nós diferentes ou alerte o usuário sobre um ataque potencial.
Propriedades de segurança
O modelo de ameaça pressupõe provedores de RPC e serviços de simulação adversários. A abordagem mantém a descentralização ao exigir um acordo unânime sobre a raiz estatal em todos os nós de verificação. Se mesmo um único nó discordar, o sistema detecta a manipulação e rejeita a simulação. As provas são determinísticas e transparentes; qualquer um pode verificar a verificação.
Compensações e limitações
A abordagem requer acesso a vários fornecedores independentes de RPC para o mecanismo de consenso. Depende do suporte RPC para eth_getProof (amplamente suportado) e debug_traceCall com prestateTracer (menos comum). O requisito de acordo unânime significa que mesmo que um nó de verificação esteja inativo ou retorne uma raiz de estado diferente, a simulação será rejeitada. Isso troca disponibilidade por segurança.
A verificação de integridade do Prestate ainda não foi implementada. A implementação atual verifica se o pré-estado fornecido é preciso, mas não verifica se está completo. Um nó malicioso pode fornecer provas precisas de estado incompleto (ocultando slots de armazenamento críticos). A defesa planejada é verificar após a execução se nenhum armazenamento foi acessado além do pré-estado verificado, mas este é um trabalho futuro.
Os fluxos condicionais em contratos inteligentes podem enganar a simulação. Um contrato malicioso pode se comportar de maneira diferente com base em condições como block.timestamp, msg.senderou outras variáveis de estado, fazendo com que a simulação mostre um comportamento benigno enquanto a execução onchain real faz algo malicioso. Este é um problema geral com todas as abordagens de simulação de transações, não específico da verificação de estado. Estamos interessados em feedback sobre possíveis mitigações para esse vetor de ataque.
A abordagem funciona para cadeias EVM que suportam eth_getProof: Rede principal Ethereum e a maioria dos L2s. Cadeias com diferentes representações de estado precisariam de uma lógica de verificação adaptada.
Discussão
Isso demonstra que a simulação de transações com confiança minimizada é prática hoje, sem esperar pela maturidade leve do cliente. Não é uma solução perfeita, mas elimina o ponto único de confiança que existe em quase todas as carteiras hoje.
Na abordagem geral: Há questões fundamentais que estamos perdendo? O mecanismo depende eth_getProof retornando provas válidas de Merkle Patricia Trie e consenso sobre raízes estaduais em nós independentes. Gostaríamos de receber feedback crítico sobre se esta base é sólida para simulação de carteira de produção ou se existem vetores de ataque que não consideramos.
Sobre design de consenso: Atualmente exigimos acordo unânime entre todos os nós de verificação para a raiz do estado. Se pelo menos um nó discordar, a simulação é rejeitada. O raciocínio é que, em teoria, não há razão legítima para os nós de verificação discordarem sobre a raiz do estado, a menos que você esteja sendo o alvo. Isso prioriza a segurança em vez da disponibilidade. Esta é a compensação certa para carteiras de produção ou deveria haver configurabilidade para usuários que preferem diferentes equilíbrios de segurança/disponibilidade?
Comparação de clientes leves: Como isso se compara à execução de um cliente full light para simulação? Vemos isso como uma solução pragmática que funciona hoje em todas as plataformas (móvel, navegador, desktop). Os clientes Light oferecem garantias mais fortes ao seguirem diretamente a camada de consenso, mas enfrentam barreiras de adoção. Existem propriedades de segurança específicas que estamos sacrificando que tornam essa abordagem inadequada para simulação de carteira?
Aguardamos seu feedback.
Fontesethresear



