每天进步一点点:custom_json操作中,分隔符引发的惨案

在之前的领空投的帖子中,我曾说到,领空投以及交易空投币本质都是使用HIVE链上的Custom operation(custom_json_operation)

image.png
(图源 :pixabay)

我们可以使用HiveSigner或者Keychain来生成并广播相应的custom_json来完成相关操作。不过作为一个爱折腾的半吊子程序员,我还是喜欢自己写代码去完成。

简单介绍custom_json

说到custom_json,我当初还真特意研究过一番,并且还专门写了一篇文章:每天进步一点点:custom_json & follow\unfollow\mute\unmute,在里边介绍了custom_json结构、大致实现以及示范了follow\unfollow\mute\unmute几项功能。

所以,这次我们可以拿来直接使用,就以claim_duat为例:

Reveal spoiler

image.png

首先我们要填充的结构大致是这样的:

op_custom_json = ['custom_json', {
    'required_auths': [],
    'required_posting_auths': [],
    'id': '',
    'json': ''
  }]

id是这个字符串,从上述截图中,不难看出id就是duat_drop_claim

因为领取空投,使用POSTING授权,所以required_auths保留为空,required_posting_auths添加上对应账户的id,比如说["oflyhigh.test"]

json信息,在Pthon中则是这样的内容json_data ={"claim":True},要把它添加到上述结构中,需要将其转换成字符串,我使用的是json.dumps(json_data)

完成结构填充后,对其进行签名,并广播即可。

广播成功后的显示差异

然而当我广播成功后,我发现,在链上我广播的内容看起来是这个样子:

Reveal spoiler

image.png

而查看别人广播的内容,看起来都是这个样子的(重新模拟生成了一下):

Reveal spoiler

image.png

你注意到两者的差异了没有?虽然我确定,我前边广播的内容"{"claim": true}"并不影响我领取空投,但是明显这样的{"claim":true}看起来更舒服!

显示差异的原因(表象——空格)

是什么导致这些差异呢(多了一圈双引号)?我百思不得其解。在其它一些区块链浏览器上,我的操作看起来也都是正常的,并且它确实起作用了,说明我的JSON没错,所以我只能将其归结为hiveblocks.com上解析&显示的问题。

但是新问题来了,为啥别人的显示和解析没问题呢?为此我进行了各种尝试:

  • 直接手工编码字符串
  • 将True替换成true并直接编码到字符串
  • 使用str()来将词典转换成字符串

当我即将被各种尝试折磨疯了以后,对比才发现,上述"{"claim": true}"{"claim":true}的差异不单单在于""的问题,前者:true之间其实还有一个空格,而这个不仔细观察是注意不到的。

当我试着用直接手工编码字符串的方式直接广播不带空格的字符串"{\"claim\":true}",发现一切都变正常了。

根本原因——json库的参数

这或许可以算是一种解决方法,至少在领空投这个事情上,这样操作是完全没有问题的。但是这岂不是意味着以后再写其它custom_json时,我都要去手工生成字符串了?简单一点的还好,如果遇到复杂的,我岂不是要累死了?

所以,找出为何json.dumps()会帮我添加上一个空格这样才能彻底解决问题

为此,我特意看了Python中json库的文档:json — JSON encoder and decoder,来看看用法和参数先:

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

最先怀疑的是indent参数,但是看到文档中说使用默认值就是最紧凑的形式处理了:

If indent is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0, negative, or "" will only insert newlines. None (the default) selects the most compact representation.Using a positive integer indent indents that many spaces per level. If indent is a string (such as "\t"), that string is used to indent each level.

都已经最紧凑了,我还能有啥办法?愁死我了!不过接着往下看,又发现separators参数:

If specified, separators should be an (item_separator, key_separator) tuple.The default is (', ', ': ') if indent is None and (',', ': ') otherwise. To get the most compact JSON representation, you should specify (',', ':') to eliminate whitespace.

Changed in version 3.4: Use (',', ': ') as default if indent is not None.

注意我划重点加粗加斜体的那句,就是说当我们选择最紧凑的模式时(indent is None),分隔符上还是给加了一个空格((', ', ': ')),这就是我们"{"claim": true}":后边空格之所以冒出来的来缘故了!

我有些搞不懂写这个库的程序员的思路了,明明设置了一个参数indent,并说这个参数默认时,是最紧凑的方式。然后又在分隔符后边加了个空格,这是什么逻辑?

仔细看文档,发现separators参数的说明中,还有一句:

To get the most compact JSON representation, you should specify (',', ':') to eliminate whitespace.

请问,之前明明说了最紧凑most compact representation,又让我指定separators参数来获取最紧凑的表示形式,恕我英语学得不好,形容词最高级之上还有最高级吗?

问题的解决

好吧,尽管这这奇怪的逻辑相当不爽,但是总算找到问题的原因了,所以我只需做如下修改,就可以愉快地使用json.dumps了:

json.dumps(json_data, separators=(',',':'))

所以,就这样,为了一个其实并没有什么影响的问题,耗费了三两天的时间,这大概可以算作惨案了吧!

image.png
(图源 :pixabay)

/(ㄒoㄒ)/~~ 不对,应该是最惨的惨案!!还不对,应该是最最最惨的惨案了!!!

相关链接

Sort:  

看起来很厉害的样子😂

Dear @oflyhigh, we need your help!

The Hivebuzz proposal already got important support from the community. However, it lost its funding a few days ago and only needs a few more HP to get funded again.

May we ask you to support it so our team can continue its work this year?
You can do it on Peakd, ecency,

Hive.blog / https://wallet.hive.blog/proposals
or using HiveSigner.
https://peakd.com/me/proposals/199

Your support would be really helpful and you could make a difference.
Thank you!

看得一头雾水,神一样的程度员。
看不懂,告辞

😂瓜叔只要懂得搬砖就可以了

😂这种程序在O哥这里拿捏得稳稳的

太厉害了👍👍