数据上链:从 bitsv 到打点 API

可能是因为临近二月份创世纪升级,前段时间几个常用的外部服务都略有不稳。小聪游戏用到的开源 bsv 库偶尔也会出现上链失败的情况。几次故障之后,我把数据上链方式由 bitsv 换成了打点开放平台的 API

替换之后,果然稳定许多,再也没有出现因为 API 不可用而导致游戏分数上链失败的情况了。

然而,我们发现本来可以被 https://trends.cash/ranking/ 收录的 satoplay.com 前缀变得无法识别了。在调查和解决这个问题的过程中,我对两个 API 的数据上链差异有了更多的了解。记录下来以备忘。

bitsv - send_op_return

bitsv 提供了一个数据上链接口 send_op_return。这个接口接受一个由 bytes 组成的 list,内部处理了拼接的细节。使用的时候可以直接这样:

data_group = ['hello_001'.encode('utf-8'), 'world_002'.encode('utf-8')]
my_key.send_op_return(data_group)

这种情况下,hello_001 会被认为是合法的前缀而被收录,小聪游戏的 satoplay.com 正是这样被识别的。

打点 API - pay_small_money (opreturn)

而情况在 打点提供的 API 这边则略有不同。

打点的 opreturn 参数是 string ,可以直接写入一般性的上链信息。而想要像上面那样区分出前缀,需要用到高级用法,也就是自己构造整个 op_return 脚本。这个脚本不复杂,甚至可以说是 bitcoin 脚本中最简单的类型,具体的结构是:

0 + OP_RETURN + PUSHDATAn + PUSHDATAn + PUSHDATAn + ...

其中每一段 PUSHDATAn 都有前缀: OP_PUSHDATA1/OP_PUSHDATA2/OP_PUSHDATA4 + 这段数据的长度,其中数据长度小于等于76个字符 (即 '0x4c',也就是 OP_PUSHDATA1 的值) 时则无需指明 OP_PUSHDATAn。

为打点 API 完整构造一个 OP_RETURN 脚本

完整的代码逻辑见下:

OP_PUSHDATA1 = b'\x4c'
OP_PUSHDATA2 = b'\x4d'
OP_PUSHDATA4 = b'\x4e'

def get_op_pushdata_code(data):
    length_data = len(data)
    if length_data <= 0x4c:  # (https://en.bitcoin.it/wiki/Script)
        return length_data.to_bytes(1, byteorder='little')
    elif length_data <= 0xff:
        return OP_PUSHDATA1 + length_data.to_bytes(1, byteorder='little')  # OP_PUSHDATA1 format
    elif length_data <= 0xffff:
        return OP_PUSHDATA2 + length_data.to_bytes(2, byteorder='little')  # OP_PUSHDATA2 format
    else:
        return OP_PUSHDATA4 + length_data.to_bytes(4, byteorder='little')  # OP_PUSHDATA4 format

OP_0 = b'\x00'
OP_RETURN = b'\x6a'

def dot_opreturn_build_hex_str(content):
    bytes_list = []
    if isinstance(content, str):
        bytes_list = [content.encode('utf-8')]
    else:
        bytes_list = [x.encode('utf-8') for x in content]

    prefix = OP_0 + OP_RETURN
    pushdata = b''
    for data in bytes_list:
        pushdata += get_op_pushdata_code(data) + data
    return (prefix + pushdata).hex()

备注:

  1. 上半部分 OP_PUSHDATAn 的获取是直接调用 bitsv 的逻辑
  2. 下半部分里,我们判断了传入的是单个 string,还是多个 string 构成的 list 并分别处理

后续小聪游戏平台进行 MetaNet 改造时,还会回来这里进一步拓展,目前就先这样吧。

(全文完)

Comments
Write a Comment

Tags

随笔   游戏开发   Programming   Bitcoin   C/C++   优化   Unity   C++   知乎   游戏设计   中国文化   比特币   Unity3D   区块链   软件开发   引擎设计   系统架构   Production   idtech   Bitcoin SV   加密货币   项目管理   BSV   游戏评论   资源管理   资源流水线   效率   道德经   网络   方法论   模板编程   Blockchain   Lua   Blockchain Computing   Oculus   GDC   渲染   VR   PerfAssist   Unity MemoryProfiler   BCH   读书笔记   经济学   信息过载   行业报告   字体   Productivity   图形   网络编程   Dice   协程   EMC   Premake   测试   中间件   Game Engine   新手引导   区块链游戏   Methodology   CI   命令行解析   goroutine   ndk   Ethereum   nanomsg   自动化   Scripting   摘录   Debugging   同步技术   cppcon   C++模板   数据上链   DOOM3   技术评估   Unity GC   C++11   学习方法   Surface Pro 3   Engine Evaluation   CRT   文化   笔记   golang   图形编程   多线程   ETH   Bitcoin Cash   cppcon14   Visual Studio   Unity Coroutine   跨语言可变参数列表   团队协作   货币   Deployment   Visual Assist   工程改进   Michael Abrash   exp   开放世界   量子计算   域名   虚拟现实   系统重构   slua   遮挡剔除   完美转发   协作式调度   Modern C++   类型推导   Memory Debugging   个人成长   小故事   BTC   暴雪   产品   历史   错误处理   Unity Profiler   MOD