美文网首页
以太坊源码阅读-数据结构篇

以太坊源码阅读-数据结构篇

作者: 区块链布道者Enoch | 来源:发表于2018-08-23 20:41 被阅读0次

    本篇文章来解读下RLP、trie和ethdb等源码,先从RLP开始。
    一、RLP
    var (
    typeCacheMutex sync.RWMutex //读写锁,用来在多线程的时候保护typeCache这个Map
    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
    }

    用户获取编码器和解码器
    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() //否则加写锁 调用cachedTypeInfo1函数创建并返回, 这里需要注意的是在多线程环境下有可能多个线程同时调用到这个地方,所以当你进入cachedTypeInfo1方法的时候需要判断一下是否已经被别的线程先创建成功了。
    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 {
    // 其他的线程可能已经创建成功了, 那么我们直接获取到信息然后返回
    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
    }

    查找不到就生成新的typeinfo
    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, tags); err != nil {
    return nil, err
    }
    return info, nil
    }

    这里根据相应的类型生成对应的编码和解码器
    func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
    kind := typ.Kind()
    switch {
    case typ == rawValueType:
    return decodeRawValue, nil
    case typ.Implements(decoderInterface):
    return decodeDecoder, nil
    case kind != reflect.Ptr && reflect.PtrTo(typ).Implements(decoderInterface):
    return decodeDecoderNoPtr, nil
    case typ.AssignableTo(reflect.PtrTo(bigInt)):
    return decodeBigInt, nil
    case typ.AssignableTo(bigInt):
    return decodeBigIntNoPtr, nil
    case isUint(kind):
    return decodeUint, nil
    case kind == reflect.Bool:
    return decodeBool, nil
    case kind == reflect.String:
    return decodeString, nil
    case kind == reflect.Slice || kind == reflect.Array:
    return makeListDecoder(typ, tags)
    case kind == reflect.Struct:
    return makeStructDecoder(typ)
    case kind == reflect.Ptr:
    if tags.nilOK {
    return makeOptionalPtrDecoder(typ)
    }
    return makePtrDecoder(typ)
    case kind == reflect.Interface:
    return decodeInterface, nil
    default:
    return nil, fmt.Errorf("rlp: type %v is not RLP-serializable", typ)
    }
    }

    创造结构体的编解码器
    type field struct {
    index int
    info *typeinfo
    }
    func makeStructWriter(typ reflect.Type) (writer, error) {
    fields, err := structFields(typ)
    if err != nil {
    return nil, err
    }
    writer := func(val reflect.Value, w *encbuf) error {
    lh := w.list()
    for _, f := range fields {
    //f是field结构, f.info是typeinfo的指针, 所以这里其实是调用字段的编码器方法。
    if err := f.info.writer(val.Field(f.index), w); err != nil {
    return err
    }
    }
    w.listEnd(lh)
    return nil
    }
    return writer, nil
    }

    构造所有字段的编码器方法
    func structFields(typ reflect.Type) (fields []field, err error) {
    for i := 0; i < typ.NumField(); i++ {
    if f := typ.Field(i); f.PkgPath == "" { // exported,字段名称是大写的。
    tags, err := parseStructTag(typ, i)
    if err != nil {
    return nil, err
    }
    if tags.ignored {
    continue
    }
    info, err := cachedTypeInfo1(f.Type, tags)
    if err != nil {
    return nil, err
    }
    fields = append(fields, field{i, info})
    }
    }
    return fields, nil
    }

    编码器
    首先定义了EnptyString和EmptyList以及Encoder接口
    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
    // values or no value at all is also permitted.
    EncodeRLP(io.Writer) error
    }

    大部分的EncodeRLP方法都是直接调用了这个方法Encode方法。这个方法首先获取了一个encbuf对象。 然后调用这个对象的encode方法。encode方法中,首先获取了对象的反射类型,根据反射类型获取它的编码器,然后调用编码器的writer方法。 这个就跟上面谈到的typecache联系到一起了。

    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)
    }

    encbuf 编码缓存
    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)
    }

    func (w *encbuf) list() *listhead {
    lh := &listhead{offset: len(w.str), size: w.lhsize}
    w.lheads = append(w.lheads, lh)
    return lh
    }

    func (w *encbuf) listEnd(lh *listhead) {
    lh.size = w.size() - lh.offset - lh.size //lh.size记录了list开始的时候的队列头应该占用的长度 w.size()返回的是str的长度加上lhsize
    if lh.size < 56 {
    w.lhsize += 1 // length encoded into kind tag
    } else {
    w.lhsize += 1 + intsize(uint64(lh.size))
    }
    }
    func (w *encbuf) size() int {
    return len(w.str) + w.lhsize
    }

    最后组装成[]byte
    func (w *encbuf) toBytes() []byte {
    out := make([]byte, w.size())
    strpos := 0
    pos := 0
    for _, head := range w.lheads {
    // write string data before header
    n := copy(out[pos:], w.str[strpos:head.offset])
    pos += n
    strpos += n
    // write the header
    enc := head.encode(out[pos:])
    pos += len(enc)
    }
    // copy string data after the last list header
    copy(out[pos:], w.str[strpos:])//
    return out
    }

    解码器 decode.go
    func (s Stream) Decode(val interface{}) error {
    if val == nil {
    return errDecodeIntoNil
    }
    rval := reflect.ValueOf(val)
    rtyp := rval.Type()
    if rtyp.Kind() != reflect.Ptr {
    return errNoPointer
    }
    if rval.IsNil() {
    return errDecodeIntoNil
    }
    info, err := cachedTypeInfo(rtyp.Elem(), tags{})
    if err != nil {
    return err
    }
    err = info.decoder(s, rval.Elem())
    if decErr, ok := err.(
    decodeError); ok && len(decErr.ctx) > 0 {
    // add decode target type to error so context has more meaning
    decErr.ctx = append(decErr.ctx, fmt.Sprint("(", rtyp.Elem(), ")"))
    }
    return err
    }

    func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
    kind := typ.Kind()
    switch {
    case typ == rawValueType:
    return decodeRawValue, nil
    case typ.Implements(decoderInterface):
    return decodeDecoder, nil
    case kind != reflect.Ptr && reflect.PtrTo(typ).Implements(decoderInterface):
    return decodeDecoderNoPtr, nil
    case typ.AssignableTo(reflect.PtrTo(bigInt)):
    return decodeBigInt, nil
    case typ.AssignableTo(bigInt):
    return decodeBigIntNoPtr, nil
    case isUint(kind):
    return decodeUint, nil
    case kind == reflect.Bool:
    return decodeBool, nil
    case kind == reflect.String:
    return decodeString, nil
    case kind == reflect.Slice || kind == reflect.Array:
    return makeListDecoder(typ, tags)
    case kind == reflect.Struct:
    return makeStructDecoder(typ)
    case kind == reflect.Ptr:
    if tags.nilOK {
    return makeOptionalPtrDecoder(typ)
    }
    return makePtrDecoder(typ)
    case kind == reflect.Interface:
    return decodeInterface, nil
    default:
    return nil, fmt.Errorf("rlp: type %v is not RLP-serializable", typ)
    }
    }

    //
    func makeStructDecoder(typ reflect.Type) (decoder, error) {
    fields, err := structFields(typ)
    if err != nil {
    return nil, err
    }
    dec := func(s *Stream, val reflect.Value) (err error) {
    if _, err := s.List(); err != nil {
    return wrapStreamError(err, typ)
    }
    for _, f := range fields {
    err := f.info.decoder(s, val.Field(f.index))
    if err == EOL {
    return &decodeError{msg: "too few elements", typ: typ}
    } else if err != nil {
    return addErrorContext(err, "."+typ.Field(f.index).Name)
    }
    }
    return wrapStreamError(s.ListEnd(), typ)
    }
    return dec, nil
    }
    //
    func (s *Stream) Bytes() ([]byte, error) {
    kind, size, err := s.Kind()
    if err != nil {
    return nil, err
    }
    switch kind {
    case Byte:
    s.kind = -1 // rearm Kind
    return []byte{s.byteval}, nil
    case String:
    b := make([]byte, size)
    if err = s.readFull(b); err != nil {
    return nil, err
    }
    if size == 1 && b[0] < 128 {
    return nil, ErrCanonSize
    }
    return b, nil
    default:
    return nil, ErrExpectedString
    }
    }

    stream 结构分析
    type Stream struct {
    r ByteReader
    // number of bytes remaining to be read from r.
    remaining uint64
    limited bool
    // auxiliary buffer for integer decoding
    uintbuf []byte
    kind Kind // kind of value ahead
    size uint64 // size of value ahead
    byteval byte // value of single byte in type tag
    kinderr error // error from last readKind
    stack []listpos
    }
    type listpos struct{ pos, size uint64 }

    func (s *Stream) List() (size uint64, err error) {
    kind, size, err := s.Kind()
    if err != nil {
    return 0, err
    }
    if kind != List {
    return 0, ErrExpectedList
    }
    s.stack = append(s.stack, listpos{0, size})
    s.kind = -1
    s.size = 0
    return size, nil
    }

    func (s *Stream) ListEnd() error {
    if len(s.stack) == 0 {
    return errNotInList
    }
    tos := s.stack[len(s.stack)-1]
    if tos.pos != tos.size {
    return errNotAtEOL
    }
    s.stack = s.stack[:len(s.stack)-1] // pop
    if len(s.stack) > 0 {
    s.stack[len(s.stack)-1].pos += tos.size
    }
    s.kind = -1
    s.size = 0
    return nil
    }

    下面补充具体图形细节

    相关文章

      网友评论

          本文标题:以太坊源码阅读-数据结构篇

          本文链接:https://www.haomeiwen.com/subject/yturmxtx.html