aboutsummaryrefslogblamecommitdiffstats
path: root/peer.go
blob: 7e505d68009ed56f9c805ac3dd65674e1f4e9474 (plain) (tree)
1
2
3
4
5
6
7
8
9


           
               
                        
             


                                             

                 
                 






                                                             
                                   
                            

 


                    


                                                                                  




                               


                               




                                   





                                          


                                     
                                             






                                    


              


                                 
 
                                                         


                                   


                                              

 



                                    

                               
                                   
                                                                
         
                                

                                                             
                             





                                                          

























                                                                              
 
                   

                   

                     

                                                           
                            
                            
                           

                      


                                                                     
                                                           
 
                     









                                                                           
                                                       


         
                                                                        
 






                                                                       
                                  
                                                         



                                                                                       

                                                                         
                               
                                                                                    
                                
                              






                                                      
                         






                                               


                                                


















                                                       
                                                                      








                                                                                     
                                                    
                                                       
 








                                                                                       

                                                                     
                                                                                 
 


                                                                             
                                                     



                                                            
                              
                                                                                


















                                                                                            
                                                  

                                                  
                                                   
                                                         
                               
                                                       

                                          



                                                      
 


                                                                                                     

                                               
                                                                                                                 









                                                                                         

                                                                    
 
                                                                               
                                                                       

                                                                                                                                                              
                                                                                                                   
                                                                                                                                              

                                                                                                      
                                                                                                            
                                                                                                                   

                                                                                                                                                   


                                                                                                                                                           
                                                                 
                                                                     


                                                         










                                                                                                                                                            

                                 

                                                                                              
 
                                                                                         

                                                                                             

                                                       
                                                                         

                                                                                                                          
                                                                                         
                                                 


                                                                 
                                         
                                 
 





                                                                            


                                                                                                  
                                                                                                                                  
                                                                    
                                                                                                              
                                                                                 
                                                                        
                                                                    

                                         

                                                                                         
                                                                     
                                                                                          
                                                                                                                                                                           
                                                 
 
                                                                    


                                                                                                   
                                         
                                 
 



                                                                                         
                                                                     

                                                                                               
                                 








                                                                                                     








                                                                                                        
 



                                                                         
 
                                 


                                                                                                       
                                                       
                                                          
                                           
                                             
                                 
 
                                                                           

                                                                            
 


                                                                                                   
                                                                                                                                   
                                                                                               





                                                                         
                                                                                                                                           
                                                                                                                        
                                                           
                                                                                                                                       
                                                                                                             
                                                
                                                                                                                       
                                         
 
                                        
                                                                                                            


                                                                                                            

                                                                                                                                  

                                                     







                                                                                                                                 









                                                                                                 
 

                                                                 
                                                                                                               
                         

                 


                
                        

                                                                                
 



                                                             

         

                                
                                                                                       



                        





                                                      
 








                                                   
                                                                         

                              








                                                                                                          


                                      
                                                       
 
                                                                        
                                                                                                
          





                           
                                            
                                                                     
                              
                                                      



                                                                               

         


                                                                                  
 


                                                                 


                                                  
                     
 
                                               
                                                                                                      



                        
                                                                        



                                                            

                                                
 
                                         

                                                                    
                                
 



                              
 



                                               
 






                                                                                      
                                               













                                                 
         
 
                                                                                                                        
 
 



                                                                      
 



                                        
 




                                                                                                                  
 


                                                     
         
 






                                                                                                                                                                         
                                                  
                          
                                                                                
                                   
                                                                                                      

                                   
                                                                                                                                                             
 

                                                                              


         
                                        
                                                      
 
 
                                                      




                                           
                                                          





                                                        




                                       




                                                       
package eth

import (
    "bytes"
    "container/list"
    "fmt"
    "github.com/ethereum/eth-go/ethchain"
    "github.com/ethereum/eth-go/ethutil"
    "github.com/ethereum/eth-go/ethwire"
    "net"
    "strconv"
    "strings"
    "sync/atomic"
    "time"
)

const (
    // The size of the output buffer for writing messages
    outputBufferSize = 50
    // Current protocol version
    ProtocolVersion = 17
)

type DiscReason byte

const (
    // Values are given explicitly instead of by iota because these values are
    // defined by the wire protocol spec; it is easier for humans to ensure
    // correctness when values are explicit.
    DiscReRequested  = 0x00
    DiscReTcpSysErr  = 0x01
    DiscBadProto     = 0x02
    DiscBadPeer      = 0x03
    DiscTooManyPeers = 0x04
    DiscConnDup      = 0x05
    DiscGenesisErr   = 0x06
    DiscProtoErr     = 0x07
)

var discReasonToString = []string{
    "Disconnect requested",
    "Disconnect TCP sys error",
    "Disconnect bad protocol",
    "Disconnect useless peer",
    "Disconnect too many peers",
    "Disconnect already connected",
    "Disconnect wrong genesis block",
    "Disconnect incompatible network",
}

func (d DiscReason) String() string {
    if len(discReasonToString) < int(d) {
        return "Unknown"
    }

    return discReasonToString[d]
}

// Peer capabilities
type Caps byte

const (
    CapPeerDiscTy = 1 << iota
    CapTxTy
    CapChainTy

    CapDefault = CapChainTy | CapTxTy | CapPeerDiscTy
)

var capsToString = map[Caps]string{
    CapPeerDiscTy: "Peer discovery",
    CapTxTy:       "Transaction relaying",
    CapChainTy:    "Block chain relaying",
}

func (c Caps) IsCap(cap Caps) bool {
    return c&cap > 0
}

func (c Caps) String() string {
    var caps []string
    if c.IsCap(CapPeerDiscTy) {
        caps = append(caps, capsToString[CapPeerDiscTy])
    }
    if c.IsCap(CapChainTy) {
        caps = append(caps, capsToString[CapChainTy])
    }
    if c.IsCap(CapTxTy) {
        caps = append(caps, capsToString[CapTxTy])
    }

    return strings.Join(caps, " | ")
}

type Peer struct {
    // Ethereum interface
    ethereum *Ethereum
    // Net connection
    conn net.Conn
    // Output queue which is used to communicate and handle messages
    outputQueue chan *ethwire.Msg
    // Quit channel
    quit chan bool
    // Determines whether it's an inbound or outbound peer
    inbound bool
    // Flag for checking the peer's connectivity state
    connected  int32
    disconnect int32
    // Last known message send
    lastSend time.Time
    // Indicated whether a verack has been send or not
    // This flag is used by writeMessage to check if messages are allowed
    // to be send or not. If no version is known all messages are ignored.
    versionKnown bool

    // Last received pong message
    lastPong int64
    // Indicates whether a MsgGetPeersTy was requested of the peer
    // this to prevent receiving false peers.
    requestedPeerList bool

    host []byte
    port uint16
    caps Caps

    pubkey []byte

    // Indicated whether the node is catching up or not
    catchingUp      bool
    diverted        bool
    blocksRequested int

    Version string
}

func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer {
    pubkey := ethutil.GetKeyRing().Get(0).PublicKey[1:]

    return &Peer{
        outputQueue:     make(chan *ethwire.Msg, outputBufferSize),
        quit:            make(chan bool),
        ethereum:        ethereum,
        conn:            conn,
        inbound:         inbound,
        disconnect:      0,
        connected:       1,
        port:            30303,
        pubkey:          pubkey,
        blocksRequested: 10,
        caps:            ethereum.ServerCaps(),
    }
}

func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {

    p := &Peer{
        outputQueue: make(chan *ethwire.Msg, outputBufferSize),
        quit:        make(chan bool),
        ethereum:    ethereum,
        inbound:     false,
        connected:   0,
        disconnect:  0,
        caps:        caps,
        Version:     ethutil.Config.ClientString,
    }

    // Set up the connection in another goroutine so we don't block the main thread
    go func() {
        conn, err := net.DialTimeout("tcp", addr, 30*time.Second)

        if err != nil {
            ethutil.Config.Log.Debugln("Connection to peer failed", err)
            p.Stop()
            return
        }
        p.conn = conn

        // Atomically set the connection state
        atomic.StoreInt32(&p.connected, 1)
        atomic.StoreInt32(&p.disconnect, 0)

        p.Start()
    }()

    return p
}

// Outputs any RLP encoded data to the peer
func (p *Peer) QueueMessage(msg *ethwire.Msg) {
    if atomic.LoadInt32(&p.connected) != 1 {
        return
    }
    p.outputQueue <- msg
}

func (p *Peer) writeMessage(msg *ethwire.Msg) {
    // Ignore the write if we're not connected
    if atomic.LoadInt32(&p.connected) != 1 {
        return
    }

    if !p.versionKnown {
        switch msg.Type {
        case ethwire.MsgHandshakeTy: // Ok
        default: // Anything but ack is allowed
            return
        }
    }

    err := ethwire.WriteMessage(p.conn, msg)
    if err != nil {
        ethutil.Config.Log.Debugln("Can't send message:", err)
        // Stop the client if there was an error writing to it
        p.Stop()
        return
    }
}

// Outbound message handler. Outbound messages are handled here
func (p *Peer) HandleOutbound() {
    // The ping timer. Makes sure that every 2 minutes a ping is send to the peer
    pingTimer := time.NewTicker(2 * time.Minute)
    serviceTimer := time.NewTicker(5 * time.Minute)

out:
    for {
        select {
        // Main message queue. All outbound messages are processed through here
        case msg := <-p.outputQueue:
            p.writeMessage(msg)

            p.lastSend = time.Now()

        // Ping timer sends a ping to the peer each 2 minutes
        case <-pingTimer.C:
            p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, ""))

        // Service timer takes care of peer broadcasting, transaction
        // posting or block posting
        case <-serviceTimer.C:
            if p.caps&CapPeerDiscTy > 0 {
                msg := p.peersMessage()
                p.ethereum.BroadcastMsg(msg)
            }

        case <-p.quit:
            // Break out of the for loop if a quit message is posted
            break out
        }
    }

clean:
    // This loop is for draining the output queue and anybody waiting for us
    for {
        select {
        case <-p.outputQueue:
            // TODO
        default:
            break clean
        }
    }
}

// Inbound handler. Inbound messages are received here and passed to the appropriate methods
func (p *Peer) HandleInbound() {

    for atomic.LoadInt32(&p.disconnect) == 0 {
        // HMM?
        time.Sleep(500 * time.Millisecond)
        // Wait for a message from the peer
        msgs, err := ethwire.ReadMessages(p.conn)
        if err != nil {
            ethutil.Config.Log.Debugln(err)
        }
        for _, msg := range msgs {
            switch msg.Type {
            case ethwire.MsgHandshakeTy:
                // Version message
                p.handleHandshake(msg)

                if p.caps.IsCap(CapPeerDiscTy) {
                    p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, ""))
                }
            case ethwire.MsgDiscTy:
                p.Stop()
                ethutil.Config.Log.Infoln("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint()))
            case ethwire.MsgPingTy:
                // Respond back with pong
                p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, ""))
            case ethwire.MsgPongTy:
                // If we received a pong back from a peer we set the
                // last pong so the peer handler knows this peer is still
                // active.
                p.lastPong = time.Now().Unix()
            case ethwire.MsgBlockTy:
                // Get all blocks and process them
                var block, lastBlock *ethchain.Block
                var err error

                // Make sure we are actually receiving anything
                if msg.Data.Len()-1 > 1 && p.diverted {
                    // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find
                    // common ground to start syncing from
                    lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1))
                    ethutil.Config.Log.Infof("[PEER] Last block: %x. Checking if we have it locally.\n", lastBlock.Hash())
                    for i := msg.Data.Len() - 1; i >= 0; i-- {
                        block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
                        // Do we have this block on our chain? If so we can continue
                        if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) {
                            // We don't have this block, but we do have a block with the same prevHash, diversion time!
                            if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) {
                                p.diverted = false
                                if !p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) {
                                    p.SyncWithPeerToLastKnown()
                                }
                                break
                            }
                        }
                    }
                    if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) {
                        // If we can't find a common ancenstor we need to request more blocks.
                        // FIXME: At one point this won't scale anymore since we are not asking for an offset
                        // we just keep increasing the amount of blocks.
                        p.blocksRequested = p.blocksRequested * 2

                        ethutil.Config.Log.Infof("[PEER] No common ancestor found, requesting %d more blocks.\n", p.blocksRequested)
                        p.catchingUp = false
                        p.FindCommonParentBlock()
                        break
                    }
                }

                for i := msg.Data.Len() - 1; i >= 0; i-- {
                    block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))

                    //p.ethereum.StateManager().PrepareDefault(block)
                    //state := p.ethereum.StateManager().CurrentState()
                    err = p.ethereum.StateManager().Process(block, false)

                    if err != nil {
                        if ethutil.Config.Debug {
                            ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash())
                            ethutil.Config.Log.Infof("[PEER] %v\n", err)
                            ethutil.Config.Log.Debugln(block)
                        }
                        break
                    } else {
                        lastBlock = block
                    }
                }

                if msg.Data.Len() == 0 {
                    // Set catching up to false if
                    // the peer has nothing left to give
                    p.catchingUp = false
                }

                if err != nil {
                    // If the parent is unknown try to catch up with this peer
                    if ethchain.IsParentErr(err) {
                        ethutil.Config.Log.Infoln("Attempting to catch up since we don't know the parent")
                        p.catchingUp = false
                        p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
                    } else if ethchain.IsValidationErr(err) {
                        fmt.Println("Err:", err)
                        p.catchingUp = false
                    }
                } else {
                    // If we're catching up, try to catch up further.
                    if p.catchingUp && msg.Data.Len() > 1 {
                        if lastBlock != nil {
                            blockInfo := lastBlock.BlockInfo()
                            ethutil.Config.Log.Debugf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash)
                        }

                        p.catchingUp = false

                        hash := p.ethereum.BlockChain().CurrentBlock.Hash()
                        p.CatchupWithPeer(hash)
                    }
                }

            case ethwire.MsgTxTy:
                // If the message was a transaction queue the transaction
                // in the TxPool where it will undergo validation and
                // processing when a new block is found
                for i := 0; i < msg.Data.Len(); i++ {
                    tx := ethchain.NewTransactionFromValue(msg.Data.Get(i))
                    p.ethereum.TxPool().QueueTransaction(tx)
                }
            case ethwire.MsgGetPeersTy:
                // Flag this peer as a 'requested of new peers' this to
                // prevent malicious peers being forced.
                p.requestedPeerList = true
                // Peer asked for list of connected peers
                p.pushPeers()
            case ethwire.MsgPeersTy:
                // Received a list of peers (probably because MsgGetPeersTy was send)
                // Only act on message if we actually requested for a peers list
                if p.requestedPeerList {
                    data := msg.Data
                    // Create new list of possible peers for the ethereum to process
                    peers := make([]string, data.Len())
                    // Parse each possible peer
                    for i := 0; i < data.Len(); i++ {
                        value := data.Get(i)
                        peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint())
                    }

                    // Connect to the list of peers
                    p.ethereum.ProcessPeerList(peers)
                    // Mark unrequested again
                    p.requestedPeerList = false

                }
            case ethwire.MsgGetChainTy:
                var parent *ethchain.Block
                // Length minus one since the very last element in the array is a count
                l := msg.Data.Len() - 1
                // Ignore empty get chains
                if l == 0 {
                    break
                }

                // Amount of parents in the canonical chain
                //amountOfBlocks := msg.Data.Get(l).AsUint()
                amountOfBlocks := uint64(100)

                // Check each SHA block hash from the message and determine whether
                // the SHA is in the database
                for i := 0; i < l; i++ {
                    if data := msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) {
                        parent = p.ethereum.BlockChain().GetBlock(data)
                        break
                    }
                }

                // If a parent is found send back a reply
                if parent != nil {
                    ethutil.Config.Log.Debugf("[PEER] Found canonical block, returning chain from: %x ", parent.Hash())
                    chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks)
                    if len(chain) > 0 {
                        ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash())
                        p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain))
                    } else {
                        p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{}{}))
                    }

                } else {
                    //ethutil.Config.Log.Debugf("[PEER] Could not find a similar block")
                    // If no blocks are found we send back a reply with msg not in chain
                    // and the last hash from get chain
                    lastHash := msg.Data.Get(l - 1)
                    //log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw())
                    p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()}))
                }
            case ethwire.MsgNotInChainTy:
                ethutil.Config.Log.Debugf("Not in chain: %x\n", msg.Data.Get(0).Bytes())
                if p.diverted == true {
                    // If were already looking for a common parent and we get here again we need to go deeper
                    p.blocksRequested = p.blocksRequested * 2
                }
                p.diverted = true
                p.catchingUp = false
                p.FindCommonParentBlock()
            case ethwire.MsgGetTxsTy:
                // Get the current transactions of the pool
                txs := p.ethereum.TxPool().CurrentTransactions()
                // Get the RlpData values from the txs
                txsInterface := make([]interface{}, len(txs))
                for i, tx := range txs {
                    txsInterface[i] = tx.RlpData()
                }
                // Broadcast it back to the peer
                p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface))

                // Unofficial but fun nonetheless
            case ethwire.MsgTalkTy:
                ethutil.Config.Log.Infoln("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str())
            }
        }
    }
    p.Stop()
}

func (p *Peer) Start() {
    peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String())
    servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String())

    if p.inbound {
        p.host, p.port = packAddr(peerHost, peerPort)
    } else {
        p.host, p.port = packAddr(servHost, servPort)
    }

    err := p.pushHandshake()
    if err != nil {
        ethutil.Config.Log.Debugln("Peer can't send outbound version ack", err)

        p.Stop()

        return
    }

    // Run the outbound handler in a new goroutine
    go p.HandleOutbound()
    // Run the inbound handler in a new goroutine
    go p.HandleInbound()

}

func (p *Peer) Stop() {
    if atomic.AddInt32(&p.disconnect, 1) != 1 {
        return
    }

    close(p.quit)
    if atomic.LoadInt32(&p.connected) != 0 {
        p.writeMessage(ethwire.NewMessage(ethwire.MsgDiscTy, ""))
        p.conn.Close()
    }

    // Pre-emptively remove the peer; don't wait for reaping. We already know it's dead if we are here
    p.ethereum.peerMut.Lock()
    defer p.ethereum.peerMut.Unlock()
    eachPeer(p.ethereum.peers, func(peer *Peer, e *list.Element) {
        if peer == p {
            p.ethereum.peers.Remove(e)
        }
    })
}

func (p *Peer) pushHandshake() error {
    pubkey := ethutil.GetKeyRing().Get(0).PublicKey

    msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
        uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey[1:],
    })

    p.QueueMessage(msg)

    return nil
}

func (p *Peer) peersMessage() *ethwire.Msg {
    outPeers := make([]interface{}, len(p.ethereum.InOutPeers()))
    // Serialise each peer
    for i, peer := range p.ethereum.InOutPeers() {
        // Don't return localhost as valid peer
        if !net.ParseIP(peer.conn.RemoteAddr().String()).IsLoopback() {
            outPeers[i] = peer.RlpData()
        }
    }

    // Return the message to the peer with the known list of connected clients
    return ethwire.NewMessage(ethwire.MsgPeersTy, outPeers)
}

// Pushes the list of outbound peers to the client when requested
func (p *Peer) pushPeers() {
    p.QueueMessage(p.peersMessage())
}

func (p *Peer) handleHandshake(msg *ethwire.Msg) {
    c := msg.Data

    if c.Get(0).Uint() != ProtocolVersion {
        ethutil.Config.Log.Debugln("Invalid peer version. Require protocol:", ProtocolVersion)
        p.Stop()
        return
    }

    // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPS, PORT, PUBKEY]
    p.versionKnown = true

    // If this is an inbound connection send an ack back
    if p.inbound {
        p.pubkey = c.Get(5).Bytes()
        p.port = uint16(c.Get(4).Uint())

        // Self connect detection
        keyPair := ethutil.GetKeyRing().Get(0)
        if bytes.Compare(keyPair.PublicKey, p.pubkey) == 0 {
            p.Stop()

            return
        }

    }

    // Set the peer's caps
    p.caps = Caps(c.Get(3).Byte())
    // Get a reference to the peers version
    p.Version = c.Get(2).Str()

    // Catch up with the connected peer
    if !p.ethereum.IsUpToDate() {
        ethutil.Config.Log.Debugln("Already syncing up with a peer; sleeping")
        time.Sleep(10 * time.Second)
    }
    p.SyncWithPeerToLastKnown()

    ethutil.Config.Log.Debugln("[PEER]", p)
}

func (p *Peer) String() string {
    var strBoundType string
    if p.inbound {
        strBoundType = "inbound"
    } else {
        strBoundType = "outbound"
    }
    var strConnectType string
    if atomic.LoadInt32(&p.disconnect) == 0 {
        strConnectType = "connected"
    } else {
        strConnectType = "disconnected"
    }

    return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps)

}
func (p *Peer) SyncWithPeerToLastKnown() {
    p.catchingUp = false
    p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
}

func (p *Peer) FindCommonParentBlock() {
    if p.catchingUp {
        return
    }

    p.catchingUp = true
    if p.blocksRequested == 0 {
        p.blocksRequested = 20
    }
    blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested)

    var hashes []interface{}
    for _, block := range blocks {
        hashes = append(hashes, block.Hash())
    }

    msgInfo := append(hashes, uint64(len(hashes)))

    ethutil.Config.Log.Infof("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String())

    msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo)
    p.QueueMessage(msg)
}
func (p *Peer) CatchupWithPeer(blockHash []byte) {
    if !p.catchingUp {
        // Make sure nobody else is catching up when you want to do this
        p.catchingUp = true
        msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)})
        p.QueueMessage(msg)

        ethutil.Config.Log.Debugf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr())

        msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{})
        p.QueueMessage(msg)
    }
}

func (p *Peer) RlpData() []interface{} {
    return []interface{}{p.host, p.port, p.pubkey}
}

func packAddr(address, port string) ([]byte, uint16) {
    addr := strings.Split(address, ".")
    a, _ := strconv.Atoi(addr[0])
    b, _ := strconv.Atoi(addr[1])
    c, _ := strconv.Atoi(addr[2])
    d, _ := strconv.Atoi(addr[3])
    host := []byte{byte(a), byte(b), byte(c), byte(d)}
    prt, _ := strconv.Atoi(port)

    return host, uint16(prt)
}

func unpackAddr(value *ethutil.Value, p uint64) string {
    byts := value.Bytes()
    a := strconv.Itoa(int(byts[0]))
    b := strconv.Itoa(int(byts[1]))
    c := strconv.Itoa(int(byts[2]))
    d := strconv.Itoa(int(byts[3]))
    host := strings.Join([]string{a, b, c, d}, ".")
    port := strconv.Itoa(int(p))

    return net.JoinHostPort(host, port)
}