Как я могу проверить, что контракт в блокчейне соответствует исходному коду?

Учитывая исходный код (Solidity) смарт-контракта, есть ли способ детерминистически скомпилировать код и сравнить его с кодом в блокчейне? Я хочу убедиться, что контракт делает то, что заявлено в исходном коде, и что автор не вмешался в него.

Ответы (7)

Насколько мне известно, лучший способ сделать это на данный момент — снова скомпилировать исходный код с той же версией компилятора, которую использовал автор (так что это необходимо раскрыть) и сравнить байт-код.

Таким образом, вы должны проверить совпадение скомпилированного байт-кода с данными создания контракта tx .

Не на 100%, все еще проблематично github.com/trufflesuite/truffle-compile/issues/77
Большое спасибо! Контракт был построен на версии 5.17.0, но я выбрал версию 5.0.0 для проверки кода контракта, поэтому он выдавал ошибки. Наконец, я меняю версию на ту же, что и у встроенного компилятора v5.17.0.

Чтобы добавить к ответу @thomas-bertani, сегодня etherchain.org выпустил инструмент проверки контрактов Ethereum .

Вот текст со страницы:

Проверка исходного кода обеспечивает прозрачность для пользователей, взаимодействующих со смарт-контрактами. Загрузив исходный код, Etherscan сопоставит скомпилированный код с кодом в блокчейне. Как и контракты, «умный контракт» должен предоставлять конечным пользователям больше информации о том, для чего они «цифровой подписью», и давать пользователям возможность проверять код, чтобы независимо убедиться, что он действительно делает то, что должен делать.

Ссылка не работает. Изменилось ли оно?
Ссылка не работает, не работает.
Новый URL-адрес: etherscan.io/verifyContract.
Я отредактировал ответ, чтобы обновить ссылку и текст.

В настоящее время рабочий процесс довольно раздражает. Вам нужно скомпилировать контракт с той же версией компилятора и теми же настройками (обратите внимание на флаг «optimization=true» ).

Теперь обратите внимание, что полученный байт-код НЕ совпадает с байт-кодом, хранящимся в адресе. Причина этого в том, что скомпилированный контракт содержит часть инициализации, которая запускается только один раз, когда контракт отправляется в цепочку. Таким образом, байт-код, хранящийся в блокчейне, представляет собой код без части инициализации.

Для проверки кода у вас есть два варианта:

  1. Отправьте скомпилированный код в (виртуальную) цепочку блоков, а затем проверьте полученный код с помощью команды getCode .
  2. Сравните скомпилированный код с полезной нагрузкой транзакции, создавшей контракт.

Etherchain помогает сделать этот процесс.

В принципе, для идентификации контакта могут применяться методы сопоставления с образцом, даже если используется не совсем тот же компилятор. Проект, который делает это и в целом связывает контракт высокого уровня (Serpent/Solidity) с адресами Ethereum: Etherscrape .

https://etherscan.io/verifyContract — инструмент проверки. Предоставляя исходный код Solidity, он проверяет, совпадает ли сгенерированный байт-код с байт-кодом контракта (по заданному адресу). пользователь должен выбрать тот же компилятор и включить или отключить оптимизацию.

Другой подход — декомпилировать байт-код и сравнить его с исходным кодом.

Существует инструмент под названием Porosity , который делает именно это.

Я совершенно уверен, что это не может работать с какой-либо эффективностью, особенно для крупных контрактов. Имена переменных не хранятся в байт-коде, поэтому декомпилятор должен создавать свои собственные имена. Попытка увидеть, совпадает ли декомпилированный код с представленным исходным кодом, будет очень сложной, я думаю.
Контракт ABI содержит все имена переменных.
Не всегда. Я видел многих, которые этого не делают.
Принято к сведению. Это действительно сделало бы декомпиляцию непрактичной для сложных контрактов.
Я не знал, что декомпилятор использовал ABI. Это явно сильно упрощает задачу.

Рекомендовать использовать инструмент командной строки с открытым исходным кодом ConsenSys, только что выпущенный, bytecode-verifier , соответствующий пакет npm

Bytecode Verifier — это удобный инструмент командной строки для проверки локально скомпилированного байт-кода целевого контракта Solidity по сравнению с его фактическим байт-кодом, хранящимся в блокчейне Etheruem, с указанием адреса контракта.

  • целостность / правильность байт-кода : то, что на самом деле хранится в цепочке, правильно скомпилировано из конкретного контракта, что может быть полезно в случае нетривиального развертывания контракта потенциального держателя с высокой стоимостью (например, MultiSig Wallet), особенно контракт развертывается через третье партийная платформа.

  • Минимум усилий, простота в использовании : компилятор Solidity требует сверхурочной работы с небольшими и некоторыми крупными изменениями, что усложняет проверку байт-кода. (поскольку на Ethereum Stack Exchange задают повторяющиеся вопросы «байт-код не соответствует»). Bytecode Verifier был протестирован на соответствие последней версии вплоть до некоторых из самых старых развернутых контрактов.

  • Удобен для тестовой сети : большинство проектов запускаются в тестовой сети перед развертыванием контрактной системы в основной сети. Этот инструмент поддерживает Rinkeby, Kovan и Ropsten Testnet, которые представляют собой три активных, хорошо поддерживаемых тестовых сети, которые использует большинство разработчиков Ethereum.

Надеюсь, поможет!

Вот как я это делаю в сценарии web3.

Сначала скомпилируйте код.

const solc = require('solc');

//contract sources
const contractPath = "../contracts/";

const input = {
  "ContractName.sol" : fs.readFileSync(contractPath + 'contractName.sol', 'utf8'),
}

let solcOutput = await solc.compile({ sources: input }, 1);

теперь сравните байт-код

let blockCode = await web3.eth.getCode(contractAddress);
let solcCode = '0x' + (solcOutput.contracts["contractName.sol:contracName"].runtimeBytecode);}
Это не работает, вам не хватает параметров конструктора и дополнительных данных.
Как вы его тестировали? это работает для меня на всех контрактах сети kyber.
@mdv Вам нужны совпадающие параметры конструктора? Я вижу противоречивые ответы, но думаю, что нет, поскольку конструктор предназначен для помещения значений в хранилище, а не для определения существования функций или переменных состояния.