在之前的领空投的帖子中,我曾说到,领空投以及交易空投币本质都是使用HIVE链上的Custom operation(custom_json_operation)。
(图源 :pixabay)
我们可以使用HiveSigner或者Keychain来生成并广播相应的custom_json
来完成相关操作。不过作为一个爱折腾的半吊子程序员,我还是喜欢自己写代码去完成。
简单介绍custom_json
说到custom_json
,我当初还真特意研究过一番,并且还专门写了一篇文章:每天进步一点点:custom_json & follow\unfollow\mute\unmute,在里边介绍了custom_json
结构、大致实现以及示范了follow\unfollow\mute\unmute几项功能。
所以,这次我们可以拿来直接使用,就以claim_duat为例:
首先我们要填充的结构大致是这样的:
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)
。
完成结构填充后,对其进行签名,并广播即可。
广播成功后的显示差异
然而当我广播成功后,我发现,在链上我广播的内容看起来是这个样子:
而查看别人广播的内容,看起来都是这个样子的(重新模拟生成了一下):
你注意到两者的差异了没有?虽然我确定,我前边广播的内容"{"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=(',',':'))
所以,就这样,为了一个其实并没有什么影响的问题,耗费了三两天的时间,这大概可以算作惨案了吧!
(图源 :pixabay)
/(ㄒoㄒ)/~~ 不对,应该是最惨的惨案!!还不对,应该是最最最惨的惨案了!!!