巧妇难为无米之炊

写下这样一个标题是不是有标题党的嫌疑?哈哈。

话说前些天,朋友的耳放开关坏掉了,让我帮他修理。可是尽管我有螺丝刀、电烙铁、焊锡丝等一堆工具,但是我没摇杆开关啊,哥们说我去淘宝买。

然后过两天他带着他的耳放机器和他买的巨大无比的开关过来了。我一看这开关,我擦,你这是用在飞机上的吧?巨大无比啊。

哥们很惭愧,然后让我告诉他买啥样的,我把他坏掉的开关卸了下来,然后观察一下,用尺子量量,应该是两档6脚开孔6毫米的开关,淘宝下单,地址直接写我家,然后我就开始耐心等待。

20180417_095916.jpg

不得不说,淘宝就是效率,没两天,开关就到货了,这样我也就没有理由继续拖延了,开工修家电吧。来感受一下他之前拿来的大开关。

20180417_100031.jpg

耳放外边的螺丝是异形螺丝,真令人讨厌,还好当年我自己DIY智能插排为了对付公牛插排的异形螺丝特意买了一组螺丝刀套装,哎,都用一字或者十字多好呀,这些变态的厂商。

20180417_100358.jpg

20180417_100107.jpg

20180417_100233.jpg

20180417_101310.jpg
费了半天劲,差点把手烙熟,总算把开关换上了(呃,完工的图呢?忘记拍了)然后找了家里豆浆机的电源线插上,打算试试能不能点亮。

小心翼翼的拨动开关,擦,一点响应都没有,来回拨几次,擦擦擦,还是没有响应!是我豆浆机电源线有问题,还是我开关换的不成功呢?

仔细观察耳放的电源接口,发现后边有一处写着 Fuse 250V的字样,莫非这里隐藏着一个保险丝?费了好大劲抠开,里边的果然是放保险丝的地方,不过已经变成一堆碎玻璃和两个金属头了。这耳放曾经遭遇了什么暴力?难以想象。

从家里电器上抠下来一个保险丝,结果规格不一样,放不进去。打电话去超市,人家说没有,哎。让我哥们自己去淘宝买吧。


就这样的,先来一盒吧,反正总共才几块钱。

于是我又变成等待状态,等保险丝到货再说吧。这也算巧妇难为无米之炊吧,所以我不是标题党哦。


This page is synchronized from the post: 巧妇难为无米之炊

C++ Range-based for loop

赵本山、赵四(刘晓光)搞笑小品《生日快乐》中有一段经典台词:

刘晓光:过上啦?
赵本山:刚过上。
刘晓光:过吧,不应该回来这是。
赵本山:刚过上,咱仨一起过,来
刘晓光:不是,现在咱们农村变化这么大嘛?三个人能在一起过?我跟你说,我适应不了

最近看STEEM代码,有时候我就是这种感觉:现在C++变化这么大嘛?还能这么用?我跟你说,我适应不了

C++ 98

从谭浩强的《C语言编程》我就接触过for循环,后来再学C++,至少我学的时候for循环还是那个样子,好多年来,我也一直那么用着。

1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;

int main () {
for( int a = 10; a < 20; a = a + 1 ) {
cout << a << endl;
}
return 0;
}

比如这段,多么熟悉,多么亲切的代码啊!

C++ 11

1
2
3
4
5
std::deque< price > copy;
for( const auto& i : fho.price_history )
{
copy.push_back( i );
}

但是在steem源码中看到这段代码,我就有点方了😳。 for( const auto& i : fho.price_history )是什么鬼?不过其实也没啥,尽管我不懂,但是我会猜啊,联系上下文,不难猜出不过是遍历fho.price_history中的元素,把元素扶植给i嘛。

尽管我读懂了这段代码,但是我的心情和刘晓光一样一样的,现在C++变化这么大嘛?还能这么用?我跟你说,我适应不了。

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
vector <string> list = {"rain", "sun", "wind", "me"};
for( const auto& i : list )
cout << i << endl;
return 0;
}

写一段代码,演练一下,编译时要加上-std=c++11参数,否则会提示:

range-based ‘for’ loops are not allowed in C++98 mode

其实 vector <string> list = {"rain", "sun", "wind", "me"};这段初始化方法C++98也不支持,不过这不是本文的重点。

C++ 17、20

看了一下C++ 的在线参考手册,区别与传统的for循环,这种for循环用法叫做Range-based for loop,是在C++ 11当中引进的。

而在C++17 以及 C++20后,这个Range-based for loop 增加了更多功能,真是日新月异啊。

结论

学习真的如逆水行舟,不进则退啊,更何况别人都在奋力向前那。

啥也不说了,继续看小品去,哈哈哈哈。


This page is synchronized from the post: C++ Range-based for loop

喂价(feed_price)以及STEEM的历史中间价(current_median_history)

在我以前的不少帖子中,都有涉及到喂价(feed_price)以及STEEM的历史中间价(current_median_history)等信息。在被问及喂价是怎么回事,历史中间价是多久的历史,这些价格如何得来等诸多问题时,我要么装作没看到,要么回答得语焉不详,原因是我也不知道啊。


(图源 :pixabay)

所以今天看了一下代码,了解了一下相关内容,这样以后再被问到,就不会丢人啦。

见证人提供并更新喂价

涉及到喂价,我们难免会问到,喂价是哪里来的呢?答案是喂价由见证人提供。

见证人可以通过witness_set_properties_operation或者feed_publish_operation设置或者发布喂价。

第一个操作可以对witness的诸多属性进行设置,比如说account_creation_feemax_block_changed以及sbd_exchange_rate

第二个操作仅仅用来发布喂价,因为大多数时候见证人的大多数属性不需要修改,但是STEEM价格变动是非常频繁的,使用feed_publish_operation可以减少数据传输量并节省系统开销。

发布喂价操作处理很简单,就是将对应见证人的喂价信息更新。

见证人的喂价一般来源于交易所STEEM兑美元的价格,因为系统认为SBD锚定一美元,所以见证人价格提供的方式为SBD/STEEM。原则上见证人可以提供任意价格,比如说100000 SBD,系统的处理机制会保证偏离过大的价格不会采纳。

current_median_history的获得

前边我们说了,见证人提供并更新喂价,但是那么多见证人提供的喂价,用谁的呢?还是用平均值?听我慢慢道来。

更新间隔

尽管STEEM市场行情每分每秒都在变化,但是系统的喂价每小时更新一次,调用的函数为:update_median_feed


尽管每出一个块都调用update_median_feed,但是以上代码使得实际被调用的周期是每小时一次。

其中:

#define STEEM_BLOCKS_PER_HOUR (60*60/STEEM_BLOCK_INTERVAL)
#define STEEM_FEED_INTERVAL_BLOCKS (STEEM_BLOCKS_PER_HOUR)

中间喂价(median_feed)

接下来的步骤是获取本轮见证人列表,以及对应见证人提供的喂价:

有关每轮见证人是如何产生的,可以参考我之前的文章:《STEEM 见证人的选择方法》

对获取的喂价进行排序,取其中间的那个值

这段代码解答了为何见证人的超高超低报价都是无效的这个问题。因为报价取的不是平均值,而是取中间的报价。

历史喂价(price_history)

有了中间喂价(median_feed),确切地说应该叫做当前喂价中间价,我们就可以更新历史喂价了。

其中STEEM_FEED_HISTORY_WINDOW为:

#define STEEM_FEED_HISTORY_WINDOW (12*7) // 3.5 days

从代码不难看出,所谓的历史喂价就是保存了3.5天(84组median_feed)的队列,新的当前喂价中间价追加到最后,最老的数据(最前边的)弹出。

接下来对历史喂价进行排序,并取中间值,这个就是current_median_history了。

代码最下边的段落用于调整current_median_history,以限制SBD在市场总份额中的占比,这个至少目前没被触发,先略过不谈了,回头计算一下。

总结

通过学习,我们得出如下结论:

  • 见证人提供并更新喂价
  • 系统每小时更新一次系统的喂价数据
    • 选择本轮见证人的喂价数据
    • 排序取中间值/median_feed(所以偏差较大数据无效)
    • 将median_feed追加到price_history末尾,并丢掉price_history头部数据
    • 排序取price_history中间值作为current_median_history

好吧,这回喂价(feed_price)以及STEEM的历史中间价(current_median_history)总算清楚了。

需要注意的是不同语境下,喂价(feed_price)代表不同意思。比如对于见证人而言,喂价(feed_price)指的是见证人提供的STEEM报价,对于STEEM区块链系统而言,喂价(feed_price)指的是STEEM的历史中间价(current_median_history)


This page is synchronized from the post: 喂价(feed_price)以及STEEM的历史中间价(current_median_history)

温度计 / Thermometer

很多年前迁新居的时候,朋友送了一个最最普通的那种玻璃棒的水银温度计,用她的话说,有了这个温度计,就可以知冷知热了。


(图源 :pixabay)

不过如何放这么一个温度计,可让我愁够呛,挂在外边柜子上,我总怕家人或者客人一不小心打碎了它,水银(汞)可是剧毒呢,如果挥发到空气中,在被我呼吸进肺里,我就会中毒,就会变得傻傻的。尽管我现在也不是很聪明,但是也不想变得更傻。

如果收藏起来呢,那么就没法知冷知热了。后来我终于给它找到一个栖身之所,就是卫生间的浴巾架,我把它挂到浴巾架的最内侧的挂钩上,这样我即能看到温度,一帮情况任何人都不会碰到它,安全系数大增。

好多年来,我觉得房间里特冷或者特热的时候,我总会去瞧一眼这个水银温度计,然后每次看的时候温度都是25摄氏度附近,于是我恍然大悟,温度一直没变,变得是我的心情。

但是好多年温度也不见变化,我开始怀疑不是我的感知出了问题,而是这个温度计坏掉了,不过就一个密闭的水银柱能咋坏呢?不管了,姑且当它坏掉吧。但是看它也没裂没碎,就那样挂着留作纪念吧。

再后来玩Arduino、玩IOT,手头有了一堆温度或者温湿度模块,比如LM35、有比如DHT11等,然后用Arduino连接LM35加上LED点阵来显示温度,或者后来用ESP8266+MQTT以及微信公众号实现随时查询家里温湿度的功能,玩得不亦乐乎。

看着LED点阵上不断跳动的温度,或者微信公众号返回的家里实时温湿度,我不禁感慨科技真的很发达,以前看起来很是高大上的东西,我这种菜鸟也可以随便DIY出来。再看玻璃棒水银温度计,觉得好简陋啊,一点不带感。

然后玩了一段时间之后,我厌倦了LED点阵在那不停的刷新,看着桌子上一堆电线以及模块也觉得很不顺眼,为了让公众号工作我弄的几台树莓派/香蕉派跑MQTT以及Apache更是觉得碍事,于是有一天一怒之下,我把这些乱七八糟的东西通通拔掉收了起来。

前两天下雪了,我觉得家里很冷,公众号发个指令查家里温度却一直没有应答,我才想起来,公众号相关的一堆设备都被我拔掉了,LED点阵的滚动温度显示也没了。于是我又想起了角落的温度计,看了一下温度,竟然是20摄氏度,果然比平时低。

温度计的温度竟然不是一直以来的25度,一方面说明温度真的降了,另一方面说明温度计还是好用的,这么多年,我冤枉它了。


(图源 :pixabay)

再看它这个光溜溜中空带水银柱的玻璃棒,一点也不觉得简陋了,原来最好的就是最简单的。


This page is synchronized from the post: 温度计 / Thermometer

使用WHM/cPanel 在服务器间批量转移账户

这些年没少在不同的服务器间转移网站数据,对于简单的网站一般来讲我都是在新服务器上创建好站点,然后到老服务器上用tar打包站点文件目录的所有文件,用mysqldump导出所有的数据库数据,然后再到新站点上恢复。

一般来讲,上述操作无往不利,在老服务器上用上命令行FTP,直接把tar文件以及数据库备份丢到新服务器上,不用通过本地中转,一般站点几分钟搞定。如果两个空间都开有SSH,那么就会更加便捷。

但是如果站点很复杂,比如绑定了一堆域名,开了一堆数据库,有一堆邮件账户以及邮件转发,设置了N多FTP账户,如果再设置了Crontab,域名设置了一堆解析记录,想用手动或者简单脚本来转移站点,那是相当有难度了。如果再涉及多个账户,那么就更是雪上加霜了。

WHM/cPanel

在WHM/cPanel中,这个事情被大大的简化了。你可能会问,WHM/cPanel是啥?答案是最最流行的一款虚拟主机管理面板,功能超级强大,但是价格也超级贵,以Softlayer.com为例,每台服务器每月WHM/cPanel的授权费为25美元。WHM是服务器管理员用的面板,cPanel是提供给用户的面板。

在装有WHM/cPanel主机之间转移站点,是很容易的事情,毕竟每月25美元软件授权费交着呢。一种方式是我们登陆旧站的cPanel,然后生成并下载全站备份,然后在新站点的cPanel中恢复。这种方式需要本地中转,如果站点数据量很大,需要转移的网站很多,本地网络再不好的话,这将会是个很恼人的工作。

所以最好的方式从服务器端直接操作,下面我介绍一下如何从WHM里操作批量转移站点。

转移步骤

  • 首先登陆WHM

  • 进入Home »Transfers

  • 选择Transfer Tool,填入旧站点所在服务器信息

  • 根据旧服务器的设置填入授权信息

    (需要注意的是,要保证两台服务器的防火墙都没有屏蔽对方以及对方端口)

  • 可以选择安全设置以及高级选项

    (如果都是自己的服务器,大可不必关心这个问题)

  • 点击

    会列出服务器信息,Packages信息,以及Accounts(账户列表)

  • 勾选对应的账户

    (可通过搜索快速定位,可按条件过滤,可多选)

  • 点击执行复制

  • 账户转移成功提示如下

后续工作

当然了,转移成功之后还是要做一点点工作的,比如说修改域名解析到新服务器。如果服务器自建DNS解析服务,那么直接改域名的DNS即可,反之则要添加对应的A记录、MX记录、CNAME等内容。

待转移成功,并且DNS解析完全生效后,检查无误就可以删除老站点了。当然,因为不同ISP的DNS缓存设置以及域名各项记录的TTL设置问题,域名各项记录全球生效可能需要一些时间,所以适当延长老站点的保留时间可以避免出现访问中断等问题。但是对于动态站点(需要写入数据的)这同样有可能造成两个站点数据不一致。

结论

使用WHM/cPanel 可以在服务器间迅速、批量转移账户,大大减轻维护的工作量。


This page is synchronized from the post: 使用WHM/cPanel 在服务器间批量转移账户

认真思索一下按用户、按操作授权的可行性

今天一个朋友 @maiyude 在我 10个月以前的老帖子《STEEMIT高级操作之:如何多人共同维护一个公共STEEMIT账户(ID)》 下回复了以下内容:

好厉害的操作。不知道能不能只允许别人操作内部市场挂单,而不能转账呢?如果可以这样的话,基金托管经理也可以诞生了。

授权功能

说起来这个老帖还是 @laodr 公用账户开始启用不久之后发的,为了方便当时的茶馆茶东共同维护这个公共账户,我特意研究一下相关内容,在实现了对应的需求后,我将学习心得总结成上述帖子。(注:现在老道茶馆茶东已经不包含 @oflyhigh 以及 @deanliu 了😀)。

扯远了,看到这个朋友的问题之后,我第一个反应就是不可行,因为STEEM授权体系就4级,Owner、Active、Posting以及Memo,内部市场挂单以及转账都需要的是Active权限,在这之下,STEEM是没有细分的,也就是说按照我文中提到的方法,如果你给了一个用户Active权限,那么他即能挂单又能转账。

但是是否可以进一步细分操作和权限呢?比如我们添加了A用户以及B用户的Active权限,A用户只可以转账,B用户只可以挂单?或者我们添加了C用户和D用户的Posting权限,能否实现C用户只能点赞,D用户只能发帖呢?

我们A、B用户分别实现转账以及挂单功能为例,看看有没有什么办法可以实现。这个问题可以从两方面来看,一方面是授权,一方面是区分操作类型。如果我们用文首文中提及的办法,亦即完全授权,那么将无法限制A、B的操作类型,所以必须引用授权的权重以及阈值的概念。

简单来讲就是给每个用户赋予一定的操作权重,然后必须总权重超过阈值才可以进行对应操作。

用户 权重
U_M 20
U_A 1
U_B 1

假设我们Active权限设置了上述用户,并且设置阈值(threshold)为21,那么上述三个用户单独签名将无法进行任何操作,应该提示类似Threshold not satisfied的错误。

多重签名(Multisignature)

但是如果将U_M和U_A 或者 U_M和U_B组合起来,并对交易(transaction)进行多重签名(Multisignature),那么就会满足阈值,就可以进行操作了。也就是说,我们可以通过U_M来允许或者禁止U_A或者U_B进行操作

到这步思路就渐渐明朗了,既然我们可以通过U_M来允许或者禁止U_A或者U_B进行操作,那么我们是否可以在U_M这里判断用户的操作类型,来进行控制(允许或者禁止)呢?答案是肯定的,因为交易(transaction)中包含有操作(operations)信息,包括操作类型。

但是用一个U_M用户进行控制,我们显然不能再找个人充当U_M,我们自己也不能充当U_M,否则U_A、U_B进行操作时总喊我进行签名,岂不是累死?那么答案就是编程实现喽。U_A或者U_B的操作由他们签名后提交给网络程序,程序判断用户和操作类型后,对符合条件的由U_M进行签名,并广播出去。

对Posting权限的授权同样如此,其实我们可以更进一步,比如限制U_A只能转账给X1、X2、X3用户,限制U_C只能给X1、X2、X3用户的帖子点赞等等,也就是说可以通过U_M实现个超级权限控制中心

结论

通过授权时指定权重以及阈值,并通过Master用户以及对应程序来进行判断,对符合条件的用户的操作进行多重签名,我们可以实现对授权的精确控制。

本文仅仅为思路探索,并不确保一定可行,更不确保是最优思路,仅供参考。

参考链接


This page is synchronized from the post: 认真思索一下按用户、按操作授权的可行性

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×