-
Notifications
You must be signed in to change notification settings - Fork 17
incentivization
The original idea of blockchain is a permissionless peer-to-peer network, where anybody can participate if he only runs a node and sync with the other peers. Why this is still true, we know that such a node won't run on a small iot-device.
This is why a lot of users try remote-nodes to server their devices. But this introduces a new single-point of failure and the risk of man-in-the-middle attacks.
So the first step is decentralizing remote nodes by sharing rpc-nodes with other apps.
While this removes the single point of failure it introduces the risc of trust. We cannot simply trust other RPC-nodes. In order to turn this into a trustless Architecture, each Server needs to provide verifiable proofs. (for Details See Ethereum Verification and MerkleProof )
In order to incentivize a node to serve requests to clients there must be something to gain (payment) or to lose ( access to other nodes for it's clients ).
As a simple rule we can define:
The incubed network will serve your client requests, if you also run a honest node.
This requires to connect a client key (used to sign his requests) with a registered server. clients are able to share keys as long as the owner of the node is able to ensure their security. This makes it possible to use one key for the same mobile app or device. The owner may also register as many keys as he wants for his server or even change them from time to time. (as long as only one client key points to one server) The key is registered in a client-contract, holding a mapping from the key to the server-address.
Connecting a client key to a server does not mean he relies on it, but simply his requests will be serverd in the same quality as the connected node will serve other clients. This creates a very strong incentive to deliver all clients, because if a server node would be offline or refuses to deliver, eventually other nodes would also deliver less or even stop responding to requests coming from the connected clients.
To actually figure out which node delivers to clients, each server node will use one of the client keys to send Test-Requests and measure the Availability based on verified responses.
The servers will measure the
Based on the longtime ( >1 day ) and shorttime ( <1 day ) availibility the score is calculated:
-
$A_{long}$ - tha ratio between valid request received and sent within the last month -
$A_{short}$ - tha ratio between valid request received and sent within the last 24h -
$weight$ - the weight of the incoming request from that servers clients (See LoadBalancing) -
$C_{max}$ the maximal Number of open Requests the server can handle ( will be taken from the rergistry )
This score is then used as priority, for incoming requests. this is done by keeping Track of the number of currently open or serving requests. Whenever a new Requests comes in, the node will do the following:
- check the signature
- calculate the score based on the score of the node it is connected with.
- accept or reject the request
if ( score < openRequests ) reject()
This way nodes will reject requests with a lower score when load is increasing. For a client this means if I have a low score and the load in the network is high, my clients may get rejected often and so have to wait longer for responses. And if I have a score of 0, they even will be blacklisted.
In a optimal network each server would handle the same amount as he servers and all clients would have a equal share. In order to prevent situations where 80% of the requests come from clients belonging to the same node while the node is only delivering 10% of requests in the network, we need to decrease the score for clients sending more requests than their shares. So for each node the weight can be calculated by:
-
$R_n$ - number of request serverd to one of the clients connected to the node -
${\displaystyle\sum_{i=0}^n} R_i$ - total number of request serverd -
${\displaystyle\sum_{i=0}^n} C_i$ - total number of capacities of the registered servers -
$C_n$ - Capacity of the registered node
Each node will update the
The Capacity of a node is the maximal number of parall request it can handle and is stored in the ServerRegistry. This way all client know the cap and will weight the nodes accordingly which leads to more load to stronger servers. A node declaring a high capacity will gain a higher score and so its clients will get more reliable responses, but on the other hand if you can not deliver the load you may lose your availibility and so you score.
Each node may allow free access for clients without any signature. A special option --freeScore=2
is used when starting the server. For any client requests without a signature this this
if (!signature) score = conf.freeScroe
A low value for freeScore would server requests only if the current load or the open requests are less then this number, which would mean, that getting a response from the network without signing may take very long because this client would send a lot of requests until he is lucky enough to get a response if the load is high. The chances are a lot better if the load is very low.
Even though servers are allowed to register without a deposit, convicting is still a hard punishment. Because in this case the server is not part of the regikstry anymore and all his connected clients would be treated as without signature. In this case his devices or app will propably stop working or be exremly slow. (depending on the freeScore configured in the all the nodes)
In case of a conflict, each client has now at least one server he knows he can trust, since it is run by the same owner. This makes it impossible for attackers to use Blacklist-Attacks or other threats which can be solved by requiring a response from the "home"-node.