67 lines
2.9 KiB
Markdown
67 lines
2.9 KiB
Markdown
|
# Package - Peer
|
||
|
|
||
|
|
||
|
|
||
|
## Responsibility
|
||
|
|
||
|
Once a connection has been made. The connection will represent a established peer to the localNode. Since a connection and the `Wire` is a golang primitive, that we cannot do much with. The peer package will encapsulate both, while adding extra functionality.
|
||
|
|
||
|
|
||
|
## Features
|
||
|
|
||
|
- The handshake protocol is automatically executed and handled by the peer package. If a Version/Verack is received twice, the peer will be disconnected.
|
||
|
|
||
|
- IdleTimeouts: If a Message is not received from the peer within a set period of time, the peer will be disconnected.
|
||
|
|
||
|
- StallTimeouts: For Example, If a GetHeaders, is sent to the Peer and a Headers Response is not received within a certain period of time, then the peer is disconnected.
|
||
|
|
||
|
- Concurrency Model: The concurrency model used is similar to Actor model, with a few changes. Messages can be sent to a peer asynchronously or synchronously. An example of an synchornous message send is the `RequestHeaders` method, where the channel blocks until an error value is received. The `OnHeaders` message is however asynchronously called. Furthermore, all methods passed through the config, are wrapped inside of an additional `Peers` method, this is to lay the ground work to capturing statistics regarding a specific command. These are also used so that we can pass behaviour to be executed down the channel.
|
||
|
|
||
|
- Configuration: Each Peer will have a config struct passed to it, with information about the Local Peer and functions that will encapsulate the behaviour of what the peer should do, given a request. This way, the peer is not dependent on any other package.
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
conn, err := net.Dial("tcp", "seed2.neo.org:10333")
|
||
|
if err != nil {
|
||
|
fmt.Println("Error dialing connection", err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
config := peer.LocalConfig{
|
||
|
Net: protocol.MainNet,
|
||
|
UserAgent: "NEO-G",
|
||
|
Services: protocol.NodePeerService,
|
||
|
Nonce: 1200,
|
||
|
ProtocolVer: 0,
|
||
|
Relay: false,
|
||
|
Port: 10332,
|
||
|
StartHeight: LocalHeight,
|
||
|
OnHeader: OnHeader,
|
||
|
}
|
||
|
|
||
|
p := peer.NewPeer(conn, false, config)
|
||
|
err = p.Run()
|
||
|
|
||
|
hash, err := util.Uint256DecodeString(chainparams.GenesisHash)
|
||
|
// hash2, err := util.Uint256DecodeString("ff8fe95efc5d1cc3a22b17503aecaf289cef68f94b79ddad6f613569ca2342d8")
|
||
|
err = p.RequestHeaders(hash)
|
||
|
|
||
|
func OnHeader(peer *peer.Peer, msg *payload.HeadersMessage) {
|
||
|
// This function is passed to peer
|
||
|
// and the peer will execute it on receiving a header
|
||
|
}
|
||
|
|
||
|
func LocalHeight() uint32 {
|
||
|
// This will be a function from the object that handles the block heights
|
||
|
return 10
|
||
|
}
|
||
|
|
||
|
|
||
|
### Notes
|
||
|
|
||
|
|
||
|
Should we follow the actor model for Peers? Each Peer will have a ID, which we can take as the PID or if
|
||
|
we launch a go-routine for each peer, then we can use that as an implicit PID.
|
||
|
|
||
|
Peer information should be stored into a database, if no db exists, we should get it from an initial peers file.
|
||
|
We can use this to periodically store information about a peer.
|