5.2 以太坊原始碼詳解2

尹成發表於2018-11-09

接下來我們看一下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
    }
     1.生成對應的編碼/解碼器函式
  2. // 生成對應型別的編、解碼器函式
    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)
}

上面是編碼器的核心函式,解碼的邏輯大致一樣,我們不再多說

 

相關文章