WEB3DEV

Cover image for Método de Nick — Execução sem chaves na Ethereum
Diogo Jorge
Diogo Jorge

Posted on

Método de Nick — Execução sem chaves na Ethereum

Image description

Este artigo fornecerá uma explicação detalhada sobre o “método de Nick”, um método de execução/implantação sem chave, amplamente referenciado em várias propostas de melhoria da Ethereum, mas nem sempre totalmente explicado.

Abordaremos sua origem, como funciona e os benefícios que oferece, como requisitos de confiança reduzidos e a capacidade de implantação de várias cadeias no mesmo endereço.

Índice

-Quem é Nick?
-Como funciona?
-Como uma transação é construída?
-Modificando a transação
-Executando a partir do endereço recuperado
-Casos de uso do mundo real
-Minimizando a confiança
-Implantação multicadeia no mesmo endereço
-EIP-155 e ChainId
-Casos extremos
-Pacote NPM

Quem é Nick?

O método de Nick foi nomeado após Nick Johnson, desenvolvedor líder da ENS e ex-aluno da Ethereum Foundation, devido ao seu trabalho na criação do primeiro roteiro para esta técnica.

O método foi inspirado em uma ideia proposta por Vitalik Buterin, o fundador da Ethereum, de que uma transação pode ser válida mesmo que não seja assinada por uma chave privada.

Foi isso que levou ao uso do termo "Keyless" (Sem chave), onde nenhuma chave privada foi associada à transação para ser válida.

Como funciona ?

Antes de começar explicando como funciona, é essencial saber de uma forma de alto nível, como é construída uma Transação Ethereum.

Como uma transação é construída?

O código abaixo mostra uma simples Tx (transaction) Ethereum do tipo 0 (Legacy)

{
 nonce: "0x00",
 gasPrice: "0x09184e72a000",
 gasLimit: "0x27100",
 para: "0x00000000000000000000000000000000000000000",
 valor: "0x01",
 dados: "0x7f746573743200000000000000000000000000000000000000000000000000000000600057,
}
Enter fullscreen mode Exit fullscreen mode

Os campos JSON indicam o endereço com o qual está interagindo, a quantidade de valor, os dados, o gasPrice e o gasLimit.

Após assinar a Tx com chave privada, teremos mais 3 campos relacionados à assinatura da transação (v, r, s):

{
 nonce: "0x00",
 gasPrice: "0x09184e72a000",
 gasLimit: "0x27100",
 para: "0x00000000000000000000000000000000000000000",
 valor: "0x01",
 dados: "0x7f746573743200000000000000000000000000000000000000000000000000000000600057",
 v: "0x26",
 r: "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
 s: "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663,
}
Enter fullscreen mode Exit fullscreen mode

Ao assinar, qualquer alteração em um dos campos principais da transação, como nonce, gasPrice, gasLimit, to, value e data resultará em um valor de assinatura diferente.

Como você pode ver, não há o campo remetente (from) na transação, então como a rede saberia quem está executando a transação? De quem serão deduzidos as GasFees e o valor enviado?

A rede usará a função ecrecover que recebe uma mensagem e uma assinatura como parâmetros e recupera a chave pública => endereço do signatário dela.

Nesse contexto, a transação principal atua como a mensagem, com v, r e s servindo como a assinatura correspondente.

// Pseudo-código :)

// Ao assinar

const addressA = '0x067024faa81ACBF984EEA0E4E75Fcc3F44558AfD';
const addressAPrvtKey = 'b37ff986840fc14c956d74a7a3375488cce495d7fe36cfa5e8201df1f1a03aaf';

const {v,r,s} = sign(Transaction, addressAPrvtKey);

> v: 0x25
> r: 0x79855f28bdc327adbcbf85d32cb76b9aeef67dc5b9c4dafbd0a94ad3757ec501
> s: 0x3a51556f88edc2e218c5b6c540662bf289a09f16e3a0f505fcfe435dfb490a22

// Ao recuperar

const addressRecovered = ecrecover(Transaction, v, r, s);

> addressRecovered: 0x067024faa81ACBF984EEA0E4E75Fcc3F44558AfD
Enter fullscreen mode Exit fullscreen mode

Conforme mostrado no código acima, o endereço A está assinando a transação. Quando a transação for passada para a rede, ela utilizará a função “ecrecover” na transação e os parâmetros de assinatura associados para identificar o endereço A como o remetente da transação, responsável pelo pagamento das taxas de gás, etc.

Não importa quem encaminha a transação para a rede, pois como dito anteriormente, o endereço que executa a transação é o recuperado da transação e a assinatura não necessariamente da pessoa que está encaminhando (transmitindo) a transação para a rede.

Modificando a transação

Como o endereço que deu origem à transação é recuperado da própria Transação e dos campos de assinatura, o que acontece se mudarmos um dos parâmetros da assinatura?

Acontece que “ecrecover” funcionará bem com ~a maioria~ dos valores gerados aleatoriamente v, r, s e retornará um endereço Ethereum válido correspondente à mensagem e à assinatura.

// Pseudo-código :)

Se v, r, s fossem alterados para:

> v: 0x25
> r: 0x1212121212121212121212121212121212121212121212121212121212121212 // Gerado por humanos e aleatório

> s: 0x0000000000000000000000000000000001000000000000000000000000000000 // Gerado por humanos e aleatório

// Ao recuperar

const addressRecovered = ecrecover(Transaction, v, r, s);

// Retorna um endereço ethereum aleatório

> addressRecovered: 0xe2140bdbe71cdf1d1df3a6b5d85939d1ad313722
Enter fullscreen mode Exit fullscreen mode

Normalmente, os valores v, r e s são gerados sempre que um endereço assina uma mensagem com a chave privada associada.

Embora o endereço recuperado não tenha assinado a própria Transação, a Transação (Mensagem) com esses valores de assinatura gerados aleatoriamente retornará seu endereço (endereço recuperado).

Executando a partir do endereço recuperado

Mesmo com a alteração dos valores de v, r e s para valores gerados aleatoriamente, a transação não será considerada como "inválida". Ela ainda será executada com sucesso a partir do endereço recuperado, desde que o endereço recuperado da transação e a assinatura tenha fundos suficientes para cobrir as taxas de gás.

Nesse caso, a solução seria financiar manualmente o endereço recuperado com algum ether para que a gasFees possa ser deduzida do seu saldo.

Depois de financiar o endereço recuperado e transmitir a transação para a rede, a transação será executada com sucesso a partir do endereço recuperado.

A probabilidade de ter o endereço recuperado usado por outra pessoa (controlado por uma chave privada conhecida) é extremamente baixo, o que torna seguro financiar e assumir o nonce.

Resumo

Em resumo, este método permite a execução de uma transação sem ser assinada por uma chave privada (Sem chave), gerando assim um “endereço incontrolável de uso único” apenas com a finalidade de executar uma transação a partir dele.

Casos de uso do mundo real

A princípio, é difícil prever como esse método pode ser usado. Por que alguém executaria uma transação de um endereço não controlado? Por que não de seu endereço principal?

Minimizando a confiança

Conforme descrito no artigo de Nick, Como enviar Ether para 11.440 pessoas, esse método foi usado para enviar Ether para 11.440 endereços na blockchain após o DAO Hack.

Dado que os fundos eram controlados por uma multi-sig, era muito difícil e consumia recursos exigir várias assinaturas sempre que precisavam enviar os fundos da multi-sig para um endereço. Isso pode levar uma eternidade e consumirá muito gás.

Também, enviar os fundos para um endereço controlado e confiar neste endereço para enviar o ether para todos os outros 11.440 não era uma opção.

Eles vão passar uma semana assinando meticulosamente 11.440 transações individuais? Eles vão enviar o valor total para uma conta controlada por um único indivíduo para que eles possam fazer os pagamentos?

É possível fazer todas as transferências sem precisar confiar, de uma forma que exija apenas uma única transferência pelos curadores— Nick Johnson

Em suma, a solução foi criar um contrato MultiSend que envia uma matriz de valores (ethers) para uma matriz de destinatários:

  • Para atingir 11.140 endereços, o total de tx necessárias é de 104 tx diferentes. \ Gerar 104 transações que interagem com MultiSend e enviam Ether para aproximadamente 110 endereços cada (devido ao limite de gás).
  • Bagunçar a assinatura das txs geradas.
  • Recuperar com “ecrecover” 104 endereços não controlados.
  • Gerar uma tx que interaja com o MultiSend novamente para enviar ether aos 104 endereços.
  • Modificar a assinatura e recuperar um endereço não controlado.
  • Enviar todos os fundos necessários da multi-sig para o último endereço não controlado recuperado.
  • Transmitir a transação que financia os 104 endereços do último endereço não controlado recuperado para a rede.
  • Transmitir as transações que financiam 110 endereços individuais dos 104 endereços para a rede.

Image description

Como enviar Ether para 11.440 pessoas — Nick Johnson

.. iniciar todo o processo que resultará no envio de ether para todos na lista - tudo com apenas uma única assinatura necessária e sem precisar confiar os fundos a um indivíduo.

Implantação multicadeia no mesmo endereço

Um endereço de contrato é gerado com base em dois fatores: o endereço do remetente e seu nonce.

Portanto, é tecnicamente possível implantar contratos no mesmo endereço transmitindo a transação de implantação do contrato do mesmo endereço com o mesmo nonce em diferentes redes, mesmo sem usar o método de Nick. No entanto, quais benefícios o método de Nick oferece que este método não oferece?

Primeiro, o problema com esse tipo de implantação é que:

  • Requer manutenção e trabalho manual. Então alguém precisa preservar a chave privada que controla o endereço com segurança.
  • Existe uma possível probabilidade de mexer com os nonces e ter um nonce maior que o usado para implantar e perder a possibilidade de implantar o contrato no mesmo endereço.

Registros e fábricas são normalmente os tipos de contratos que precisam ser implantados no mesmo endereço em várias cadeias. Isso requer preservar a chave privada com segurança para garantir que o registro ou a fábrica tenham o mesmo endereço em diferentes cadeias que possam ser criadas no futuro.

Com a crescente popularidade de contas e carteiras de contratos inteligentes, está se tornando cada vez mais comum ver contas e carteiras implantadas no mesmo endereço em várias redes. Para tornar isso possível, um contrato CREATE2 Factory precisa ser implantado em diferentes cadeias com o mesmo endereço.

O método de Nick oferece uma solução simples para implantar contratos no mesmo endereço em várias cadeias, criando uma transação que é enviada para a rede a partir de um endereço não controlado.

As etapas seriam:

  • Gere uma tx do tipo 0 — Legado.
{
 nonce: "0x00",
 gasPrice: "0x09184e72a000",
 gasLimit: "0x27100",
 valor: "0x00",
 dados: "0x<bytecode do contrato>,
}

Enter fullscreen mode Exit fullscreen mode
  • Adicione um campo v com um valor de “0x1b” (27). (Você verá por que mais tarde 👀)
  • Adicione valores aleatórios para r, s.
{
 nonce: "0x00",
 gasPrice: "0x09184e72a000",
 gasLimit: "0x27100",
 valor: "0x00",
 data: "0x<bytecode do contrato>",
 em: "0x1b",
 r: "0x0000000001000000000000000000000000100000000000000000000000000100000",
 s: "0x12121212121212121212121212121212121212121212121212121212121212121212",

}

Enter fullscreen mode Exit fullscreen mode
  • Recupere o endereço do implantador usando “ecrecover”.
  • Serialize a transação para gerar a transação raw (bruta) pronta para transmissão na rede Ethereum.

Você terá a rawTx, o endereço do implantador, também poderá obter o endereço do contrato que será criado.

  • Você financia o endereço do implantador com gasPrice * gasLimit.
  • Conecte-se a diferentes redes e transmita o rawTx.
const Web3 = require("web3");
const web3 = new Web3(/** Conectar-se a diferentes redes*/);

const rawTx = '0xf9074b808506400000008307a1208080b906f8600560005560c0604052601460809081527f53696d706c6520436f6e7472616374204e616d6500000000000000000000000060a05260019061004190826100f3565b5034801561004e57600080fd5b506101b2565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007e57607f821691505b60208210810361009e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100ee57600081815260208120601f850160051c810160208610156100cb5750805b601f850160051c820191505b818110156100ea578281556001016100d7565b5050505b505050565b81516001600160401b0381111561010c5761010c610054565b6101208161011a845461006a565b846100a4565b602080601f831160018114610155576000841561013d5750858301515b600019600386901b1c1916600185901b1785556100ea565b600085815260208120601f198616915b8281101561018457888601518255948401946001909101908401610165565b50858210156101a25787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610537806101c16000396000f3fe6080604052600436106100655760003560e01c8063c47f0 02711610043578063c47f0027146100ca578063f2c9ecd8146100ea578063f38fb65b1461010857600080fd5b806317d7de7c1461006a5780633fb5c1cb14610095578063568a1c69146100b7575b600080fd5b34801561007657600080fd5b5061007f61011d565b60405161008c9190610283565b60405180910390f35b3480156100a157600080fd5b506100b56100b03660046102d8565b600055565b005b6100b56100c5366004610307565b6101af565b3480156100d657600080fd5b506100b56100e5366004610307565b610205565b3480156100f657600080fd5b5060005460405190815260200161008c565b34801561011457600080fd5b506100b5610215565b60606001805461012c906103b8565b80601f0160208091040260200160405190810160405280929190818152602001828054610158906103b8565b80156101a55780601f1061017a576101008083540402835291602001916101a5565b820191906000526020600020905b81548152906001019060200180831161018857829003601f168201915b5050505050905090565b60323410156102055760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f7567682076616c75652070726f76696465640000000000000060448201526064015b60405180910390fd5b60016102118 282610441565b5050565b60405162461bcd60e51b815260206004820152603660248201527f546172676574436f6e74726163743a72657665727443616c6c3a20746869732060448201527f66756e6374696f6e20686173207265766572746564210000000000000000000060648201526084016101fc565b600060208083528351808285015260005b818110156102b057858101830151858201604001528201610294565b818111156102c2576000604083870101525b50601f01601f1916929092016040019392505050565b6000602082840312156102ea57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561031957600080fd5b813567ffffffffffffffff8082111561033157600080fd5b818401915084601f83011261034557600080fd5b813581811115610357576103576102f1565b604051601f8201601f19908116603f0116810190838211818310171561037f5761037f6102f1565b8160405282815287602084870101111561039857600080fd5b826020860160208301376000928101602001929092525095945050505050565b600181811c908216806103cc57607f821691505b6020821081036103ec57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561043c576000818 15260208120601f850160051c810160208610156104195750805b601f850160051c820191505b8181101561043857828155600101610425565b5050505b505050565b815167ffffffffffffffff81111561045b5761045b6102f1565b61046f8161046984546103b8565b846103f2565b602080601f8311600181146104a4576000841561048c5750858301515b600019600386901b1c1916600185901b178555610438565b600085815260208120601f198616915b828110156104d3578886015182559484019460019091019084016104b4565b50858210156104f15787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220e33436a76b28a7ded5996fad916166dc8b63f86b65336f728d944e1b9252427b64736f6c634300080f00331ba0b0506c61293520454796fae142b4e173251fa5d91a7d6506cc0ca0669708065da00cd51f3367e8d81c6afa79ea89521b6b8dd777d23d26535bad37bc8d83f39c70'

async function sendRawTx() {
   await web3.eth.sendSignedTransaction(rawTx)
   .on('receipt', console.log);
}

sendRawTx();
Enter fullscreen mode Exit fullscreen mode

Então, por que estamos obtendo o mesmo endereço com esse método? Principalmente porque o endereço recuperado não é controlado, significando que o nonce é atualmente 0 em todas as redes. Quando este endereço implanta um contrato, o endereço do contrato implantado depende do nonce do implantador (0, o mesmo em todas as cadeias) e do endereço do implantador (igual em todas as cadeias). Dessa forma, podemos garantir que o contrato a ser criado será implantado no mesmo endereço em todas as cadeias.

Com este método, não há necessidade de salvaguardar uma chave privada ou de se preocupar com o nonce ser um valor específico porque será sempre zero para um endereço não controlado. A transação bruta pode ser tornada pública e qualquer pessoa que queira implantar o contrato pode simplesmente financiar o endereço do implantador com as taxas exigidas e transmitir a transação bruta para a rede.

Também é possível experimentar diferentes combinações de valores r e s. Então o endereço do contrato que será criado seria um endereço personalizado com caracteres especiais, como 0xFaC100450Af66d838250EA25a389D8Cd09062629_ começando com 0xFaC10_≈Fábrica.

EIP-155 e ChainId

O EIP-155 introduziu o chainId como uma medida para evitar ataques de repetição de transações, garantindo que as transações sejam executadas apenas na rede blockchain pretendida, semelhante a como nonces evitam que uma transação seja repetida várias vezes na mesma cadeia.

Exemplo: Bob tem 10 Ether na Ethereum e 10 LYX na LUKSO e quer enviar 3 Ethers para Alice. Se ele construir a transação sem proteção de replay (chainId), é possível para Alice retransmitir a mesma transação no LUKSO e receber 3 LYX do endereço de Bob.
Enter fullscreen mode Exit fullscreen mode

O chainId está incluído no valor v da assinatura com as seguintes fórmulas:

v = CHAIN_ID * 2 + 35 || v = CHAIN_ID * 2 + 36

Isso é problemático para a aplicação de casos de uso específicos para o método do nick (implantação multi-chain no mesmo endereço), onde a transação precisa ser transmitida em várias cadeias sem nenhuma modificação, incluindo o valor v. Se o valor v for alterado, ele irá alterar a assinatura e, posteriormente, o endereço do implantador recuperado da transação e da assinatura, levando a diferentes endereços para o contrato em cada cadeia, anulando assim o propósito de implantar no mesmo endereço em diferentes cadeias.

Para resolver este problema e não ter um valor v relacionado a uma cadeia específica e permitir transações multi-cadeia sem o efeito do chainId, as transações podem ser executadas sem incluir o chainId e com um valor v de 27 (0x1b em hex). Esta valor v de 27 é o valor usado para transações anteriores à implementação do EIP-155.

Casos extremos

Ao usar o método de Nick com a finalidade de Implantação multicadeia no mesmo endereço, é importante ter em mente que a transação bruta gerada não pode ser alterada posteriormente. Isso ocorre porque quaisquer alterações feitas na transação afetarão o contrato resultante e o endereço do implantador.

Portanto, é crucial considerar os preços futuros de gás ao especificar o valor gasPrice na transação. Recomenda-se definir o gasPrice para um valor mais alto para suportar possíveis aumentos nos preços de gás em outras cadeias. Portanto, se você definir o gasPrice na transação como 100 gwei e, no futuro, na cadeia B, o gasPrice for 150, enviar a rawTx gerada na cadeia B causará uma reversão.

Além disso, é importante observar que alguns nós de redes podem bloquear transações que não usam a proteção EIP155, o que também pode ser uma limitação a ser considerada. Portanto, mais trabalho precisa ser feito no nível do nó para permitir esse tipo de transação com a bandeira — rpc.allow-unprotected-txs.

O termo transação desprotegida é usado para enfatizar o ponto onde se v não incluir o chainId, é possível repetir esta transação em outra rede. Para nosso caso de uso, é um comportamento intencional, mas para outros cenários pode ser prejudicial. Como o cenário de Alice e Bob acima.

Pacote NPM

Dada a limitada documentação e ferramentas disponíveis para usar o método de Nick, criei este artigo e um pacote npm que facilita a geração desses tipos de transações.

método de nick:

www.npmjs.com

Fim do artigo.

Conecte-se comigo no Twitter, GithubGenericName,** e LinkedIn.**

Enter fullscreen mode Exit fullscreen mode




Referências :

Este artigo foi escrito por Yamin Merhi e traduzido por Diogo Jorge. O artigo original pode ser encontrado aqui.

Latest comments (0)