vlambda博客
学习文章列表

太上中的基因设计与Binary | 函数式与区块链(一)

关于函数式编程:

函数式编程是有别于传统的面对对象范式的编程范式,函数式方向是目前编程语言发展的大方向,所有新设计的编程语言都或多或少的引入了函数式编程功能。

笔者认为,「下一代计算机学科体系」将基于函数式编程语言。因此,打好函数式编程基础对于具备「长期主义」思维的程序员是必要的。

关于本专栏:

本专栏将通过实战代码分析与经典著作解读,分享作者关于函数式编程与区块链的思考与实践。就目前而言,本专栏将基于两种函数式语言:Rust 和 Elixir,有时候会提及其它语言,作为辅助性参考。

关于太上:

太上是笔者团队近期实践的一个函数式+区块链的项目。

太上炼金炉在不改变原有 NFT 合约的基础上,通过附加「存证合约」,赋予 NFT 组合、拆解、生命周期、权益绑定等能力,锻造 NFT +,创造无限创新玩法与想象空间。

愿景0x01:助力所有 NFT 及其相关项目,让其具备无限商业想象空间与无限玩法。

愿景0x02:成为下一代区块链基础设施

太上是本系列用以探讨函数式编程的第一个项目。

Binary 基础知识

什么是 Binary?Binary 中文为二进制类型,是一种各编程语言中都存在的基本数据类型,在部分语言(如Python)中,将其称之为 Bytes。

Binary 可以看做是 0-255 的整型构成列表(List),如:<<255,18,33>>

Binary 和字符串(String)是什么关系?字符串是 Binary 的子集,字符串能转化为 Binary,但不是所有的 Binary 都能转化为String。

Binary 在区块链中有哪些应用?

Binary 的形式;智能合约编码后是 Binary;签名(Signature)也是 Binary。

不同语言中的 Binary

虽然在本质上等价,但是在不同语言中 Binary 会呈现不同的形式。

Python:

>> payload = bytes('你好 世界', encoding='UTF-8')>> print(payload)b'\xe4\xbd\xa0\xe5\xa5\xbd \xe4\xb8\x96\xe7\x95\x8c'

Java:

class BytesDemo{ public static void main(String[] args) {
byte payload[] = new byte[3]; payload[0] = (byte) 0x0A; payload[1] = (byte) 0xFF; payload[2] = (byte) 0x01;
for (byte theByte : payload){ System.out.println(Integer.toHexString(theByte)); } }}

NodeJs:

> var payload = new Buffer('hello world')> Buffer.prototype.toByteArray = function () {return Array.prototype.slice.call(this, 0)}> payload.toByteArray()[ 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

Rust:

let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82"; // SHIFT-JIS 编码的 "ようこそ"

Elixir:

iex> <<11,22,33,44>>

万变不离其宗。我们要认识到,本质上来讲这些 Binary 都是一样的。

太上中的基因设计

太上中的基因,是对于价值容器(NFT)承载的属性的一种抽象表达。具体渲染出来的实体,不管是渲染出一只猫还是一把屠龙宝刀,这事和基因本身是解耦的。

因此,笔者设计了这样的 Binary 模型:

Gene<<33, 44, 66, 22, 11, 55, 234, 111>>|---| |---------------------|-----  | |1/4处用以表示二值属性,如男/女 后3/4用以表示数值属性,如魔法值

在处理 Gene 的时候,函数式编程中的 「Pattern Match」(模式匹配)就表现出它的威力了,我们可以通过 Pattern Match 充分玩转 Binary。

下面将以基因分离为例,讲解「变量层面的模式匹配」这个知识点。

目标:实现函数,将基因的二值部分与其余部分分离。

Elixir 实现:

@spec split_gene(binary) :: {binary, binary}def split_gene(gene) do base2_size = gene |> byte_size() |> div(4)
# 1/4 is base2 <<binary_base2::bytes-size(base2_size), binary_base10::binary>> = gene {binary_base2, binary_base10}end

只需一行代码,借助变量层面的模式匹配,我们便抽离出了binary_base2binary_base10

Rust:

Rust 中可借助nom这个库,以下是解析 hex color 为 RGB 的例子:

fn hex_color(input: &str) -> IResult<&str, Color> { let (input, _) = tag("#")(input)?; let (input, (red, green, blue)) = tuple((hex_primary, hex_primary, hex_primary))(input)?;
Ok((input, Color { red, green, blue }))}

Binary 的编码方式

常见地,「元」 Binary 可以被编码为 Base16、Base32、Base64 等多种形式。

Binary 编码有助于让信息的传输更有效率,因此,Base64编码在我们的日常开发中非常常见。

base58和base64一样是一种二进制转可视字符串的算法,主要用来转换大整数值。区别是,转换出来的字符串,去除了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。

——https://www.jianshu.com/p/e002931bb38b

比特币之所以加入改进版的 Base58 算法,主要为了解决 Base58 导出的字符串没有校验机制,这样,在传播过程中,如果漏写了几个字符,会检测不出来。所以使用了改进版的算法 Base58Check。

实现是:在encode前,在输入流尾部加入输入内容的hash值(4个字节)。然后再对输入流进行 Base58Encode。

在 decode 时候:先 Base58Decode, 然后拆成两部分(内容和校验值),判断对内容计算的校验值和校验值字段是否一致。

——https://www.jianshu.com/p/e002931bb38b

在 Rust 中,我们通过base**库来实现 Binary 的编码:

use base64::{encode, decode};......
let result = encode(payload);

References

[1] https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp: https://link.jianshu.com/?t=https%3A%2F%2Fgithub.com%2Fbitcoin%2Fbitcoin%2Fblob%2Fmaster%2Fsrc%2Fbase58.cpp




李大狗Leeduckgo
面向「炫酷」编程
133篇原创内容
Official Account
后台输入关键字有自动回复:
输入「 比特币 」,推送比特币技术入门教程;
输入「 联盟链 」,推送联盟链开发系列教程;
输入「 项目 」,看看大狗最近在玩什么。