接下来我们看一下RLP,RLP是一种编码规则,以太坊中的数据都会经过它编码之后才会存储到数据库中,
上面是RLP的编码原理,接下来我们看一下以太坊中的RLP
从图上我们可以看到,在以太坊源码中,RLP包里面有用的文件其实只有三个,接下来我们详细看看
typecache.go:
1. 核心数据结构
核心数据结构
var (
typeCacheMutex sync.RWMutex
typeCache=make(map[typekey]*typeinfo)
)
type typeinfo struct {
decoder
writer
}
type typekey struct {
reflect.Type
// the key must include the struct tags because they
// might generate a different decoder.
tags
}
-
核心函数
1.生成对应的编码/解码器函数// map的查询 func cachedTypeInfo(typ reflect.Type, tags tags) (*typeinfo, error) { // 加锁 typeCacheMutex.RLock() info := typeCache[typekey{typ, tags}] // 查找类型 typeCacheMutex.RUnlock() // 解锁 if info != nil { // 如果不为空,直接返回 return info, nil } // not in the cache, need to generate info for this type. typeCacheMutex.Lock() defer typeCacheMutex.Unlock() return cachedTypeInfo1(typ, tags) } func cachedTypeInfo1(typ reflect.Type, tags tags) (*typeinfo, error) { key := typekey{typ, tags} info := typeCache[key] if info != nil { // 不为空,有可能是别的goroutine已经创建成功了,直接获取信息,返回 // another goroutine got the write lock first return info, nil } // put a dummmy value into the cache before generating. // if the generator tries to lookup itself, it will get // the dummy value and won't call itself recursively. // 创建了一个值来填充这个类型的位置,避免遇到一些递归定义是产生死循环 typeCache[key] = new(typeinfo) info, err := genTypeInfo(typ, tags) if err != nil { // remove the dummy value if the generator fails delete(typeCache, key) return nil, err } *typeCache[key] = *info //存储到缓存中 return typeCache[key], err } -
// 生成对应类型的编、解码器函数 func genTypeInfo(typ reflect.Type, tags tags) (info *typeinfo, err error) { info = new(typeinfo) // 创建解码器 if info.decoder, err = makeDecoder(typ, tags); err != nil { return nil, err } // 创建编码器 if info.writer, err = makeWriter(typ); err != nil { return nil, err } return info, nil }
上面是typecache.go中的主要逻辑
encode.go
编码器
1 .核心数据结构
var (
// Common encoded values.
// These are useful when implementing EncodeRLP.
EmptyString = []byte{0x80}
EmptyList = []byte{0xC0}
)
// Encoder is implemented by types that require custom
// encoding rules or want to encode private fields.
type Encoder interface {
// EncodeRLP should write the RLP encoding of its receiver to w.
// If the implementation is a pointer method, it may also be
// called for nil pointers.
//
// Implementations should generate valid RLP. The data written is
// not verified at the moment, but a future version might. It is
// recommended to write only a single value but writing multiple
ӣ̵ᖫᎱ encode.go
// values or no value at all is also permitted.
EncodeRLP(io.Writer) error // 接口类型
}
2 .编码
func Encode(w io.Writer, val interface{}) error {
if outer, ok := w.(*encbuf); ok {
// Encode was called by some type's EncodeRLP.
// Avoid copying by writing to the outer encbuf directly.
return outer.encode(val)
}
eb := encbufPool.Get().(*encbuf)
defer encbufPool.Put(eb)
eb.reset()
if err := eb.encode(val); err != nil {
return err
}
return eb.toWriter(w)
}
func (w *encbuf) encode(val interface{}) error {
rval := reflect.ValueOf(val)
ti, err := cachedTypeInfo(rval.Type(), tags{})
if err != nil {
return err
}
return ti.writer(rval, w)
}
// 此处充当buffer
type encbuf struct {
str []byte //string data, contains everything except list headers
lheads []*listhead // all list headers
lhsize int // sum of sizes of all encoded list headers
sizebuf []byte // 9-byte auxiliary buffer for uint encoding
}
type listhead struct{
offset int // index of this header in string data
size int // total size of encoded data (including list headers)
}
上面是编码器的核心函数,解码的逻辑大致一样,我们不再多说
-
学院Go语言视频主页
https://edu.csdn.net/lecturer/1928 -
扫码获取海量视频及源码 QQ群:721929980