neo-go/pkg/peer
decentralisedkev 30e5aa8f48
Add Chain saving functionality to Database (#206)
* [database]

- Add Prefix method to interface
- Convert leveldb error to `database error`
- Be explicit with prefixedKey in `Table` as slices can be pointers

* [protocol]
- Add stringer method to protocol

* [Chaindb]

- Added saveBlock() which will allow us to save a block into the
database. The block is broken up into transactions and Headers. The
headers are saved as is. The transactions are saved as is, then the
utxos in the transactions are collected to make the utxo db.

- Verification for blocks and transactions will reside in the same
package. Note that the save methods are all unexported, while the Get
methods are exported. Making it so that any can call a get method, but
only code in this package may save to the database. The other code which
will reside in this package will be code verification logic.

* [chaindb]

- Added saveHeader function which saveHeaders  uses

- Update the latest header, each time we save a header instead of after a batch. This is so that we can call saveHeader without saveHeaders. This functionality can be rolled back if the performance of updating the header after a batch is significant

- small refactor in test code
2019-03-23 16:57:05 +00:00
..
stall VM: Add basic vm (#166) 2019-03-18 21:40:21 +00:00
config.go Fix lint errors (#182) 2019-03-17 18:26:35 +00:00
peer.go Add Chain saving functionality to Database (#206) 2019-03-23 16:57:05 +00:00
peer_test.go Initial commit 2019-02-25 22:44:14 +00:00
peerhandshake.go Fix lint errors (#182) 2019-03-17 18:26:35 +00:00
readme.md Initial commit 2019-02-25 22:44:14 +00:00

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.