成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Derek解讀Bytom源碼-P2P網(wǎng)絡(luò) 地址簿

Kahn / 3144人閱讀

摘要:作者簡介地址地址本章介紹代碼網(wǎng)絡(luò)中地址簿作者使用操作系統(tǒng),其他平臺(tái)也大同小異介紹用于存儲(chǔ)網(wǎng)絡(luò)中保留最近的對端節(jié)點(diǎn)地址在下,默認(rèn)的地址簿路徑存儲(chǔ)在地址簿格式地址類型在中存儲(chǔ)的地址有兩種標(biāo)識(shí)新地址,不可靠地址未成功連接過。

作者:Derek

簡介

Github地址:https://github.com/Bytom/bytom

Gitee地址:https://gitee.com/BytomBlockc...

本章介紹bytom代碼P2P網(wǎng)絡(luò)中addrbook地址簿

作者使用MacOS操作系統(tǒng),其他平臺(tái)也大同小異

Golang Version: 1.8

addrbook介紹

addrbook用于存儲(chǔ)P2P網(wǎng)絡(luò)中保留最近的對端節(jié)點(diǎn)地址
在MacOS下,默認(rèn)的地址簿路徑存儲(chǔ)在~/Library/Bytom/addrbook.json

地址簿格式

~/Library/Bytom/addrbook.json

{
    "Key": "359be6d08bc0c6e21c84bbb2",
    "Addrs": [
        {
            "Addr": {
                "IP": "122.224.11.144",
                "Port": 46657
            },
            "Src": {
                "IP": "198.74.61.131",
                "Port": 46657
            },
            "Attempts": 0,
            "LastAttempt": "2018-05-04T12:58:23.894057702+08:00",
            "LastSuccess": "0001-01-01T00:00:00Z",
            "BucketType": 1,
            "Buckets": [
                181,
                10
            ]
        }
    ]
}
地址類型

在addrbook中存儲(chǔ)的地址有兩種:
p2p/addrbook.go

const (
    bucketTypeNew = 0x01  // 標(biāo)識(shí)新地址,不可靠地址(未成功連接過)。只存儲(chǔ)在一個(gè)bucket中
    bucketTypeOld = 0x02  // 標(biāo)識(shí)舊地址,可靠地址(已成功連接過)??梢源鎯?chǔ)在多個(gè)bucket中,最多為maxNewBucketsPerAddress個(gè)
)

注意: 一個(gè)地址的類型變更不在此文章中做介紹,后期的文章會(huì)討論該問題

地址簿相關(guān)結(jié)構(gòu)體

地址簿

type AddrBook struct {
    cmn.BaseService

    mtx               sync.Mutex
    filePath          string  // 地址簿路徑
    routabilityStrict bool  // 是否可路由,默認(rèn)為true
    rand              *rand.Rand 
    key               string  // 地址簿標(biāo)識(shí),用于計(jì)算addrNew和addrOld的索引
    ourAddrs          map[string]*NetAddress  // 存儲(chǔ)本地網(wǎng)絡(luò)地址,用于添加p2p地址時(shí)做排除使用
    addrLookup        map[string]*knownAddress // 存儲(chǔ)新、舊地址集,用于查詢
    addrNew           []map[string]*knownAddress // 存儲(chǔ)新地址
    addrOld           []map[string]*knownAddress // 存儲(chǔ)舊地址
    wg                sync.WaitGroup
    nOld              int // 舊地址數(shù)量
    nNew              int // 新地址數(shù)量
}

已知地址

type knownAddress struct {
    Addr        *NetAddress // 已知peer的addr
    Src         *NetAddress // 已知peer的addr的來源addr
    Attempts    int32 // 連接peer的重試次數(shù)
    LastAttempt time.Time // 最近一次嘗試連接的時(shí)間
    LastSuccess time.Time // 最近一次嘗試成功連接的時(shí)間
    BucketType  byte // 地址的類型(表示可靠地址或不可靠地址)
    Buckets     []int // 當(dāng)前addr所屬的buckets
}

routabilityStrict參數(shù)表示地址簿是否存儲(chǔ)的ip是否可路由??陕酚墒歉鶕?jù)RFC劃分,具體參考資料:RFC標(biāo)準(zhǔn)

初始化地址簿
// NewAddrBook creates a new address book.
// Use Start to begin processing asynchronous address updates.
func NewAddrBook(filePath string, routabilityStrict bool) *AddrBook {
    am := &AddrBook{
        rand:              rand.New(rand.NewSource(time.Now().UnixNano())),
        ourAddrs:          make(map[string]*NetAddress),
        addrLookup:        make(map[string]*knownAddress),
        filePath:          filePath,
        routabilityStrict: routabilityStrict,
    }
    am.init()
    am.BaseService = *cmn.NewBaseService(nil, "AddrBook", am)
    return am
}

// When modifying this, don"t forget to update loadFromFile()
func (a *AddrBook) init() {
  // 地址簿唯一標(biāo)識(shí)
    a.key = crypto.CRandHex(24) // 24/2 * 8 = 96 bits
    // New addr buckets, 默認(rèn)為256個(gè)大小
    a.addrNew = make([]map[string]*knownAddress, newBucketCount)
    for i := range a.addrNew {
        a.addrNew[i] = make(map[string]*knownAddress)
    }
    // Old addr buckets,默認(rèn)為64個(gè)大小
    a.addrOld = make([]map[string]*knownAddress, oldBucketCount)
    for i := range a.addrOld {
        a.addrOld[i] = make(map[string]*knownAddress)
    }
}
bytomd啟動(dòng)時(shí)加載本地地址簿

loadFromFile在bytomd啟動(dòng)時(shí),首先會(huì)加載本地的地址簿

// OnStart implements Service.
func (a *AddrBook) OnStart() error {
    a.BaseService.OnStart()
    a.loadFromFile(a.filePath)
    a.wg.Add(1)
    go a.saveRoutine()
    return nil
}

// Returns false if file does not exist.
// cmn.Panics if file is corrupt.
func (a *AddrBook) loadFromFile(filePath string) bool {
    // If doesn"t exist, do nothing.
    // 如果本地地址簿不存在則直接返回
    _, err := os.Stat(filePath)
    if os.IsNotExist(err) {
        return false
    }

  // 加載地址簿json內(nèi)容
    // Load addrBookJSON{}
    r, err := os.Open(filePath)
    if err != nil {
        cmn.PanicCrisis(cmn.Fmt("Error opening file %s: %v", filePath, err))
    }
    defer r.Close()
    aJSON := &addrBookJSON{}
    dec := json.NewDecoder(r)
    err = dec.Decode(aJSON)
    if err != nil {
        cmn.PanicCrisis(cmn.Fmt("Error reading file %s: %v", filePath, err))
    }

  // 填充addrNew、addrOld等
    // Restore all the fields...
    // Restore the key
    a.key = aJSON.Key
    // Restore .addrNew & .addrOld
    for _, ka := range aJSON.Addrs {
        for _, bucketIndex := range ka.Buckets {
            bucket := a.getBucket(ka.BucketType, bucketIndex)
            bucket[ka.Addr.String()] = ka
        }
        a.addrLookup[ka.Addr.String()] = ka
        if ka.BucketType == bucketTypeNew {
            a.nNew++
        } else {
            a.nOld++
        }
    }
    return true
}
定時(shí)更新地址簿

bytomd會(huì)定時(shí)更新本地地址簿,默認(rèn)2分鐘一次

func (a *AddrBook) saveRoutine() {
    dumpAddressTicker := time.NewTicker(dumpAddressInterval)
out:
    for {
        select {
        case <-dumpAddressTicker.C:
            a.saveToFile(a.filePath)
        case <-a.Quit:
            break out
        }
    }
    dumpAddressTicker.Stop()
    a.saveToFile(a.filePath)
    a.wg.Done()
    log.Info("Address handler done")
}

func (a *AddrBook) saveToFile(filePath string) {
    log.WithField("size", a.Size()).Info("Saving AddrBook to file")

    a.mtx.Lock()
    defer a.mtx.Unlock()
    // Compile Addrs
    addrs := []*knownAddress{}
    for _, ka := range a.addrLookup {
        addrs = append(addrs, ka)
    }

    aJSON := &addrBookJSON{
        Key:   a.key,
        Addrs: addrs,
    }

    jsonBytes, err := json.MarshalIndent(aJSON, "", "	")
    if err != nil {
        log.WithField("err", err).Error("Failed to save AddrBook to file")
        return
    }
    err = cmn.WriteFileAtomic(filePath, jsonBytes, 0644)
    if err != nil {
        log.WithFields(log.Fields{
            "file": filePath,
            "err":  err,
        }).Error("Failed to save AddrBook to file")
    }
}
添加新地址

當(dāng)peer之間交換addr時(shí),節(jié)點(diǎn)會(huì)收到對端節(jié)點(diǎn)已知的地址信息,這些信息會(huì)被當(dāng)前節(jié)點(diǎn)添加到地址簿中

func (a *AddrBook) AddAddress(addr *NetAddress, src *NetAddress) {
    a.mtx.Lock()
    defer a.mtx.Unlock()
    log.WithFields(log.Fields{
        "addr": addr,
        "src":  src,
    }).Debug("Add address to book")
    a.addAddress(addr, src)
}


func (a *AddrBook) addAddress(addr, src *NetAddress) {
    // 驗(yàn)證地址是否為可路由地址
    if a.routabilityStrict && !addr.Routable() {
        log.Error(cmn.Fmt("Cannot add non-routable address %v", addr))
        return
    }
    // 驗(yàn)證地址是否為本地節(jié)點(diǎn)地址
    if _, ok := a.ourAddrs[addr.String()]; ok {
        // Ignore our own listener address.
        return
    }

    // 驗(yàn)證地址是否存在地址集中
    // 如果存在:則判斷該地址是否為old可靠地址、是否超過了最大buckets中。否則根據(jù)該地址已經(jīng)被ka.Buckets引用的個(gè)數(shù)來隨機(jī)決定是否添加到地址集中
    // 如果不存在:則添加到地址集中。并標(biāo)識(shí)為bucketTypeNew地址類型
    ka := a.addrLookup[addr.String()]

    if ka != nil {
        // Already old.
        if ka.isOld() {
            return
        }
        // Already in max new buckets.
        if len(ka.Buckets) == maxNewBucketsPerAddress {
            return
        }
        // The more entries we have, the less likely we are to add more.
        factor := int32(2 * len(ka.Buckets))
        if a.rand.Int31n(factor) != 0 {
            return
        }
    } else {
        ka = newKnownAddress(addr, src)
    }

    // 找到該地址在地址集的索引位置并添加
    bucket := a.calcNewBucket(addr, src)
    a.addToNewBucket(ka, bucket)

    log.Info("Added new address ", "address:", addr, " total:", a.size())
}
選擇最優(yōu)節(jié)點(diǎn)

地址簿中存儲(chǔ)眾多地址,在p2p網(wǎng)絡(luò)中需選擇最優(yōu)的地址去連接
PickAddress(newBias int)函數(shù)中newBias是由pex_reactor產(chǎn)生的地址評分。如何計(jì)算地址分?jǐn)?shù)在其他章節(jié)中再講
根據(jù)地址評分隨機(jī)選擇地址可增加區(qū)塊鏈安全性

// Pick an address to connect to with new/old bias.
func (a *AddrBook) PickAddress(newBias int) *NetAddress {
    a.mtx.Lock()
    defer a.mtx.Unlock()

    if a.size() == 0 {
        return nil
    }
    // newBias地址分?jǐn)?shù)限制在0-100分?jǐn)?shù)之間
    if newBias > 100 {
        newBias = 100
    }
    if newBias < 0 {
        newBias = 0
    }

    // Bias between new and old addresses.
    oldCorrelation := math.Sqrt(float64(a.nOld)) * (100.0 - float64(newBias))
    newCorrelation := math.Sqrt(float64(a.nNew)) * float64(newBias)

  // 根據(jù)地址分?jǐn)?shù)計(jì)算是否從addrOld或addrNew中隨機(jī)選擇一個(gè)地址
    if (newCorrelation+oldCorrelation)*a.rand.Float64() < oldCorrelation {
        // pick random Old bucket.
        var bucket map[string]*knownAddress = nil
        num := 0
        for len(bucket) == 0 && num < oldBucketCount {
            bucket = a.addrOld[a.rand.Intn(len(a.addrOld))]
            num++
        }
        if num == oldBucketCount {
            return nil
        }
        // pick a random ka from bucket.
        randIndex := a.rand.Intn(len(bucket))
        for _, ka := range bucket {
            if randIndex == 0 {
                return ka.Addr
            }
            randIndex--
        }
        cmn.PanicSanity("Should not happen")
    } else {
        // pick random New bucket.
        var bucket map[string]*knownAddress = nil
        num := 0
        for len(bucket) == 0 && num < newBucketCount {
            bucket = a.addrNew[a.rand.Intn(len(a.addrNew))]
            num++
        }
        if num == newBucketCount {
            return nil
        }
        // pick a random ka from bucket.
        randIndex := a.rand.Intn(len(bucket))
        for _, ka := range bucket {
            if randIndex == 0 {
                return ka.Addr
            }
            randIndex--
        }
        cmn.PanicSanity("Should not happen")
    }
    return nil
}
移除一個(gè)地址

當(dāng)一個(gè)地址被標(biāo)記為Bad時(shí)則從地址集中移除。目前bytomd的代碼版本并未調(diào)用過

func (a *AddrBook) MarkBad(addr *NetAddress) {
    a.RemoveAddress(addr)
}

// RemoveAddress removes the address from the book.
func (a *AddrBook) RemoveAddress(addr *NetAddress) {
    a.mtx.Lock()
    defer a.mtx.Unlock()
    ka := a.addrLookup[addr.String()]
    if ka == nil {
        return
    }
    log.WithField("addr", addr).Info("Remove address from book")
    a.removeFromAllBuckets(ka)
}

func (a *AddrBook) removeFromAllBuckets(ka *knownAddress) {
    for _, bucketIdx := range ka.Buckets {
        bucket := a.getBucket(ka.BucketType, bucketIdx)
        delete(bucket, ka.Addr.String())
    }
    ka.Buckets = nil
    if ka.BucketType == bucketTypeNew {
        a.nNew--
    } else {
        a.nOld--
    }
    delete(a.addrLookup, ka.Addr.String())
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/24240.html

相關(guān)文章

  • Derek解讀Bytom源碼-P2P網(wǎng)絡(luò) upnp端口映射

    摘要:作者簡介地址地址本章介紹代碼網(wǎng)絡(luò)中端口映射作者使用操作系統(tǒng),其他平臺(tái)也大同小異介紹通用即插即用。端口映射將一個(gè)外部端口映射到一個(gè)內(nèi)網(wǎng)。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介紹bytom代碼P2P網(wǎng)絡(luò)中upnp端口映射 作者使用Mac...

    ranwu 評論0 收藏0
  • Derek解讀Bytom源碼-啟動(dòng)與停止

    摘要:只有當(dāng)觸發(fā)了或才能終止進(jìn)程退出。退出時(shí)執(zhí)行如下操作會(huì)將挖礦功能停止,網(wǎng)絡(luò)停止等操作。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介紹bytom代碼啟動(dòng)、節(jié)點(diǎn)初始化、及停止的過程 作者使用MacOS操作系統(tǒng),其他平臺(tái)也大同小異Golang V...

    Godtoy 評論0 收藏0
  • Derek解讀Bytom源碼-Api Server接口服務(wù)

    摘要:首先讀取請求內(nèi)容,解析請求,接著匹配相應(yīng)的路由項(xiàng),隨后調(diào)用路由項(xiàng)的回調(diào)函數(shù)來處理。每一個(gè)路由項(xiàng)由請求方法和回調(diào)函數(shù)組成將監(jiān)聽地址作為參數(shù),最終執(zhí)行開始服務(wù)于外部請求創(chuàng)建對象首先,實(shí)例化對象。我們可以看到一條項(xiàng)由和對應(yīng)的回調(diào)函數(shù)組成。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com...

    GitCafe 評論0 收藏0
  • Derek解讀Bytom源碼-持久化存儲(chǔ)LevelDB

    摘要:函數(shù)總共操作有兩步從緩存中查詢值,如果查到則返回如果為從緩存中查詢到則回調(diào)回調(diào)函數(shù)?;卣{(diào)函數(shù)會(huì)將從磁盤上獲得到塊信息存儲(chǔ)到緩存中并返回該塊的信息。回調(diào)函數(shù)實(shí)際上調(diào)取的是下的,它會(huì)從磁盤中獲取信息并返回。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc......

    Eminjannn 評論0 收藏0
  • Derek解讀Bytom源碼分析-持久化存儲(chǔ)LevelDB

    摘要:函數(shù)總共操作有兩步從緩存中查詢值,如果查到則返回如果為從緩存中查詢到則回調(diào)回調(diào)函數(shù)?;卣{(diào)函數(shù)會(huì)將從磁盤上獲得到塊信息存儲(chǔ)到緩存中并返回該塊的信息?;卣{(diào)函數(shù)實(shí)際上調(diào)取的是下的,它會(huì)從磁盤中獲取信息并返回。 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介紹Dere...

    GitChat 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<