hexutil

package
v0.0.0-...-fda1b34 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2022 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package hexutil 这个文件定义了如何在uint64和16进制之间进行编解码; 定义了如何在大整数和16进制之间进行编解码; 定义了如何在普通字符串或字节切片与16进制之间进行编解码。

乙太坊中定义的16进制数据必定要以"0x"作为前缀,乙太坊规定用16进制最大只能定义256比特位的大整数。

Package hexutil 该文件里定义了以下三种自定义类型:

  • type Bytes []byte
  • type Big big.Int
  • type Uint64 uint64
  • type Uint uint

每个类型都为其实现了 MarshalText、UnmarshalText、UnmarshalJSON方法, UnmarshalText与UnmarshalJSON之间的关系为:当我们调用json.Unmarshal去解码数据时,如果给定的指针所代表的数据类型实现了 UnmarshalJSON方法,则会调用该类型自定义的UnmarshalJSON方法进行解码;否则如果给定的指针所代表的数据类型实现了UnmarshalText 方法,并且需要解码的数据被双引号包围,则会调用该类型自定义的UnmarshalText方法进行解码(解码的时候会把引号去掉)。

其中,Bytes、Big和Uint64三个类型还实现了 ImplementsGraphQLType 和 UnmarshalGraphQL 两个方法。

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrEmptyString 如果给定的16进制数是空的,就是连前缀都不含有,则报告该错误。
	ErrEmptyString = &decError{msg: "empty hex string"}
	// ErrSyntax 16进制数的取值范围是[0, F],一一例举的话就是:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f},
	// 不在这个范围内的都会报这个错误。
	ErrSyntax        = &decError{msg: "invalid hex string"}
	ErrMissingPrefix = &decError{msg: "hex string without 0x prefix"}
	// ErrOddLength 16进制数由四个比特表示,表示范围是[0000, 1111],而一个字节由8个比特组成,因此一个字节可以代表两个16进制
	// 数,也就是说必须两个16进制数才能组成一个字节,所以一个数据被编码成16进制数,那么结果的长度必然是偶数。
	ErrOddLength = &decError{msg: "hex string of odd length"}
	// ErrEmptyNumber 如果给定的16进制数等于0,换句话说就是只有"0x"前缀,则报告该错误,它与ErrEmptyString有一点点不一样。
	ErrEmptyNumber = &decError{msg: "hex string \"0x\""}
	// ErrLeadingZero 如果给定的16进制数不等于0,但是紧跟在前缀"0x"后面的数是"0",则报告此错误。
	ErrLeadingZero = &decError{msg: "hex number with leading zero digits"}
	// ErrUint64Range 一个64位的无符号整型由8个字节组成
	ErrUint64Range = &decError{msg: "hex number > 64 bits"}
	ErrUintRange   = &decError{msg: fmt.Sprintf("hex number > %d bits", uintBits)}
	ErrBig256Range = &decError{msg: "hex number > 256 bits"}
)

Errors ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

定义了9个项目全局范围内的 decError 实例,用来反映在解码16进制字符串时可能遇到的错误。

Functions

func Decode

func Decode(number string) ([]byte, error)

Decode ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

解码16进制字符串数据,得到字节切片,这个方法要求输入的字符串必须含有"0x"或"0X"前缀,不然就 返回 ErrMissingPrefix 错误。

例如:输入"0x43444546", 解码得到:[67 68 69 70]

func DecodeBig

func DecodeBig(number string) (*big.Int, error)

DecodeBig ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

解码大整数,给定的大整数的16进制字符串如果符合以下5个情况之一,则无法解码:

  1. 给定的字符串为空:""
  2. 给定的字符串没有"0x"或"0X"前缀:"1234"
  3. 给定的字符串只含有前缀:"0x" 或 "0X"
  4. 给定的非零16进制数的字符串开头等于0:"0x01"
  5. 去掉前缀后字符串的长度大于64

根据上述第5个情况所描述的规则,给定的16进制数必须小于^uint256(0)。

例如:输入"0x123",得到291

func DecodeUint64

func DecodeUint64(number string) (uint64, error)

DecodeUint64 ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

DecodeUint64 将给定的16进制数字(字符串形式,必须带有"0x"或"0X"前缀)解析成10进制数字。

例如:输入"0x1f",得到结果:31

func Encode

func Encode(bz []byte) string

Encode ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

Encode将给定的数据编码成带有"0x"前缀的16进制数据。

例如:输入[97 98 99 100], 输出:"0x61626364"

func EncodeBig

func EncodeBig(number *big.Int) string

EncodeBig ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

对大整数进行编码,得到含有"0x"前缀的16进制数字字符串形式的结果。

例如输入的大整数为-12,得到结果"-0xc"

func EncodeUint64

func EncodeUint64(number uint64) string

EncodeUint64 ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

将64位的无符号整型转换成带有"0x"前缀的16进制数据。

例如:输入24,得到结果"0x18";输入7,得到结果"0x7"

func MustDecode

func MustDecode(number string) []byte

MustDecode ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

对 Decode 方法进行了包装,实际上该方法还是调用了 Decode 方法,然后如果 Decode 方法返回了错误, 则MustDecode方法会直接panic。

func MustDecodeBig

func MustDecodeBig(number string) *big.Int

MustDecodeBig ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

MustDecodeBig 实际上执行 DecodeBig 来解码16进制的大数字,DecodeBig 如果返回错误,则直接panic。

func MustDecodeUint64

func MustDecodeUint64(number string) uint64

MustDecodeUint64 ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

对 DecodeUint64 方法进行包装,实际上 MustDecodeUint64 调用 DecodeUint64 方法解码给定的16进制数字,如果返回错误,则直接panic。

func UnmarshalFixedJSON

func UnmarshalFixedJSON(typ reflect.Type, input, out []byte) error

UnmarshalFixedJSON ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

UnmarshalFixedJSON 方法接收3个入参,其中第一个入参是要解码的数据类型,第二个入参是编码数据,第三个参数是接收解码结果的一个字节切片, 第二个入参和第三个入参都是字节切片类型的,UnmarshalFixedJSON 对这两个参数具有如下要求:

  1. 首先,第二个入参是编码数据,要求这个编码数据必须被双引号包围,并且必须含有"0x"或"0X"前缀
  2. 其次,要求第二个参数除前缀外,剩下的部分的长度值必须是偶数
  3. 最后,第三个参数作为接收解码结果的一个容器,编码数据是16进制形式的,所以要求第三个参数的切片长度必须等于第二个参数去掉前缀后,剩下 部分长度的一半,即:len(out) = len(input[1:len(input)-1]。

func UnmarshalFixedText

func UnmarshalFixedText(typName string, input, out []byte) error

UnmarshalFixedText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

UnmarshalFixedText 方法接收3个入参,其中第一个入参是要解码的数据类型,第二个入参是编码数据,第三个参数是接收解码结果的一个字节切片, 第二个入参和第三个入参都是字节切片类型的,UnmarshalFixedText 对这两个参数具有如下要求:

  1. 首先,第二个入参是编码数据,要求这个编码数据必须含有"0x"或"0X"前缀
  2. 其次,要求第二个参数除前缀外,剩下的部分的长度值必须是偶数
  3. 最后,第三个参数作为接收解码结果的一个容器,编码数据是16进制形式的,所以要求第三个参数的切片长度必须等于第二个参数去掉前缀后,剩下 部分长度的一半,即:len(out) = len(input[1:len(input)-1]。

func UnmarshalFixedUnPrefixedText

func UnmarshalFixedUnPrefixedText(typName string, input, out []byte) error

UnmarshalFixedUnPrefixedText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

UnmarshalFixedUnPrefixedText 方法接收3个入参,其中第一个入参是要解码的数据类型,第二个入参是编码数据,第三个参数是接收解码结果的 一个字节切片,第二个入参和第三个入参都是字节切片类型的,UnmarshalFixedUnPrefixedText 对这两个参数具有如下要求:

  1. 首先,第二个入参是编码数据,这个编码数据不用必须含有"0x"或"0X"前缀
  2. 其次,如果第二个参数含有前缀,要求其除前缀外,剩下的部分的长度值必须是偶数
  3. 最后,第三个参数作为接收解码结果的一个容器,编码数据是16进制形式的,(如果第二个参数含有前缀)所以要求第三个参数的切片长度必须等于 第二个参数去掉前缀后,剩下部分长度的一半,即:len(out) = len(input[1:len(input)-1]。

Types

type Big

type Big big.Int

Big ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

我们自定义的Big类型,其底层就是big.Int,自定义一个Big类型方便我们对大整数进行marshal/unmarshal, 大整数里的0会被编码成"0x0"。不支持对负数进行unmarshal,因为负数的编码结果的表现形式是"-0x..."这样 的,所以在利用 checkNumberText 方法验证需要编码数据是否具有"0x"或"0X"前缀时,验证结果会显示不存在 前缀,因为这里的前缀等于"-0"。比特位数大于256位的大整数在解码时会报错,但是在编码时不会报错。

func (Big) ImplementsGraphQLType

func (b Big) ImplementsGraphQLType(name string) bool

ImplementsGraphQLType ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

ImplementsGraphQLType 方法的输入参数如果是"BigInt",则该方法返回true。 第三方库github.com/graph-gophers/graphql-go对该方法的解释是:

ImplementsGraphQLType将实现的自定义Go类型映射到模式中的GraphQL标量类型。

func (Big) MarshalText

func (b Big) MarshalText() ([]byte, error)

MarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 encoding.TextMarshaler 接口,对大整数进行编码,得到含有"0x"前缀的16进制数字字符串, 然后返回该字符串的字节切片形式,返回的第二个参数永远都是nil。

func (*Big) String

func (b *Big) String() string

String ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

String 方法返回 Big 的字符串形式,实际上,就是对大整数进行编码,得到含有"0x"前缀的16进制数字字符串形式的结果。

func (*Big) ToInt

func (b *Big) ToInt() *big.Int

ToInt ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

ToInt 方法将 *Big 转换成 *big.Int。

func (*Big) UnmarshalGraphQL

func (b *Big) UnmarshalGraphQL(input interface{}) error

UnmarshalGraphQL ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

UnmarshalGraphQL 方法的输入参数是一个interface{},如果该参数的实际类型是string,则调用 Big 的 UnmarshalText 方法对该参数 的字节切片进行解码,并将得到的结果赋值给该方法的接收器 Big;如果参数的实际类型是int32,则调用 big.Int 的 SetInt64 方法将该参数 赋值给该方法的接收器 Big。如果输入的参数不是以上两种类型中的其中之一,则返回错误。 第三方库github.com/graph-gophers/graphql-go对该方法的解释是:

UnmarshalGraphQL是实现类型的自定义unmarshaler,每当你使用自定义GraphQL标量类型作为输入时,就会调用这个函数。

func (*Big) UnmarshalJSON

func (b *Big) UnmarshalJSON(input []byte) error

UnmarshalJSON ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 json.Unmarshaler 接口,该方法将给定的字节切片解码成 Big,但是给定的字节切片需要满足以下条件:

  1. 切片的两端必须是引号'"'
  2. 切片左边的引号之后必须紧跟"0x"或"0X"前缀

实际上该方法是调用 Big 的 UnmarshalText 方法对去掉两端引号后的字节切片进行解码。

func (*Big) UnmarshalText

func (b *Big) UnmarshalText(input []byte) error

UnmarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 encoding.TextUnmarshaler 接口,将给定的带有"0x"或"0X"前缀的字节切片数据解码成大整数。

 🚨注意:给定的字节切片必须含有前缀!否则会报错。另外去掉前缀后的字节切片的长度不能超过64,不然也会报错,
	因为我们无法对比特位数超过256位的大整数进行解码。

type Bytes

type Bytes []byte

Bytes ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

我们自己定义了一个切片类型Bytes,它的底层实现就是[]byte,定义该类型的目的是方便对字节切片进行编解码。

func (Bytes) ImplementsGraphQLType

func (b Bytes) ImplementsGraphQLType(name string) bool

ImplementsGraphQLType ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

ImplementsGraphQLType 方法的输入参数如果是"Bytes",则该方法返回true。 第三方库github.com/graph-gophers/graphql-go对该方法的解释是:

ImplementsGraphQLType将实现的自定义Go类型映射到模式中的GraphQL标量类型。

func (Bytes) MarshalText

func (b Bytes) MarshalText() ([]byte, error)

MarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

该方法实现了 encoding.TextMarshaler 接口,该方法的作用就是将字节切片转换为16进制数据, 我们知道一个字节可以代表两个16进制数,所以转换为16进制数据后,长度会扩大一倍,只是在此 基础上,我们还要在转换后的数据前加上`0x`前缀,所以长度还要再加2。

func (Bytes) String

func (b Bytes) String() string

String ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

输出Bytes的字符串表现形式,将给定的数据编码成带有"0x"前缀的16进制数据。

func (*Bytes) UnmarshalGraphQL

func (b *Bytes) UnmarshalGraphQL(input interface{}) error

UnmarshalGraphQL ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

UnmarshalGraphQL 方法的输入参数是一个interface{},如果该参数的实际类型是string,则调用 Decode 方法对该参数 进行解码,并将得到的结果赋值给该方法的接收器 Bytes。

🚨注意:由于它调用 Decode 方法进行解码,所以要求输入的字符串参数必须含有"0x"或"0X"前缀,否则会报错。

第三方库github.com/graph-gophers/graphql-go对该方法的解释是:

UnmarshalGraphQL是实现类型的自定义unmarshaler,每当你使用自定义GraphQL标量类型作为输入时,就会调用这个函数。

func (*Bytes) UnmarshalJSON

func (b *Bytes) UnmarshalJSON(input []byte) error

UnmarshalJSON ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 json.Unmarshaler 接口,该方法将给定的字节切片解码成 Bytes,但是给定的字节切片需要满足以下条件:

  1. 切片的两端必须是引号'"'
  2. 切片左边的引号之后必须紧跟"0x"或"0X"前缀

该方法实际上是调用 Bytes 的 UnmarshalText 方法对去掉两端引号后的字节切片进行解码。

func (*Bytes) UnmarshalText

func (b *Bytes) UnmarshalText(input []byte) error

UnmarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/26|

UnmarshalText方法实现了encoding.TextUnmarshaler接口,该方法将 MarshalText 的编码结果解码成原始数据, 由于是 MarshalText 的编码结果,所以给定的输入参数必然要含有"0x"前缀,不然会直接报错。

type Uint

type Uint uint

Uint ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

Uint 是我们自定义的一个数据类型,其底层实现其实就是Go内置的uint,定义 Uint 是为 了方便对uint进行marshal/unmarshal,0会被编码成"0x0"。

func (Uint) MarshalText

func (i Uint) MarshalText() ([]byte, error)

MarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 encoding.TextMarshaler 接口,实际上是将 Uint 强制类型转换成 Uint64, 然后调用 Uint64 的 MarshalText 方法对无符号整数进行编码。

func (Uint) String

func (i Uint) String() string

String ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

String 方法返回 Uint 的字符串形式,实际上是先将 Uint 强制类型转换为 uint64,然后利用 EncodeUint64 方法对其进行编码, 将64位的无符号整型转换成带有"0x"前缀的16进制数据。

例如:输入24,得到结果"0x18";输入7,得到结果"0x7"

func (*Uint) UnmarshalJSON

func (i *Uint) UnmarshalJSON(input []byte) error

UnmarshalJSON ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 json.Unmarshaler 接口,该方法将给定的字节切片解码成 Uint,但是给定的字节切片需要满足以下条件:

  1. 切片的两端必须是引号'"'
  2. 切片左边的引号之后必须紧跟"0x"或"0X"前缀

实际上该方法是调用 Uint 的 UnmarshalText 方法对去掉两端引号后的字节切片进行解码。

func (*Uint) UnmarshalText

func (i *Uint) UnmarshalText(input []byte) error

UnmarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 encoding.TextUnmarshaler 接口,该方法是对 Uint 的 MarshalText 方法产生的编码结果进行解码, 由于 Uint 的 MarshalText实际上是通过调用 Uint64 的 MarshalText 方法实现的,所以 Uint 的 UnmarshalText 方法也是通过调用 Uint64 的 UnmarshalText 方法实现的。

type Uint64

type Uint64 uint64

Uint64 ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

我们自定义了一个Uint64类型,它的底层实现其实就是Go内置的uint64类型,定义Uint64是为了方便对64位 无符号整型进行marshal/unmarshal,0会被编码成"0x0"。

func (Uint64) ImplementsGraphQLType

func (i Uint64) ImplementsGraphQLType(name string) bool

ImplementsGraphQLType ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

ImplementsGraphQLType 方法的输入参数如果是"Long",则该方法返回true。 第三方库github.com/graph-gophers/graphql-go对该方法的解释是:

ImplementsGraphQLType将实现的自定义Go类型映射到模式中的GraphQL标量类型。

func (Uint64) MarshalText

func (i Uint64) MarshalText() ([]byte, error)

MarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 encoding.TextMarshaler 接口,该方法实际上是调用 strconv.AppendUInt 方法对 Uint64 进行编码,编码的规则是:先将 Uint64 转换成16进制,如75被转换成4b,然后用ASCII码字符对应的编码逐个替换 4b里的4和b,4在ASCII码里对应的编码是52,b在ASCII码里对应的编码是98,所以最终75被转换为[52 98],在此 基础上,我们还要在转换的结果前加上"0x"前缀,0在ASCII码里对应的编码是48,x在ASCII码里对应的编码是120, 所以,如果该方法的接收器的值是75,调用 UnmarshalText 方法得到的结果将是[48 120 52 98]。

func (Uint64) String

func (i Uint64) String() string

String ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

String 方法返回 Uint64 的字符串形式,实际上就是将64位的无符号整型转换成带有"0x"前缀的16进制数据。

例如:Uint64 的实例是24,得到结果"0x18";Uint64 的实例是7,得到结果"0x7"

func (*Uint64) UnmarshalGraphQL

func (i *Uint64) UnmarshalGraphQL(input interface{}) error

UnmarshalGraphQL ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

UnmarshalGraphQL 方法的输入参数是一个interface{},如果该参数的实际类型是string,则调用 Uint64 的 UnmarshalText 方法对 该参数的字节切片进行解码,并将得到的结果赋值给该方法的接收器 Uint64;如果参数的实际类型是int32,则将该参数强制类型转换成 Uint64。 如果输入的参数不是以上两种类型中的其中之一,则返回错误。 第三方库github.com/graph-gophers/graphql-go对该方法的解释是:

UnmarshalGraphQL是实现类型的自定义unmarshaler,每当你使用自定义GraphQL标量类型作为输入时,就会调用这个函数。

func (*Uint64) UnmarshalJSON

func (i *Uint64) UnmarshalJSON(input []byte) error

UnmarshalJSON ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 json.Unmarshaler 接口,该方法将给定的字节切片解码成 Uint64,但是给定的字节切片需要满足以下条件:

  1. 切片的两端必须是引号'"'
  2. 切片左边的引号之后必须紧跟"0x"或"0X"前缀

实际上该方法是调用 Uint64 的 UnmarshalText 方法对去掉两端引号后的字节切片进行解码。

func (*Uint64) UnmarshalText

func (i *Uint64) UnmarshalText(input []byte) error

UnmarshalText ♏ |作者:吴翔宇| 🍁 |日期:2022/10/27|

该方法实现了 encoding.TextUnmarshaler 接口,该方法就是将 Uint64 的 MarshalText 方法的编码结果再 解码成 Uint64。

🚨注意:该方法要求传入的字节切片参数必须含有"0x"或"0X"前缀。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL