Akawa

ETY001的博客

最近为了研究 xposed 模块开发,我拿我的一块手机跟我妈换了下,把她手里的小米4C换过来,准备用这个作为开发机使用。折腾了一整天,终于是搞定了。

准备工作

  • 解锁BL
  • 线刷包 libra_images_6.1.7_20151221.0000.11_5.1_cn_b09dac70a0.tgz
  • cofface_twrp_recovery.img
  • SuperSU-v2.79-SR2-20170103_automode_by_kane.apk
  • XposedInstaller_3.0_alpha4.apk
  • xposed-v86-sdk22-arm64-MIUI-edition-by-Solar_-20160710.zip

下载所需的资源

准备工作中列出的各种工具,都已放到百度云了,链接: https://pan.baidu.com/s/1GPumHzCjc89o-jZlKh1V3g 提取码: 25xf。其中 cofface_twrp_recovery.img小米4C刷第三方recovery工具2.8.7.3.zip 中。

解锁BL

先去这里 http://www.miui.com/unlock/index.html 申请解锁手机BL的资格。BL 就是 BootLoader,解锁后才能修改 BootLoader。

获得解锁资格后如下图所示

然后下载解锁工具。解锁工具只有 Windows 版,因此如果你用的是非 Windows 系统,请自行准备 Windows 系统 或者虚拟机。启动解锁工具,会提示登陆

登陆后,将手机关机进入Fastboot模式(同时按电源键及音量减键),手机上会出现米兔在维修机器人的图标,

然后这时用数据线连接电脑和手机,然后在电脑上点击“解锁”

大约一分钟左右即可完成解锁,然后系统会自动重启。

刷入低版本系统

目前已知 6.1.7 及以下的版本是没有任何锁的,之后的版本都对 /system 分区加锁了,因此我们需要先刷入低版本的系统。从 http://www.miui.com/shuaji-393.html 这里可以找到通用刷机工具,按照这个网页中的教程操作即可。

刷完后,手机自动重启,第一次重启会很长时间,耐心等待直到进入系统。

做完系统初始化配置后,进入到设置里,找到“关于手机”,一直点击 MIUI版本上 直到开启“开发者选项”,切回设置主菜单,“其他高级设置”里面找到“开发者选项”,打开“USB调试”。

刷入第三方Recovery

再次进入 Fastboot 模式,手机线连接手机和电脑,在电脑上解压 小米4C刷第三方recovery工具2.8.7.3.zip,如果是 windows 系统,直接执行里面的一个 bat 脚本即可完成第三方 Recovery 刷入。

由于我 Mac 下有 ADBFastboot 工具,因此我是手动刷入并引导进入 Recovery 的,如下图:

对系统进行ROOT

刷入第三方 Recovery 后,会自动重启进入 Recovery,界面如下图

这时在我的电脑里应该能找到手机的SD卡的那个盘,把 SuperSU-v2.79-SR2-20170103_automode_by_kane.apk 拷贝进去,然后回到手机,点击“安装刷机包”,找到 SuperSU-v2.79-SR2-20170103_automode_by_kane.apk,并滑动滑块开始安装,等提示完成后,即可重启手机。进入系统后就能在桌面看到新安装的“超级授权”应用了。

安装 xposed

从我的电脑里,把 XposedInstaller_3.0_alpha4.apkxposed-v86-sdk22-arm64-MIUI-edition-by-Solar_-20160710.zip 复制进手机SD卡。在手机上安装 XposedInstaller_3.0_alpha4.apk

安装后,进入 Recovery 模式,即一直按住电源键和音量增键,直至出现开机Logo的时候,松开电源键,再等几秒后,进入 Recovery,这时松开音量增键。

点击进入“安装刷机包”,选择 xposed-v86-sdk22-arm64-MIUI-edition-by-Solar_-20160710.zip,滑动进行确认后开始安装,完成后重启手机。进入系统后,打开 xposed installer 点击“框架”,就能看到如下的字样

说明我们的 xposed 已经安装好了。

为了测试下是否安装正确,我安装了一个微信机器人的模块,并且把微信机器人放到了群里测试了下,效果如下:

至此,完成!

1. A valid provisioning profile for this executable was not found.

这个问题,在网上搜了很久,有很多种可能会导致这个问题。我遇到这个问题的解决方案是:

File > Workspace Settings > Set Build system to “Legacy Build System”

2. Cannot read property ‘semver’ of null

  • find the path /platforms/android/cordova/lib/emulator.js
  • find the line avd.target = 'Android ' + level.semver + ' (API level ' + api_level + ')';
  • replace it with avd.target = 'Android ' + (level ? level.semver : '') + ' (API level ' + api_level + ')';

3. 如果 build 的时候显示 Error: spawn EACCES

这个错误说明你正在使用的程序没有执行权限,通过给 cordova 命令增加 --verbose 参数,可以看到是哪个程序执行不了,然后给这个程序加上执行权限即可

4. cordova build 之前先配置好环境变量

详细的安装配置需要去看下 cordova 的官方文档,这里只是强调下环境变量的配置。这里分享下我的环境变量配置:

1
2
3
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/jdk/Contents/Home
export ANDROID_HOME=/Users/ety001/Library/Android/sdk
export PATH=${PATH}:${JAVA_HOME}/bin:${ANDROID_HOME}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin

把上面的配置加到你的 ~/.bashrc 或者如果你要用的是 zsh 的话就是 ~/.zshrc

5. 代码更新

代码修改后,需要先 npm run build ,也就是先把 js 编译好,编译好后的静态文件会在项目根目录的 www 目录中,再执行 cordova prepare -d 就会把静态文件复制到各个 platformwww 目录里面。

6. 如何使用 Safari 和 Chrome 调试 app

  • ios的话,先在手机上找到 “设置” => “Safari浏览器” => “高级” => 把 “Web 检查器” 选中,然后用手机线把手机和电脑连接,电脑上打开 “Safari 浏览器”,”偏好设置” => “高级” => 选中 “在菜单栏显示开发菜单”,最后打开手机上的 App,这样在 Safari 的 “开发” 菜单中就能看到你的手机名的菜单了,选中其中的 app 名字就能打开 inspect 进行调试了。
  • android的话,也差不多的流程,在 Chrome 浏览器里访问 chrome://inspect,使用 debug 模式打开模拟器里要调试的 app 后,在 Chrome 浏览器里就能看到信息了,点击 inspect 就能打开针对这个 app 的调试窗口。需要注意的是,调试窗口里面的调试器需要翻墙,可以先用浏览器访问 https://chrome-devtools-frontend.appspot.com/serve_rev/@180870/devtools.html ,然后把这个网址加入到白名单里面,再回到 inspect 就可以看到调试界面了(这里我折腾了一天多,最终才发现是墙的问题😂)。

今天才发现,自从上次重装服务器后,一直忘记恢复 Steem 见证人的喂价程序了。之前一直使用的是 @furion 开发的 conductor,并且之前没有用 Dockerfile 封装成镜像,而是直接在 ubuntu:16.04 的镜像上启动容器,添加的命令。这次就直接做成镜像方便以后使用。

镜像文件

  • 你可以自己编译,Dockerfile 如下:

    1
    2
    3
    4
    5
    6
    7
    FROM alpine:3.6
    RUN apk add --no-cache python3 python3-dev gcc git musl-dev libffi-dev openssl-dev \
    && pip3 install -U git+git://github.com/Netherdrake/steem-python \
    && pip3 install -U git+https://github.com/Netherdrake/conductor \
    && apk del git gcc musl-dev libffi-dev python3-dev
    ENV UNLOCK=123456
    CMD ["conductor"]
  • 也可以直接用我封装好的,docker pull ety001/steem-conductor

使用方法

  • 添加 active_key 。

    1
    docker run -it --rm -v ~/.local/share/steem:/root ety001/steem-conductor /bin/ash

    执行后,进入容器,再执行

    1
    steempy addkey

    输入 active key 后就可以把你要操作的用户加入到本地数据库里了,数据库文件最终会存储在你宿主机的 ~/.local/share/steem/.local/share/steem 位置。添加好以后,执行 exit 退出容器环境即可,效果如下图:

  • 初始化 conductor

    1
    docker run -it --rm -v ~/.local/share/steem:/root ety001/steem-conductor conductor init

  • 测试喂价程序

    1
    docker run -it --rm -v ~/.local/share/steem:/root ety001/steem-conductor conductor feed


    可以工作

  • 启动喂价容器

    1
    docker run -itd --name steem-feed -v ~/.local/share/steem:/root --restart always ety001/steem-conductor conductor feed

完工!以后再部署喂价程序,两行命令就搞定了。

最近接手的 Stellar 钱包的外包小活需要搭建个 API 服务,考虑再三,由于 Stellar SDK 中我只会 Javascript,因此打算使用 Nodejs 去完成这个服务搭建工作。

大约5年前曾经用 Express 框架搭建过一个记事本网站,不过这次是做 API,用 Express 感觉好像太重了,于是搜索了下,发现了 hapi 这个框架。

说干就干。

首先初始化一个 Nodejs 项目

1
npm init

然后安装一下 hapi

1
npm install hapi -s

创建一个 index.js 文件,并粘贴下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
'use strict';

const Hapi = require('hapi');
const server = Hapi.server({
port: 8877,
});

server.route({
method: 'GET',
path: '/',
options: {
cors: true
},
handler: (request, h) => {
return 'Hello, ' + request.query.r;
}
});

const init = async () => {
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};

process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});

init();

启动一下,并访问 http://localhost:8877/?r=ety001,会看到 Hello, ety001

这样最简单的 API 服务就搞定了。

这里需要注意下 cors 这个配置,这个设置为 true,就可以避免跨域的报错,不过安全性需要注意,详细的配置参数请看 hapi 的文档。

除此之外,我还加入了缓存。因为每次去获取 Trade Aggregation 数据都需要大约5–6秒,这样的性能还是不行的。因此加入一个10秒的缓存,10秒内访问,将会返回缓存数据。

加入方法很简单,大致的代码结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const getTradePair = async (pointPair) => {
// the code to get trade pairs and trade aggregation
}
const traidPairCache = server.cache({
expiresIn: 10 * 1000,
segment: 'customSegment',
generateFunc: async (pair) => {
return await getTradePair(pair);
},
generateTimeout: 20000
});
server.route({
method: 'GET',
path: '/v2/api/trade_aggregations',
options: {
cors: true
},
handler: async (request, h) => {
return await traidPairCache.get('pair');
}
});

这里说明下。 traidPairCachegenerateFunc 方法就是在缓存未命中的时候,去获取新数据的方法。第一个参数相当于是缓存的标示,generateTimeout 就是 generateFunc 的执行超时时间。

hapi 使用 catbox 来实现缓存,框架默认使用 memory 作为缓存介质。

以上就是目前我所用到的功能,hapi 框架真的很轻,在处理些类似我这样的需求的时候,最省时间,尤其再配合 Docker,把服务直接做成镜像,部署起来也就一句话的事儿~~

昨天买了《浮生六记》回来看,最早听到《浮生六记》应该是在语文课上的课文里,“余忆童稚时,能张目对日,明察秋毫……”,这也是这次买这本书的原因了。

一直好奇《浮生六记》讲了什么,买回来看了序才知道原来写的是夫妻之间的家庭生活之事。于是有些怀疑写一些琐事是如何能获得200来年里各种大文学家的好评的。于是耐下心去读,看看到底是个什么。

读完前两记,起初还是有些不耐烦的,但是随着阅读反而平静了下来。文字虽不奢华,但是叙事中却不让人觉得是在记流水账。读完真的是可以感受到了一股浓浓的生活气息。

与其说这个是部散文选,不如说这其实是一部纪录片,就好像我们每天在用微信发朋友圈来记录我们的生活似的,但是《浮生六记》却不给人一种无聊的感觉,又能记录下精彩丰富的生活,实在是很让人惊叹。

继续阅读剩下的四记去了。

媳妇有个好习惯,就是每次去超市都会把要买的东西记录到纸上。

但是每次到了超市就会发现,不是忘带了那张纸,就是纸找不到放到哪里了😂。

于是我花了一天多的时间给媳妇做了个微信小程序用来实现记录要买的东西。

现在公开出来,大家也可以使用了,微信扫描文末的小程序码即可~

下面是演示视频:

Youtube

优酷

因为最初也是为了自己用,因此把需求砍到了最精简,直接输入添加要买的东西即可。
删除的话,只需要长按就可以了。
由于考虑到经常去超市购买的物品大致相同,所以增加了一个历史记录的功能,
这样下次再添加要买物品的时候,可以从历史记录里直接点按即可添加。
另外把小程序添加进“我的小程序”中,可以从微信首页下拉菜单中快速进入~

欢迎各位家庭煮妇(夫)使用,也欢迎分享给更多的家庭煮妇(夫)~

PS:据说有人还要用这个来记录其他的东西,而不仅仅是超市购物使用🤔。

起因

昨天收到了新买的二手网件路由,预刷的梅林系统,今天上午花了一个多小时把家里的主路由(米3)替换成新买的网件,在配置梅林的时候,发现梅林支持USB 3G Dongle。突然就想到了我之前买的,已经闲置了的优酷路由宝L1,里面我刷了不死 breed,可以考虑拿那个路由折腾下,正好手里有联通的大天王卡(每天3块钱无限流量)可以测试。

其实这个月初就在考虑怎么用这个天王卡,但是由于急着去青岛度假,时间匆忙,就拿了个 Android 手机当路由使。实际的体验效果是,手机终归是手机,可以带的设备数还是很有限的,同时4台手机上网就很卡了。这次正好发现梅林支持我手里的华为E1750C,于是就准备拿已经闲置的优酷路由宝L1开试(路由宝的配置对于这个价位还是很良心的)。

开始

首先要做的就是刷入系统。从网上搜索了下,路由宝的Flash容量不足以装下梅林系统,但是可以装下老毛子的 Padavan ,所以去下载了 Padavan 的固件(Google搜索 rt-n14u-gpio-1-youku1-128m_3.4.3.9-099.trx 即可找到)。因为我之前路由宝里已经刷入了 breed,所以写入新固件很轻松,只需要断电状态下,按住 Reset 键,然后送电,等待大约 2s 松开 Reset ,然后网线连接路由的 Lan 口,访问 192.168.1.1 打开 Breed,上传固件刷入即可。

写入成功后,路由会自动重启,重启后,找到新的IP地址是 192.168.123.1 访问下,在 高级设置 > USB应用程序 中,找到 USB调制解调器 ,国家选择 China,应用设置即可。

回到 网络地图,点击那个地球,就能看到连接方式变成了 USB调制解调器(总是),过一会 连接状态 就会显示 已连接

这时就能开心的使用流量上网了。由于是个3G的卡托,所以速度还是不理想,对于4G卡来说有些浪费了。以后再有机会的时候,换个4G卡托。目前来看,虽然带宽小了些,但是浏览网页看个视频还是没有问题的。

最后附一张设备图

d0.jpg

一周三次出块都失败了,也不知道服务器到底抽了什么风,于是索性就重装系统吧,顺便把 zram 也折腾下。重做系统的时候没有再选择 ubuntu16.04,而是选择了我最熟悉的 Archlinux。重做很快就结束了,登陆系统看了下,还是 Arch 精简干练,即使把所有需要的软件都装完,内存依然占用很少。

由于我还是打算在 docker 里面跑见证人,所以先安装 docker,执行 pacman -S docker 搞定。

然后安装一个轻量的管理 docker 界面 portainer

1
2
# docker volume create portainer_data
# docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock --name portainer --restart always -v portainer_data:/data portainer/portainer

安装好,直接浏览器访问 IP:9000 ,配置上用户名和密码,选择本地模式,搞定。

接下来就是做个文件的 swap

1
2
3
4
# fallocate -l 50G /swapfile
# mkswap /swapfile
# swapon /swapfile
# echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab

然后安装 zramswap,由于 zramswap 是在 AUR 里,所以先安装一下 makepkg 所要用到的编译环境

1
# pacman -S base-devel

然后新建一个普通用户,并切换到该用户的家目录,然后下载 zramswap 的安装包(在 https://aur.archlinux.org/packages/zramswap/ 这里能找到下载地址),解压后编译安装

1
2
3
4
$ wget https://aur.archlinux.org/cgit/aur.git/snapshot/zramswap.tar.gz
$ tar xvf zramswap.tar.gz
$ cd zramswap
$ makepkg -si

安装好以后,确认下 zram 模块是否加载,如果没有加载的话,加载下

1
2
# lsmod | grep zram
# modprobe zram

启动 zramswap 并设置为开机自启动,

1
2
# systemctl start zramswap
# systemctl enable zramswap

检查是否正常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram9 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram8 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram7 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram6 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram5 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram4 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram3 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram2 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram1 lz4 1006.3M 4K 69B 4K 10 [SWAP]
/dev/zram0 lz4 1006.3M 4K 69B 4K 10 [SWAP]

# swapon
NAME TYPE SIZE USED PRIO
/swapfile file 50G 0B -2
/dev/zram0 partition 1006.3M 0B 100
/dev/zram1 partition 1006.3M 0B 100
/dev/zram2 partition 1006.3M 0B 100
/dev/zram3 partition 1006.3M 0B 100
/dev/zram4 partition 1006.3M 0B 100
/dev/zram5 partition 1006.3M 0B 100
/dev/zram6 partition 1006.3M 0B 100
/dev/zram7 partition 1006.3M 0B 100
/dev/zram8 partition 1006.3M 0B 100
/dev/zram9 partition 1006.3M 0B 100

发现 zramswap 只分配了10G内存,于是去查了下他的启动文件 /usr/lib/systemd/system/zramswap.service,发现最终执行的文件是 /usr/lib/systemd/scripts/zramctrl,打印下 zramctrl 的内容,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# cat /usr/lib/systemd/scripts/zramctrl 
#!/bin/sh

start() {
exec awk -v ZRAM_SIZE=$ZRAM_SIZE -v ZRAM_PARM="$(modinfo zram | grep -E -o '(num_devices|zram_num_devices)')" '

FILENAME == "/proc/cpuinfo" && ($1 == "processor" || $1 == "Processor") {
cpucount++
next
}
FILENAME == "/proc/meminfo" && $1 == "MemTotal:" {
if (ZRAM_SIZE == "")
ZRAM_SIZE = 20
mem_total = int( (0 + $2) * 1024 * ( ZRAM_SIZE/100 ) )
next
}

....以下代码省略

发现需要设置一个 $ZRAM_SIZE 的环境变量,否则默认20%。在 /usr/lib/systemd/system/zramswap.service 中增加环境变量,

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=Zram-based swap (compressed RAM block devices)

[Service]
Type=oneshot
Environment="ZRAM_SIZE=100" # 这里是增加的环境变量
ExecStart=/usr/lib/systemd/scripts/zramctrl start
ExecStop=/usr/lib/systemd/scripts/zramctrl stop
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

重载配置文件并重启 zramswap

1
2
# systemctl daemon-reload
# systemctl restart zramswap

再次查看 zram 状态,发现已经搞定。

1
2
3
4
5
6
7
8
9
10
11
12
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram9 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram8 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram7 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram6 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram5 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram4 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram3 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram2 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram1 lz4 4.9G 4K 69B 4K 10 [SWAP]
/dev/zram0 lz4 4.9G 4K 69B 4K 10 [SWAP]

接下来就是去部署 @someguy123 的见证人镜像了,这个在之前写过教程,就不再细说了,这是链接 https://steemit.com/cn/@ety001/5xtjgz

看目前下载离线区块数据的速度应该不是网络卡导致的丢块,难道是之前配置的 shared-file-size 有问题?等部署完见证人运行起来再观察下看看还会不会频繁的丢块了吧。。。

25天前填完 LightDB 的坑以后,就开始研究 alt 留下的那个 btsbots代码 了。之前也有团队在修复这套代码 ,但是考虑到这么重要的一个设施,还是把核心技术握在自己手里比较好,要不然哪天那个团队歇菜了,又要凉。

代码断断续续的看了将近一个月了,总的感受就是崩溃。

从我开始参加工作开始,接的活都是半路加入救火的,没有人指导,只有代码,基本上是靠分析输出数据和看代码来逆向梳理需求的。但是这次修复 btsbots 的难度加大了,因为不会 *C++*,只能对着各种输出数据去逆向推理 btsbots 的代码到底想要做什么,为什么这么做。所以等这个 btsbots 修好,还是要找时间去学 C++ 了。

目前并没有什么实质的代码修改,还停留在分析代码的阶段,该文就是基于目前我对于 btsbots 的理解进行的总结。

最简单的做市需要的数据无非就是当前账户内各种币剩多少,交易对是否满足下单要求,是否有订单需要取消。btsbots 的思路其实很简单,就是基于 1.11.x 这个 operation history object 来把链上的所有操作 replay 一遍,然后得到所有用户的 balance 和所有的交易对深度数据。

btsbots 项目使用 python 来完成从链上取数据并 replay 的操作,然后存入 MongoDB,最后基于 Meteor 开发了应用界面来读取 MongoDB 中的数据并展示,用户可以设置自己的做市逻辑并在浏览器本地完成下单和取消订单的签名操作。

思路很明确,但是比较让人恶心的就是数据和需求的分析了。

目前几乎所有的时间都在分析 scripts 目录下的 python 代码的逻辑,因为这一块之前在试跑的时候,数据一直有问题。

scripts 目录下主要就是 correct-balance.py , monitor.py, statistics.py 这三个文件。

这三个文件中,monitor.pystatistics.py 这两个的目的我是最明确的了,correct-balance.py 的目的一直很糊涂。

之前忘记在哪里看到的部署文档说,第一次运行 btsbots 的时候,要先运行 correct-balance.py 进行 balanceorder 的初始化。然而看 correct-balance.py 的代码中,只是去获取 1.8.x 这一种类型的订单的数据和 2.5.xbalance 数据。在代码的头部,你需要指定 x 的上限,如下图

然后循环获取从 1.8.01.8.x 获取订单数据并插入数据库,从 2.5.02.5.x 获取 balance 数据并插入数据库。完成这两步以后,会再遍历一遍已经插入数据库的订单数据,然后去更新数据库里已经存下来的 balance,如图:

这里我就有疑问了!!!

首先是为什么第一次获取数据只获取 1.8.x 这一种类型的订单,而在下面的 add_b_from_o 函数中却有 1.4.x1.7.x 的处理逻辑?

其次就是获取到的 2.5.x 是最新的 balance 数据,而拿着订单中的 amount 在最新 balance 上加减是不是错误的?我通过自己手动从 API 获取到的 2.5.x 的数据来看,拿到的这些 balance 数据都是刨除掉未成交订单额度后的,而在 btsbots 中却又在 2.5.x 的数据的基础上去刨除订单额度貌似是不对的,但是现在我又不敢确定,因为我不确定 1.4.x, 1.7.x, 1.8.x这些数据是代表的是未成交的订单,还是所有的订单。

最后就是感觉这里处理 balance 的方法跟 monitor.py 的处理方法是冲突的,这里先按下不表。我们先去看 monitor.py 的代码。

monitor.py 中,思路很简单,就是获取 1.11.x,然后根据各种不同的 operation type 来分别处理数据,最后把数据更新进数据库。这个脚本里的疑问也是有不少。

首先是怎么触发的问题,先看下图的代码,

其中 63 行是我补上的代码。与第 63 行类似的代码其实在这个类初始化的时候已经执行过了,这个在这里可以看到。在 python-bts 库里,默认是把 clear_filter 置为 false 了,这意味着只有你发送了 get_object 的指令,服务端才会推送你刚才获取的那个 object 的变动。

在没有我补上的 63 行的代码之前,执行 monitor.py 其实是没有任何数据进数据库的,因为所有的插入数据库的操作都在 onOperation 里面,而 onOperation 的触发是在用户订阅的 1.11.xobject 有变动的时候才会触发,而程序代码从开始运行,就没有 get_object 的操作,所以服务端并不知道你想要获取哪个 object 的变动信息。加上 63 行后,把 clear_filter 置为 true,那么服务端就会推送所有的 object 的变动信息了。

其次就是语言方面的问题了,如下图

由于我写 python 的时间不久,这里并不明白加锁的意义。如果加锁是为了保证共享资源的修改顺序的话,为啥还要用协程来异步?这里我还需要再多看看这方面的文章去了解下协程中的锁的目的。

然后这里第 41 行的代码在执行的时候也有问题。在这个类的父类中,看到作者最早是把 op_id_begin 置为 1.11.0 的,在从数据库中取不到数据的时候(也就是说第一次运行的时候),但是现在注释掉了,改为了置为 None,这就导致这里的代码如果按照作者原先的逻辑,就是从当前程序执行的时刻起,开始数据的同步。这也是之前那个团队修复的 btsbots 为何不支持老账户的原因。这里我改回到 1.11.0 后,运行程序跑了一天多后,发现有报错,大致意思就是插入的数据的索引有重复导致插入失败。这个问题现在还没有去深究原因。

最后为解决的难点就是这个 monitor.pyoperation 的处理了。先看下面两个截图感受下

第一个截图中,是初始化了所有类型的 op,从 btsbots 的代码里看,截止到这份代码的最后修改时间,一共有 44 个类型,这里比较蛋疼的就是之后的 bitshares-core 中是否有再新增类型吗?由于我看不懂 **C++**,所以这里就会不确定。这 44 个类型里,有些没有手续费的类型,就去掉了没有处理,因为这个对于 balance 不产生影响,剩下的类型由 16 个 handler 处理,这里就有疑问了。大致扫过这些 handler,里面也有对数据库中的 balance 的操作,那么这里通过 1.11.xbalance 进行的操作与 correct-balance.py 文件中,通过 1.8.xbalance 的操作会不会有冲突?这个问题现在我一直在里面绕着出不来。现在的打算是,最好能确认 correct-balance.py 的意义,然后把这个文件中的逻辑整合进 monitor.py 中。

目前还没有深入看 statistics.py 这个文件,这个文件的主要作用就是通过 1.2.9952 发布的喂价来更新数据库里的交易对的交易价格,另外就是统计一下交易数据。

纵观这三个文件,还有个疑问就是三个文件都在获取 global properties,且都更新数据库,那么这里面到底会不会有问题有冲突,这个还没有细看。

以上就是现有的收获了。接下来有两个方向,一个是继续看所有的 handler,把具体的处理逻辑都看完,然后再修复,另一个方向就是跳过细看 handler,直接去看看那个索引冲突的问题,强行把程序跑起来看看。

最后再附上一份我搜集的 object id

ID Object Type
1.1.x base object
1.2.x account object
1.3.x asset object
1.4.x force settlement object
1.5.x committee member object
1.6.x witness object
1.7.x limit order object
1.8.x call order object
1.9.x custom object
1.10.x proposal object
1.11.x operation history object
1.12.x withdraw permission object
1.13.x vesting balance object
1.14.x worker object
1.15.x balance object
2.0.x global_property_object
2.1.x dynamic_global_property_object
2.3.x asset_dynamic_data
2.4.x asset_bitasset_data
2.5.x account_balance_object
2.6.x account_statistics_object
2.7.x transaction_object
2.8.x block_summary_object
2.9.x account_transaction_history_object
2.10.x blinded_balance_object
2.11.x chain_property_object
2.12.x witness_schedule_object
2.13.x budget_record_object
2.14.x special_authority_object

最近在使用 Python 重写 LightDB 的第二层的数据转换程序,因为之前 PHP 版的转换程序效率太低了(主要是设计思路的问题)。使用 Python 换了个思路来实现。

现在发现了 PyMysql 在多线程下工作异常,示例代码大致如下:

执行效果如下:

通过搜索引擎找到这个 Issue (https://github.com/PyMySQL/PyMySQL/issues/422),在 7 楼有提到,

1
2
3
See https://www.python.org/dev/peps/pep-0249/#threadsafety

PyMySQL's threadsafety is 1.

解决方案,在这个 Issue 中也提到了,就是一个 process/thread 中开一个 mysql 的连接。

Oh my god !!!!!

这显然并不好!

另外,@oflyhigh O哥给找到了一个小哥写的库,https://github.com/jkklee/pymysql-connpool ,这个库的目的就是实现一个 Mysql connection pool 来解决多线程的问题。准备尝试下这个库。感谢 O哥。

0%