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

[ADR -44] Lite Client with Weak Subjectivity #3795

Merged
merged 13 commits into from
Aug 15, 2019
Merged

Conversation

zmanian
Copy link
Contributor

@zmanian zmanian commented Jul 13, 2019

ADR for Lite Client with Weak Subjectivity ADR.

Closes #2133

Implementation in #3577

with weak subjectivity ADR
@codecov-io
Copy link

codecov-io commented Jul 13, 2019

Codecov Report

Merging #3795 into master will decrease coverage by 0.04%.
The diff coverage is n/a.

@@            Coverage Diff            @@
##           master   #3795      +/-   ##
=========================================
- Coverage   65.65%   65.6%   -0.05%     
=========================================
  Files         217     217              
  Lines       18198   18202       +4     
=========================================
- Hits        11948   11942       -6     
- Misses       5382    5389       +7     
- Partials      868     871       +3
Impacted Files Coverage Δ
privval/signer_server.go 95.65% <0%> (-4.35%) ⬇️
consensus/ticker.go 91.66% <0%> (-4.17%) ⬇️
consensus/metrics.go 15.17% <0%> (-1.83%) ⬇️
lite/dynamic_verifier.go 66.96% <0%> (-1.37%) ⬇️
blockchain/v0/pool.go 80% <0%> (-0.99%) ⬇️
consensus/reactor.go 76.78% <0%> (-0.47%) ⬇️
p2p/pex/pex_reactor.go 83.76% <0%> (+1.73%) ⬆️
privval/signer_listener_endpoint.go 89.13% <0%> (+2.17%) ⬆️
privval/signer_endpoint.go 84% <0%> (+5.33%) ⬆️

@tac0turtle tac0turtle changed the title Lite Client with Weak Subjectivity ADR [ADR -44] Lite Client with Weak Subjectivity Jul 14, 2019
Copy link
Contributor

@tac0turtle tac0turtle left a comment

Choose a reason for hiding this comment

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

Quick run through, will do another tomorrow.

Co-Authored-By: Marko <marbar3778@yahoo.com>
Copy link
Contributor

@melekes melekes left a comment

Choose a reason for hiding this comment

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

Great post! However, the choice of the concrete data structures (Provider, UpdatingProvider, ConcurrentProvider, DBProvider, MultiProvider) is still not clear to me. Like why there are so many of them? Could not we just expose two? One for linear verification and one for bisecting verification OR even make this an option. Thanks!

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

Nice! Should we combine this / #3796 / #3710?

I think we can offload more work to the full node in the bisection algorithm.

Changelog:
- 13-07-2019: Initial Draft
## Context
The concept of light clients was introduced in the Bitcoin white paper. It describes a watcher of distributed consensus process that only validates the consensus algorithm and not the state machine transactions within.
Copy link
Contributor

Choose a reason for hiding this comment

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

Two things to note:

  • Light clients are expected to agree with full nodes on the canonical chain
  • Tendermint provides a somewhat different (stronger) light client model under eclipse, since the eclipsing node(s) can only fool the light client if they have two-thirds of the private keys from the last root of trust.


Tendermint light clients allow light weight devices and other blockchains to efficiently verify the consensus of a Tendermint blockchain. This forms the basic of safe and efficient state synchronization for new network nodes and InterBlockchain Communication.

In a network that is expected to reliably punish validators for misbehavior through punishments or where the validator set is largely trusted and changes infrequently, clients can take advantage of this assumption to safely synchronize a lite client without downloading the intervening headers.
Copy link
Contributor

Choose a reason for hiding this comment

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

"largely trusted" is a bit vague. I think both conditions are necessary - only if misbehaviour is punished and validator set changes are infrequent can a light client skip most of the headers. Note also that the state machine can enforce limits on validator set liquidity, which might be useful to provide tighter efficiency/safety bounds.


In a network that is expected to reliably punish validators for misbehavior through punishments or where the validator set is largely trusted and changes infrequently, clients can take advantage of this assumption to safely synchronize a lite client without downloading the intervening headers.

Light clients (and full nodes) operating in the Proof Of Stake context need a trusted block height from a trusted source that is no older than 1 unbending window. This is called “weak subjectivity”
Copy link
Contributor

Choose a reason for hiding this comment

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

We should explain why one unbonding window (and I think it should be one unbonding window minus delta, where delta is a parameter set according to the expected synchrony bounds for the light client to be able to report evidence)

```

## Linear Verification
The linear verification of the light client requires downloading all headers between the `TrustHeight` and the `LatestHeight`. The lite client downloads the full header for the provided `TrustHeight` and then proceeds to download `N+1` headers and applies the [Tendermint validation rules](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#validation) to each block.
Copy link
Contributor

Choose a reason for hiding this comment

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


## Bisecting Verification

Bisecting Verification is a more bandwidth and compute intensive mechanism that in the most optimistic case requires a light client to only download two block headers to come into synchronization.
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a less bandwidth and compute-intensive mechanism, right?

We can bound the number of headers precisely if we make assumptions about validator set liquidity.


The Bisection algorithm proceeds in the following fashion. The client downloads and verifies the full block header for `TrustHeight` and then fetches `LastestHeight` blocker header. The client then verifies the `LatestHeight` header. Finally the client attempts to verify the `LatestHeight` header with voting powers taken from `NextValdiatorSet` in the `TrustHeight` header. This will verification will succeed if that validators from `TrustHeight` still have > 2/3 +1 of voting power in the `LatestHeight`. If this succeeds, the client is fully synchronized. If this fails, then following Bisection Algorithm should be followed.

The Client tries to download the block at the mid-point block between `LatestHeight` and `TrustHeight` and attempts that same algorithm as above using `MidPointHeight` instead of `LatestHeight`. In the case the of failure, recursively perform the `MidPoint` verification until success then start over with an updated `NextValidatorSet` and `TrustHeight`.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would note that it's safe to ask the full node to provide the specific headers that the client needs, given the root of trust height that it has. Should we do that instead? The full node has to track a bit more, but further reduces bandwidth / compute for the light client.

zmanian and others added 2 commits July 15, 2019 08:18
Co-Authored-By: Christopher Goes <cwgoes@pluranimity.org>
Co-Authored-By: Christopher Goes <cwgoes@pluranimity.org>

Bisecting Verification is a more bandwidth and compute intensive mechanism that in the most optimistic case requires a light client to only download two block headers to come into synchronization.

The Bisection algorithm proceeds in the following fashion. The client downloads and verifies the full block header for `TrustHeight` and then fetches `LastestHeight` blocker header. The client then verifies the `LatestHeight` header. Finally the client attempts to verify the `LatestHeight` header with voting powers taken from `NextValdiatorSet` in the `TrustHeight` header. This will verification will succeed if that validators from `TrustHeight` still have > 2/3 +1 of voting power in the `LatestHeight`. If this succeeds, the client is fully synchronized. If this fails, then following Bisection Algorithm should be followed.
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that +2/3 in the new validator set is not sufficient to establish trust of the new validator set as total voting power of new validators and potential adversary set of the old set could be bigger than +1/3 of total voting power. See #3710.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So it seems like we should say that in order for bisection to take place, the total voting power of the new block must be greater or equal to the total voting power of the last trusted block to prevent this attack correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's more complex than that. Total voting power of new validators together with 1/3 of voting power of old validators that are also present in new validator set must be in total at most 1/3 of voting power in the new val set.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay here is my proposed check.

After current checks for if LatestHeight is valid in it's own terms, if LatestHeight is valid in terms of TrustedHeight.NextValidatorSet we compute the following. Take the sum of the following, for each validator abs((LatestHeightVotingPower/LatestHeightTotalPower)-TrustedHeightVotingPower/TrustedHeightTotalPower)). if this value is greater than 1/3rd, fail for the height.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm still somewhat split if we want to have this check in the presence of counterfactual slashing.

It does confuse the incentive layers a bit, but counterfactual slashing does ensure that any attack using this kind of change of voting powers is still slashable.

Copy link
Contributor

Choose a reason for hiding this comment

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

I still have trouble to see link between counterfactual slashing and the checks about validator power change, i.e., how we can get rid of checks in the presence of counterfactual slashing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So an attacker who wants to exploit this vulnerability needs signatures from 2/3rd from the TrustedSet. in attack these signatures are either equivocations or counterfactual signatures.

zmanian and others added 2 commits July 15, 2019 13:15
Co-Authored-By: Anca Zamfir <ancazamfir@users.noreply.github.com>
@jaekwon
Copy link
Contributor

jaekwon commented Jul 22, 2019

Great post! However, the choice of the concrete data structures (Provider, UpdatingProvider, ConcurrentProvider, DBProvider, MultiProvider) is still not clear to me. Like why there are so many of them? Could not we just expose two? One for linear verification and one for bisecting verification OR even make this an option. Thanks!

I think it just needs a bit of documentation, but otherwise that the separation potentially makes things easier to maintain and understand. For example, it isn't necessary to know how a Provider works underneath the hood to understand how ConcurrentProvider works. Similarly, I like to add caching as a layer, as MultiProvider lets you do w/ DBProviders. Each is solving an orthogonal concern, and can get composed. Otherwise we'd eventually end up with two very-complicated struct implementations that would otherwise be hard to tease out (e.g. not-same-but-similar criticism as Tendermint's consensus state not being split out). But not all of these need to be exposed to the user... It would be sufficient to keep the internal unexposed implementation based on these components, but only expose things that external users need to know.

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

A few more minor suggestions, and I think it would be nice to link this to the formal bisection safety spec (once merged, or leave a pointer to be linked in the future).

Co-Authored-By: Christopher Goes <cwgoes@pluranimity.org>
@melekes
Copy link
Contributor

melekes commented Aug 14, 2019

@cwgoes: thanks for the thorough review 👍

@melekes melekes requested a review from cwgoes August 15, 2019 06:49
@tac0turtle tac0turtle merged commit 7b101ab into master Aug 15, 2019
@tac0turtle tac0turtle deleted the zaki/liteclientADR branch August 15, 2019 09:50
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.

Create an ADR for lite/provider
8 participants