func (n *Node) updateRoutingTable(info *nodeInfo) {
	idx := getMostSignificantBit(n.DAddr.xor(info.dAddr))
	if idx < 0 {
		errors.Errorf("collision occurred")
		return
	}
	rb, ok := n.routingTable[idx]
	if !ok || rb == nil {
		panic(fmt.Sprintf("the routing table on %d not exist", idx))
	}
	rb.mux.Lock()
	defer rb.mux.Unlock()
	for i, n := range rb.bucket {
		if n.dAddr == info.dAddr {
			n.accessedAt = time.Now().UTC().Unix()
			rb.popAndAppend(i, n)
			return
		}
	}
	ni := &nodeInfo{
		nAddr:      info.nAddr,
		dAddr:      info.dAddr,
		accessedAt: time.Now().UTC().Unix(),
	}
	if len(rb.bucket) < bucketSize {
		rb.bucket = append(rb.bucket, ni)
	} else {
		rb.popAndAppend(0, ni)
	}
	n.logger.Infof("[updateRoutingTable] new nodeInfo inserted: %s", info.nAddr)
}
update routingTable using a given nodeInfo
package node
import (
	"context"
	"crypto/sha1"
	"fmt"
	"sort"
	"sync"
	"time"
	"github.com/mathetake/doogle/crawler"
	"github.com/mathetake/doogle/grpc"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ed25519"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
const (
	alpha         = 3
	bucketSize    = 20
	maxNumGetItem = 20  
)
type item struct {
	dAddrStr doogleAddressStr
	url   string
	title string
	edges []doogleAddressStr
	localRank         float64
	rankComputedCount float64
	mux sync.Mutex
}
type Node struct {
	DAddr doogleAddress
	routingTable map[int]*routingBucket
	dht sync.Map
	items sync.Map
	publicKey  []byte
	secretKey  []byte
	nonce      []byte
	difficulty int
	certificate *doogle.NodeCertificate
	logger *logrus.Logger
	crawler crawler.Crawler
	nAddrToConn sync.Map
	pageRankComputingQueue chan doogleAddressStr
}
var _ doogle.DoogleServer = &Node{}
type nodeInfo struct {
	dAddr      doogleAddress
	nAddr      string
	accessedAt int64
}
type routingBucket struct {
	bucket []*nodeInfo
	mux    sync.Mutex
}
func (rb *routingBucket) popAndAppend(idx int, ni *nodeInfo) {
	prev := rb.bucket
	l := len(prev)
	rb.bucket = make([]*nodeInfo, l)
	for i := 0; i < l; i++ {
		if i == l-1 {
			rb.bucket[i] = ni
		} else if i < idx {
			rb.bucket[i] = prev[i]
		} else {
			rb.bucket[i] = prev[i+1]
		}
	}
}
type dhtValue struct {
	itemAddresses []doogleAddressStr
	mux           sync.Mutex
}
func (n *Node) isValidSender(ct *doogle.NodeCertificate) bool {
	if n.certificate == ct {
		return true
	}
	if len(ct.DoogleAddress) < addressLength || int(ct.Difficulty) < n.difficulty {
		return false
	}
	var da doogleAddress
	copy(da[:], ct.DoogleAddress[:])
	if verifyAddress(da, ct.NetworkAddress, ct.PublicKey, ct.Nonce, int(ct.Difficulty)) {
		ni := nodeInfo{
			dAddr:      da,
			nAddr:      ct.NetworkAddress,
			accessedAt: time.Now().UTC().Unix(),
		}
		n.updateRoutingTable(&ni)
		return true
	}
	return false
}