RLP(Recursive Length Prefix,递归长度前缀) 是以太坊定义的一种编码算法,网上目前没有js版本的实现方法,这里根据原理简单实现一下,ps:代码未优化,写的比较粗糙,欢迎大家在评论区批评及提出优化方案。关于RLP的原理概述,网上有很多,这里不再描述。
首先写几个方法函数:
1. 数组内数字求和:
const sumArr = (arr: Array<number>) => {
var s = 0;
for (var i=0; i<arr.length; i++) {
s += arr[i];
}
return s;
}
2. 字符串转ASCII数组
const charToCode = (inputChar: any) => {
let result: Array<number> = []
for(let i in inputChar) {
result.push(inputChar.charCodeAt(i))
}
return result
}
3.bit数组计算字节数
const calByte = (arr: Array<number>) => {
var result: Array<number> = []
for(let i in arr) {
result.push(Math.floor(arr[i]/256))
}
return result
}
准备5个测试数据:
const data1 = "a"
const data2 = "abc"
const data3 = "The length of this sentence is more than 55 bytes, I know it because I pre-designed it"
const data4 = ["abc", "def"]
const data5 = ["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]
rpl编码支持输入字符串或者字符串数组,因此将计算字符串的方法单独封装:
const charToRlp = (inputChar: any) => {
const length = inputChar.length
if(length === 1) {
return inputChar.charCodeAt(0)
}else if (length <= 55) {
return [128 + length].concat(charToCode(inputChar))
} else {
return [184 + Math.floor(length/256), length].concat(charToCode(inputChar))
}
}
在主函数中根据输入格式做不同的处理,这里的代码思路是先把字符串转化为ASCII数组,再与描述长度的header拼接(感觉这种实现方法不是最优解,有待提高):
const rlpCoding = (input: any) => {
let length: Array<number> = [] //当输入为一个数组的时候,Length是数组中每个字符串的长度
const inpType = typeof input
let resultLis: Array<number> = []
if (inpType === "string") {
return charToRlp(input)
} else {
for(let i in input) {
length.push(input[i].length)
resultLis = resultLis.concat(charToRlp(input[i]))
}
if(sumArr(length) <= 55) {
return [192 + resultLis.length].concat(resultLis)
} else {
return [248 + Math.floor((sumArr(calByte(length)) + resultLis.length)/256), sumArr(calByte(length)) + resultLis.length].concat(resultLis)
}
}
}
测试输出
console.log("result1:", rlpCoding(data1), "\n",
"result2:", rlpCoding(data2), "\n",
"result3:", rlpCoding(data3), "\n",
"result4:", rlpCoding(data4), "\n",
"result5:", rlpCoding(data5)
)