Warning: This is the beginning of an unfinished draft. Don't continue reading!
Adversarial nodes may have the incentive to lie to a lightclient about the state of a Tendermint blockchain. An attempt to do so is called attack. Light client verification checks incoming data by checking a so-called "commit", which is a forwarded set of signed messages that is (supposedly) produced during executing Tendermint consensus. Thus, an attack boils down to creating and signing Tendermint consensus messages in deviation from the Tendermint consensus algorithm rules.
As Tendermint consensus and light client verification is safe under the assumption of more than 2/3 of correct voting power per block [TMBC-FM-2THIRDS], this implies that if there was an attack then [TMBC-FM-2THIRDS] was violated, that is, there is a block such that
In the case of an attack, the lightclient attack detection mechanism computes data, so called evidence [LC-DATA-EVIDENCE.1], that can be used
This specification considers how a full node in a Tendermint blockchain can isolate a set of attackers that launched the attack. The set should satisfy
TODO when preparing a version for broader review.
For definitions of data structures used here, in particular LightBlocks [LCV-DATA-LIGHTBLOCK.1], cf. Light Client Verification.
The specification of the detection mechanism describes
type LightClientAttackEvidence struct {
ConflictingBlock LightBlock
CommonHeight int64
}
The isolator is a function that gets as input evidence ev
and a prefix of the blockchain bc
at least up to height ev.ConflictingBlock.Header.Height + 1
. The output is a set of peerIDs of validators.
We assume that the full node is synchronized with the blockchain and has reached the height ev.ConflictingBlock.Header.Height + 1
.
When an output is generated it satisfies the following properties:
bc[CommonHeight].bfttime
is within the unbonding period w.r.t. the time at the full node,ev.ConflictingBlock.Header != bc[ev.ConflictingBlock.Header.Height]
ev.ConflictingBlock.Commit
represent more than 1/3 of the voting power in bc[ev.CommonHeight].NextValidators
bc[CommonHeight].NextValidators
that
bc[ev.commonHeight].NextValidators
ev.ConflictingBlock.Header.Height
by violating the Tendermint consensus protocol.Here we discuss how to solve the problem of isolating misbehaving processes. We describe the function isolateMisbehavingProcesses
as well as all the helping functions below. In Part V, we discuss why the solution is complete based on result from analysis with automated tools.
Describe solution (in English), decomposition into functions, where communication to other components happens.
func isolateMisbehavingProcesses(ev LightClientAttackEvidence, bc Blockchain) []ValidatorAddress {
reference := bc[ev.conflictingBlock.Header.Height].Header
ev_header := ev.conflictingBlock.Header
ref_commit := bc[ev.conflictingBlock.Header.Height + 1].Header.LastCommit // + 1 !!
ev_commit := ev.conflictingBlock.Commit
if violatesTMValidity(reference, ev_header) {
// lunatic light client attack
signatories := Signers(ev.ConflictingBlock.Commit)
bonded_vals := Addresses(bc[ev.CommonHeight].NextValidators)
return intersection(signatories,bonded_vals)
}
// If this point is reached the validator sets in reference and ev_header are identical
else if RoundOf(ref_commit) == RoundOf(ev_commit) {
// equivocation light client attack
return intersection(Signers(ref_commit), Signers(ev_commit))
}
else {
// amnesia light client attack
return IsolateAmnesiaAttacker(ev, bc)
}
}
ev.conflictingBlock.Header.Height
then bc[ev.conflictingBlock.Header.Height + 1].Header.LastCommit
refers to the locally stored commit for this height. (This commit must be present by the precondition on length(bc)
.)length(bc) >= ev.conflictingBlock.Header.Height
ValidAndVerifiedUnbonding(bc[ev.CommonHeight], ev.ConflictingBlock) == SUCCESS
ev.ConflictingBlock.Header != bc[ev.ConflictingBlock.Header.Height]
func ValidAndVerifiedUnbonding(trusted LightBlock, untrusted LightBlock) Result
trusted.Header.Time > now - UnbondingPeriod
func violatesTMValidity(ref Header, ev Header) boolean
ev
violates the validity property of Tendermint Consensus, by checking agains a reference headerref.Height == ev.Height
ref.ValidatorsHash != ev.ValidatorsHash
orref.NextValidatorsHash != ev.NextValidatorsHash
orref.ConsensusHash != ev.ConsensusHash
orref.AppHash != ev.AppHash
orref.LastResultsHash != ev.LastResultsHash
func IsolateAmnesiaAttacker(ev LightClientAttackEvidence, bc Blockchain) []ValidatorAddress
func RoundOf(commit Commit) []ValidatorAddress
commit
is well-formed. In particular all votes are from the same round r
.r
that is encoded in all the votes of the commitfunc Signers(commit Commit) []ValidatorAddress
commit
func Addresses(vals Validator[]) ValidatorAddress[]
vals
As discussed in the beginning of this document, an attack boils down to creating and signing Tendermint consensus messages in deviation from the Tendermint consensus algorithm rules.
The main function isolateMisbehavingProcesses
distinguishes three kinds of wrongly signing messages, namely,
The question is whether this captures all attacks.
First observe that the first checking in isolateMisbehavingProcesses
is violatesTMValidity
. It takes care of lunatic attacks. If this check passes, that is, if violatesTMValidity
returns FALSE
this means that [FN-NONVALID-OUTPUT] evaluates to false, which implies that ref.ValidatorsHash = ev.ValidatorsHash
. Hence after violatesTMValidity
, all the involved validators are the ones from the blockchain. It is thus sufficient to analyze one instance of Tendermint consensus with a fixed group membership (set of validators). Also it is sufficient to consider two different valid consensus values, that is, binary consensus.
TODO we have analyzed Tendermint consensus with TLA+ and have accompanied Galois in an independent study of the protocol based on Ivy proofs.
[supervisor] The specification of the light client supervisor.
[verification] The specification of the light client verification protocol
[detection] The specification of the light client attack detection mechanism.