很多人喜欢Go语言,其实是因为Go语言有其独特的语言属性在支撑着其在编程语言界的发展,今天兄弟连Go语言+区块链培训老师给大家介绍一下关于以太坊源码详解2,下面我们一起来看一下吧。
接下来我们看一下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
}
核心函数
// 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 er ror) {
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 o f its receiver to w.
// If the implementation is a pointer method, i t may also be
// called for nil pointers.
//
// Implementations should generate valid RLP. The data written is
// not verified at the moment, but a future v ersion might. It is
// recommended to write only a single value but writing multiple
???? encode.go
// values or no value at all is also permi tted.
EncodeRLP(io.Writer) error // 接口类型
}
2 .编码
func Encode(w io.Writer, val interface{}) error {
if outer, ok := w.(*encbuf); ok {
// Encode was called by some t ype's EncodeRLP.
// Avoid copying by writing to t he 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 encod ing
}
type listhead struct{
offset int // index of this header in string data
size int // total size of encoded data (including list h eaders)
}
上面是编码器的核心函数,解码的逻辑大致一样,我们不再多说