笔者想要编译solidity代码,需要solc编译器,为了方便solc编译器的管理,下载solc-select(solc编译器的管理包,可以实现安装不同版本的solc编译器以及其版本切换)

环境:Ubuntu 22.04、Python 3.10、solc-select 1.0.4、slither

问题:solc-select install 报 HTTP 403 Forbidden 问题排查与解决

1.下载solc-select

pip install solc-select

2.查看安装是否成功,默认安装的最新版本1.0.4

pip show solc-select
得到结果:
wxy@wxy-mac:~/contract$ pip show solc-select
Name: solc-select
Version: 1.0.4
Summary: Manage multiple Solidity compiler versions.
Home-page: https://github.com/crytic/solc-select
Author: Trail of Bits
Author-email: 
License: AGPL-3.0
Location: /home/wxy/.local/lib/python3.10/site-packages
Requires: packaging, pycryptodome
Required-by: crytic-compile

3.查看solc-select可安装的solc版本

solc-select install

这里遇到问题:

Available versions to install:

Traceback (most recent call last):
  ...
  File ".../solc_select.py", line 249, in get_available_versions
    list_json = urllib.request.urlopen(list_url).read()

urllib.error.HTTPError: HTTP Error 403: Forbidden

3.1初步分析:从异常栈可以看出

solc-select install
    ↓
get_installable_versions()
    ↓
get_available_versions()
    ↓
urllib.request.urlopen(list_url)
    ↓
HTTP 403

说明:

  • DNS解析成功
  • HTTPS连接成功
  • 请求已经到达服务器

但是服务器拒绝了请求。

因此:

不是网络问题
不是DNS问题
不是SSL问题
不是URL不存在

而是:

服务器主动返回了403 Forbidden

3.2验证网络是否正常

首先直接访问 Solidity 官方 CDN:

curl -I https://binaries.soliditylang.org/linux-amd64/list.json

结果:

HTTP/1.1 200 OK

说明:

网络正常
CDN正常
Cloudflare正常

问题不在网络层。

3.3查看 solc-select 源码

查看:

grep -n "urlopen" solc_select.py

发现:

list_json = urllib.request.urlopen(list_url).read()

在多个函数中被直接调用:

get_available_versions()
get_latest_release()
get_soliditylang_checksums()

3.4验证 urllib 是否被拦截

进入 Python:

import urllib.request

url = "https://binaries.soliditylang.org/linux-amd64/list.json"

print(
    urllib.request.urlopen(url).status
)

结果:

HTTP Error 403: Forbidden

说明:

curl 可以访问
urllib 不可以访问

问题已经缩小到:

Python urllib 请求被服务器拒绝

3.5进一步验证 User-Agent

测试:进入python

import urllib.request

url = "https://binaries.soliditylang.org/linux-amd64/list.json"

req = urllib.request.Request(
    url,
    headers={"User-Agent":"Mozilla/5.0"}
)

print(
    urllib.request.urlopen(req).status
)

结果:

200

成功访问。

至此问题完全定位:

Cloudflare 拒绝了 Python 默认 User-Agent

默认 urllib 请求头类似:

Python-urllib/3.10

而浏览器 User-Agent 可以正常通过。

3.6根因分析

solc-select 1.0.4 的实现方式:

urllib.request.urlopen(list_url)

没有设置 User-Agent。

在当前 Solidity CDN 前置的 Cloudflare 策略下:

curl                -> 允许
浏览器              -> 允许
Python urllib默认UA -> 403

因此:

solc-select install

无法获取:

https://binaries.soliditylang.org/linux-amd64/list.json

最终抛出:

HTTP Error 403: Forbidden

3.7解决方案

在/home/xxx/slither_env/lib/python3.10/site-packages/solc_select/solc_select.py新增一个统一请求函数:在solc_select.py开头加

import urllib.request
def urlopen_with_ua(url):
    req = urllib.request.Request(
        url,
        headers={
            "User-Agent":"Mozilla/5.0"
        }
    )
    return urllib.request.urlopen(req)

然后替换:

urllib.request.urlopen(list_url)

为:

urlopen_with_ua(list_url)

同时修改下载:

print(f"Installing solc '{version}'...")
urllib.request.urlretrieve(
    url,
    artifact_file_dir.joinpath(f"solc-{version}")
)

为

print(f"Installing solc '{version}'...")

with urlopen_with_ua(url) as response:
    with open(
        artifact_file_dir.joinpath(f"solc-{version}"),
        "wb"
    ) as f:
        f.write(response.read())

3.8修复后验证

使用solc-select install,没有问题,结果如下:

安装需要的solc版本,如0.4.8:solc-select install 0.4.8

成功!!

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐