以太坊rlp符号化規則及び実現
4745 ワード
rlp符号化
具体的なルール定義は、この文書を参照して太坊ソースで学習することができる-RLP符号化
ここではその重要な部分を抜粋する
エンコーディングデータ型
(1)byte配列(2)byte配列の配列をリストと呼ぶ
コーディング規則
(1)値が[0,127]の間の単一バイトについて、その符号化がそのものである(2)byte配列長l<=55であれば、符号化の結果が配列そのものであり、さらに128+lを接頭辞として空文字の符号化が128(3)配列長が55より大きい場合、符号化結果の最初のものは183配列長の符号化の長さであり、次いで配列長のそれ自体の符号化であり、最後にbyte配列の符号化である.(4)リスト長が55未満の場合、符号化結果1位は192プラスリスト長の符号化の長さであり、次いで各サブリストの符号化を順次接続する.(5)リスト長が55を超えると、符号化結果1位は247プラスリスト長の符号化長、次いでリスト長そのものの符号化となり、最後に各サブリストの符号化が順次接続される.
デコードルール
復号時には、まず、符号化結果の1バイト目fの大きさに基づいて、(1)f∈[0128]の場合、それはバイトそのものである.(2)f∈[128,184)の場合、それは55を超えないbyte配列であり、配列の長さがl=f-128(3)の場合、f∈(184192)では、長さが55を超える配列であり、長さ自体の符号化長さll=f-183であり、2バイト目から長さがllであるbytesを読み出し、BigEndianに従って整数lに符号化し、lは配列の長さである.(4)f∈(192247)であれば、符号化後の総長さが55を超えないリストであり、リスト長はl=f-122である.再帰的にはルール1~4を用いて復号する.(5)f∈(247256)では、符号化後の長さが55より大きいリストであり、その長さ自体の符号化長ll=f-247であり、その後、2バイト目から長さがllのbytesを読み出し、BigEndianにより整数l、l、すなわちサブリスト長に符号化する.その後、復号ルールに従って復号する.
コーデックのC言語実装
// , rlp
static int rlp_pack_varint_be(void **dest, size_t *left, uint64_t num)
{
int space = 0;
if (num <= 0xff) {
space = 1;
if (*left < space)
return -1;
*(uint8_t *)(*dest) = num;
} else if (num <= 0xffff) {
space = 2;
if (*left < space)
return -1;
uint16_t tmp = htobe16((uint16_t)num);
memcpy(*dest, &tmp, space);
} else if (num <= 0xffffffff) {
space = 4;
if (num <= 0xffffff)
space = 3;
if (*left < space)
return -1;
uint32_t tmp = htobe32((uint32_t)num);
memcpy(*dest, &tmp + 4 - space, space);
} else {
space = 8;
if (num <= 0xffffffffff)
space = 5;
else if (num <= 0xffffffffffff)
space = 6;
else if (num <= 0xffffffffffffff)
space = 7;
if (*left < space)
return -1;
uint64_t tmp = htobe64(num);
memcpy(*dest, &tmp + 8 - space, space);
}
*dest += space;
*left -= space;
return space;
}
//
static int rlp_unpack_varint_be(void **dest, size_t *left, uint64_t *num)
{
uint8_t prefix = ((uint8_t *)*dest)[0];
if (prefix < 184 || prefix > 191)
return - 1;
*dest += 1;
*left -= 1;
int space = prefix - 183;
uint64_t tmp = 0;
memcpy(&tmp, *dest, space);
*dest += space;
*left -= space;
*num = be64toh(tmp);
return space;
}
//
static int rlp_pack_buf(void **dest, size_t *left, const void *data, size_t len)
{
if (*left < len)
return -1;
if (len == 1) {
uint8_t val = ((uint8_t *)data)[0];
if (val == 0)
*(uint8_t *)(*dest) = 128;
else
memcpy(*dest, data, len);
*dest += len;
*left -= len;
} else if (len <= 55) {
if (*left < len + 1)
return - 1;
*(uint8_t *)(*dest) = 128 + len;
*dest += 1;
*left -= 1;
memcpy(*dest, data, len);
*dest += len;
*left -= len;
} else {
char buf[8] = {0};
void *buf_p = buf;
size_t buf_left = 8;
int space = rlp_pack_varint_be(&buf_p, &buf_left, len);
if (*left < len + space + 1)
return - 1;
*(uint8_t *)(*dest) = 183 + space;
*dest += 1;
*left -= 1;
memcpy(*dest, buf, space);
*dest += space;
*left -= space;
memcpy(*dest, data, len);
*dest += len;
*left -= len;
}
return len;
}
//
static int rlp_unpack_buf(void **src, size_t *left, void *dest, size_t len)
{
if (*left > len)
return -1;
uint8_t prefix = ((uint8_t *)*src)[0];
size_t dest_len = -1;
if (prefix == 128) {
*(uint8_t *)dest = 0;
dest_len = 0;
*src += 1;
*left -= 1;
} else if (prefix < 128) {
*(uint8_t *)dest = prefix;
dest_len = 1;
*src += 1;
*left -= 1;
} else if (prefix <= 183) {
dest_len = prefix - 128;
if (len < dest_len)
return -1;
*src += 1;
*left -= 1;
memcpy(dest, *src, dest_len);
*src += dest_len;
*left -= dest_len;
} else if (prefix <= 191) {
uint64_t tmp = 0;
rlp_unpack_varint_be(src, left, &tmp);
dest_len = tmp;
if (len < dest_len)
return -1;
memcpy(dest, *src, dest_len);
*src += dest_len;
*left -= dest_len;
}
return dest_len;
}
以上はrlpの文字配列符号化のみを行い,すなわち符号化を実現し,復号規則の最初の3つについては,リストの符号化は次のイーサ坊ブロックhashの計算で実現する.
// , rlp
static int rlp_pack_varint_be(void **dest, size_t *left, uint64_t num)
{
int space = 0;
if (num <= 0xff) {
space = 1;
if (*left < space)
return -1;
*(uint8_t *)(*dest) = num;
} else if (num <= 0xffff) {
space = 2;
if (*left < space)
return -1;
uint16_t tmp = htobe16((uint16_t)num);
memcpy(*dest, &tmp, space);
} else if (num <= 0xffffffff) {
space = 4;
if (num <= 0xffffff)
space = 3;
if (*left < space)
return -1;
uint32_t tmp = htobe32((uint32_t)num);
memcpy(*dest, &tmp + 4 - space, space);
} else {
space = 8;
if (num <= 0xffffffffff)
space = 5;
else if (num <= 0xffffffffffff)
space = 6;
else if (num <= 0xffffffffffffff)
space = 7;
if (*left < space)
return -1;
uint64_t tmp = htobe64(num);
memcpy(*dest, &tmp + 8 - space, space);
}
*dest += space;
*left -= space;
return space;
}
//
static int rlp_unpack_varint_be(void **dest, size_t *left, uint64_t *num)
{
uint8_t prefix = ((uint8_t *)*dest)[0];
if (prefix < 184 || prefix > 191)
return - 1;
*dest += 1;
*left -= 1;
int space = prefix - 183;
uint64_t tmp = 0;
memcpy(&tmp, *dest, space);
*dest += space;
*left -= space;
*num = be64toh(tmp);
return space;
}
//
static int rlp_pack_buf(void **dest, size_t *left, const void *data, size_t len)
{
if (*left < len)
return -1;
if (len == 1) {
uint8_t val = ((uint8_t *)data)[0];
if (val == 0)
*(uint8_t *)(*dest) = 128;
else
memcpy(*dest, data, len);
*dest += len;
*left -= len;
} else if (len <= 55) {
if (*left < len + 1)
return - 1;
*(uint8_t *)(*dest) = 128 + len;
*dest += 1;
*left -= 1;
memcpy(*dest, data, len);
*dest += len;
*left -= len;
} else {
char buf[8] = {0};
void *buf_p = buf;
size_t buf_left = 8;
int space = rlp_pack_varint_be(&buf_p, &buf_left, len);
if (*left < len + space + 1)
return - 1;
*(uint8_t *)(*dest) = 183 + space;
*dest += 1;
*left -= 1;
memcpy(*dest, buf, space);
*dest += space;
*left -= space;
memcpy(*dest, data, len);
*dest += len;
*left -= len;
}
return len;
}
//
static int rlp_unpack_buf(void **src, size_t *left, void *dest, size_t len)
{
if (*left > len)
return -1;
uint8_t prefix = ((uint8_t *)*src)[0];
size_t dest_len = -1;
if (prefix == 128) {
*(uint8_t *)dest = 0;
dest_len = 0;
*src += 1;
*left -= 1;
} else if (prefix < 128) {
*(uint8_t *)dest = prefix;
dest_len = 1;
*src += 1;
*left -= 1;
} else if (prefix <= 183) {
dest_len = prefix - 128;
if (len < dest_len)
return -1;
*src += 1;
*left -= 1;
memcpy(dest, *src, dest_len);
*src += dest_len;
*left -= dest_len;
} else if (prefix <= 191) {
uint64_t tmp = 0;
rlp_unpack_varint_be(src, left, &tmp);
dest_len = tmp;
if (len < dest_len)
return -1;
memcpy(dest, *src, dest_len);
*src += dest_len;
*left -= dest_len;
}
return dest_len;
}