Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

logging neighbors, devp2p hello, eth status info into mysql #16

Merged
merged 43 commits into from
Feb 16, 2018

Conversation

SimonSK
Copy link

@SimonSK SimonSK commented Feb 12, 2018

All commits so far. I was going to submit multiple PRs, but branches kept diverging, so here it is. I will try my best to summarize them below.

Minor changes and other changes related to the last PRs (#13, #14):

  1. Log messages related to sql statements are now moved to Debug (if err) and Trace (if ok)
  2. mysql/mysqldb.py: some changes to sql table schemes
  3. p2p/discover: sql related functions in udp.go are now moved to sql_stmt.go. addNodeMetaInfo is removed as we don't actually care about the node addresses from Neighbors packets.

DEVp2p Hello (p2p package):

  1. p2p/node_info.go
    • The structs used to manage node information and relevant functions are added here.
    • Info struct contains a node's DEVp2p Hello and Ethereum Status info and also keeps track of the most recent db entry's row ID.
    • knownNodeInfos is a struct that wraps a map of Infos. It contains a mutex lock.
    • storeNodeInfo does the following: If a new node (not in the in-memory database): 1. add a new entry to the sql db, 2. get the entry's row ID, 3. store the information in-memory, 4. add the node as a new static node. Else, check if any information (except timestamp and remote_port) changed. If changed, treat it as a new node; otherwise, update the existing db entry.
    • KnownNodes is called by the Javascript Console to print out all node information. I implemented it for debugging purpose.
  2. p2p/rlpx.go
    • doProtoHandshake and readProtocolHandshake in p2p/rlpx.go are modified to return the message received time.
    • doProtoHandshake behavior changed to attempt to read the peer's Hello message before we send out ours. This change is to avoid situations where the peers reject us based on our information before their information reach us.
  3. p2p/rlpx_test.go
    • minor changes to remain consistent with changes made in p2p/rlpx.go
  4. p2p/server.go
    • Line 160: unlike other prepared statements, GetRowIDStmt is made public because the Ethereum protocol manager also uses it.
    • Line 385: p2p/sql_stmt.go:initSql sets up db connection and prepares statements when the p2p server starts.
    • Line 370: p2p/sql_stmt.go:CloseSql closes the statements and db connection when the server stops. It is made public because node package also needs to call it when the p2p server fails to start properly.
    • Line 799: p2p/node_info.go:storeNodeInfo is called inside SetupConn. This is where storing to mysql db and updating in-memory database occur.
    • Line 785: p2p/sql_stmt.go:addNodeMetaInfo is manually called if the handshake fails because the peer said "TooManyPeers".
  5. p2p/sql_stmt.go: sql related functions
    • Line 38: during the init, loadKnownNodeInfos is called to fill the in-memory database with the known information from our sql db. While loading, each node address is added to StaticNodes so that they are re-dialed automatically (currently at the default hardcoded frequency 30s).

Ethereum Status (eth package):

  1. eth/backend.go
    • The protocol manager shares the p2p server's GetRowIDStmt and KnownNodeInfos (in-memory database). It directly accesses the map of node infos (not the knownNodeInfos wrapper) because it won't need the mutex lock (it does not change/add anything new to the map).
  2. eth/handler.go
    • Line 93: Forgot to add this back while reverting the change in the PR log neighbors to database #13
    • Line 164: eth/sql_stmt.go:prepareSqlStmts prepares statements when the eth protocol manager starts.
    • Line 188: eth/sql_stmt.go:closeSqlStmts closes the statements when the manager stops.
    • Line 209: statusDataWrapper is used to pass the peer's status info (with received timestamp and handshake failure error) to the protocol manager.
    • Line 221: eth/node_info.go:storeEthNodeInfo is called. This is where storing to mysql db and updating in-memory database occur.
    • Line 289: eth/node_info.go:storeEthNodeInfo is called when unexpected Status messages arrive.
  3. eth/node_info.go
    • storeEthNodeInfo only considers nodes that are present in the in-memory database. If the current information contains no Eth Status information, add them to the existing node entry. If eth information changed: 1. add a new node entry to the sql db, 2. get the rowid; else, just update the eth information of the existing entry.
  4. eth/peer.go
    • Line 238: validStatus returns true if the peer's status resulted in error because of the specified mismatches.
    • Handshake and readStatus modified to handle statusDataWrapper
  5. eth/sql_stmt.go: sql related functions

internal/web3ext/web3ext.go and node/api.go: to allow calling KnownNodes through the Javascript console

TODOs (added to #15):

  • ORM
  • make re-dial frequency as an configurable option
  • update daofork check

@SimonSK SimonSK requested a review from a team February 12, 2018 01:34
@SimonSK SimonSK mentioned this pull request Feb 12, 2018
21 tasks
p2p/server.go Outdated
&sqlObj.p2pVersion, &sqlObj.clientId, &sqlObj.caps, &sqlObj.listenPort,
&sqlObj.firstHelloAt, &sqlObj.lastHelloAt, &sqlObj.protocolVersion, &sqlObj.networkId,
&sqlObj.firstReceivedTd, &sqlObj.lastReceivedTd, &sqlObj.bestHash, &sqlObj.genesisHash,
&sqlObj.daoForkSupport, &sqlObj.firstStatusAt, &sqlObj.lastStatusAt)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found out I screwed up the order here. This does not match the order used in line 987. &sqlObj.daoForkSupport should be the last column. I will push this change shortly.

@SimonSK SimonSK force-pushed the simonsk/mysql-connect-option branch from 8da924f to 078d872 Compare February 12, 2018 04:41
@SimonSK SimonSK changed the title logging neighbors and devp2p hello info into mysql logging neighbors, devp2p hello, eth status info into mysql Feb 12, 2018
@SimonSK SimonSK force-pushed the simonsk/mysql-connect-option branch from 10d954a to a4e152d Compare February 12, 2018 06:13
@SimonSK SimonSK force-pushed the simonsk/mysql-connect-option branch from 8b0aa09 to a10c7ec Compare February 12, 2018 10:30
@SimonSK
Copy link
Author

SimonSK commented Feb 16, 2018

After performing DAO fork check through BlockHeaders/GetBlockHeaders exchange, dao_fork field on the database and DAOForkSupport field in the Info struct are updated.

  1. The field is changed from bool to a signed int. 1 = true (mainnet), 0 (or NULL on db) = unknown, -1 = false (classic).
  2. eth/node_info.go
    • Line 70~ (storeDAOForkSupportInfo): if current DAOForkSupport is 0, then simply update the existing entry as it is the first time we learned about the node's DAOForkSupport status. Otherwise, if the DAOForkSupport status changed for some reason, add a new entry, copying all other information from the previous entry.

@SimonSK
Copy link
Author

SimonSK commented Feb 16, 2018

If any part of the initial sql preparation (p2p/server.go:385) returns error, the client goes through proper shutdown procedures.
If the db handle exists but a prepared statement variable is null, the client immediately exits using log.Crit.
If the client fails to execute a prepared statement, it logs the error as well as the values that were supposed to be added to the db.

After the changes,

  • Trace: successful event that doesn't involve changing data, like open/closing database handle or preparing statements
  • Debug: successful event that involves changing data, like executing prepared statements
  • Error: failure of those mentioned above 2
  • Crit: failing to initialize/prepare sql related variables or prepared statements missing when expected

@@ -285,13 +296,19 @@ func (p *peer) readStatus(network uint64, status *statusData, genesis common.Has

p.Log().Proto("<<"+ethCodeToString[msg.Code], "receivedAt", unixTime, "obj", status, "size", int(msg.Size), "peer", p.ID())

statusWrapper.ReceivedAt = &msg.ReceivedAt
statusWrapper.Status = &status

if status.GenesisBlock != genesis {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zzma I decided to keep this behavior (as well as checking the error code again in eth/handler.go:216) for now. If these 3 mismatch checks are removed, our node will assume the peer is compatible (e.g. on the same blockchain) and resume other behaviors, such as DAO fork check through BlockHeader exchange. I assume the peer will do the same checks and disconnect us anyways, but I am not sure if that assumption is enough to remove the checks.

@SimonSK
Copy link
Author

SimonSK commented Feb 16, 2018

Another TODO added to #15 is removing case-study style log messages from node-finder.
That was the first thing I brought from case-study thinking it would be useful, but now I find it too much.
I plan to remove them in the next PR, which will also include the following two:

  • make re-dial frequency as an configurable option
  • call all sql execution functions as go routine

@SimonSK SimonSK merged commit 9854e53 into node-finder-master Feb 16, 2018
@SimonSK SimonSK deleted the simonsk/mysql-connect-option branch February 16, 2018 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant