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

feat: Make voter electing staisfy finality #123

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ jobs:
name: run localnet and exit on failure
command: |
set -x
docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang:1.14.1-alpine /bin/sh -c "apk add --update git make gcc libc-dev build-base && make build"
make build-linux
make localnet-start &
./scripts/localnet-blocks-test.sh 40 5 10 localhost

Expand Down Expand Up @@ -370,7 +370,7 @@ jobs:
./scripts/get_nodejs.sh
# build the binaries with a proper version of Go
# Build Tendermint
docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang:1.14.1-alpine /bin/sh -c "apk add --update git make gcc libc-dev build-base && make build"
make build-linux
# Build contract-tests
docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint ubuntu:20.10 ./scripts/prepare_dredd_test.sh
# This docker image works with go 1.7, we can install here the hook handler that contract-tests is going to use
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- uses: actions/cache@v1
with:
path: ~/go/bin
key: ${{ runner.os }}-go-tm-binary
key: ${{ runner.os }}-go-tm-binary-${{ hashFiles('**/*.go', '**/go.sum', 'Makefile') }}

test_abci_apps:
runs-on: ubuntu-latest
Expand All @@ -43,7 +43,7 @@ jobs:
- uses: actions/cache@v1
with:
path: ~/go/bin
key: ${{ runner.os }}-go-tm-binary
key: ${{ runner.os }}-go-tm-binary-${{ hashFiles('**/*.go', '**/go.sum', 'Makefile') }}
- name: test_abci_apps
run: abci/tests/test_app/test.sh
shell: bash
Expand All @@ -60,7 +60,7 @@ jobs:
- uses: actions/cache@v1
with:
path: ~/go/bin
key: ${{ runner.os }}-go-tm-binary
key: ${{ runner.os }}-go-tm-binary-${{ hashFiles('**/*.go', '**/go.sum', 'Makefile') }}
- run: abci/tests/test_cli/test.sh
shell: bash

Expand All @@ -76,7 +76,7 @@ jobs:
- uses: actions/cache@v1
with:
path: ~/go/bin
key: ${{ runner.os }}-go-tm-binary
key: ${{ runner.os }}-go-tm-binary-${{ hashFiles('**/*.go', '**/go.sum', 'Makefile') }}
- name: test_apps
run: test/app/test.sh
shell: bash
60 changes: 60 additions & 0 deletions CHANGELOG_OF_TENDERMINT.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
# Changelog

## v0.33.6

*July 2, 2020*

This security release fixes:

### Denial of service

Tendermint 0.33.0 and above allow block proposers to include signatures for the
wrong block. This may happen naturally if you start a network, have it run for
some time and restart it **without changing the chainID**. (It is a
[misconfiguration](https://docs.tendermint.com/master/tendermint-core/using-tendermint.html)
to reuse chainIDs.) Correct block proposers will accidentally include signatures
for the wrong block if they see these signatures, and then commits won't validate,
making all proposed blocks invalid. A malicious validator (even with a minimal
amount of stake) can use this vulnerability to completely halt the network.

Tendermint 0.33.6 checks all the signatures are for the block with +2/3
majority before creating a commit.

### False Witness

Tendermint 0.33.1 and above are no longer fully verifying commit signatures
during block execution - they stop after +2/3. This means proposers can propose
blocks that contain valid +2/3 signatures and then the rest of the signatures
can be whatever they want. They can claim that all the other validators signed
just by including a CommitSig with arbitrary signature data. While this doesn't
seem to impact safety of Tendermint per se, it means that Commits may contain a
lot of invalid data.

_This was already true of blocks, since they could include invalid txs filled
with garbage, but in that case the application knew that they are invalid and
could punish the proposer. But since applications didn't--and don't--
verify commit signatures directly (they trust Tendermint to do that),
they won't be able to detect it._

This can impact incentivization logic in the application that depends on the
LastCommitInfo sent in BeginBlock, which includes which validators signed. For
instance, Gaia incentivizes proposers with a bonus for including more than +2/3
of the signatures. But a proposer can now claim that bonus just by including
arbitrary data for the final -1/3 of validators without actually waiting for
their signatures. There may be other tricks that can be played because of this.

Tendermint 0.33.6 verifies all the signatures during block execution.

_Please note that the light client does not check nil votes and exits as soon
as 2/3+ of the signatures are checked._

**All clients are recommended to upgrade.**

Special thanks to @njmurarka at Bluzelle Networks for reporting this.

Friendly reminder, we have a [bug bounty
program](https://hackerone.com/tendermint).

### SECURITY:

- [consensus] Do not allow signatures for a wrong block in commits (@ebuchman)
- [consensus] Verify all the signatures during block execution (@melekes)

## v.0.33.5

Special thanks to our external contributor on this release: @tau3
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
- Apps

- P2P Protocol

- Go API

- Blockchain Protocol
- [consensus] [\#101](https://github.com/line/tendermint/pull/101) Introduce composite key to delegate features to each function key

### FEATURES:

Expand Down
40 changes: 39 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,47 @@ build-docker:
### Local testnet using docker ###
###############################################################################

DOCKER_HOME = /go/src/github.com/tendermint/tendermint
DOCKER_CMD = docker run --rm \
-v `pwd`:$(DOCKER_HOME) \
-w $(DOCKER_HOME)
DOCKER_IMG = golang:1.14.6-alpine3.12
BUILD_CMD = apk add --update --no-cache git make gcc libc-dev build-base curl jq file gmp-dev clang \
&& cd crypto/bls/internal/bls-eth-go-binary \
&& make CXX=clang++ \
&& cd $(DOCKER_HOME) \
&& go mod edit -replace github.com/herumi/bls-eth-go-binary=./crypto/bls/internal/bls-eth-go-binary \
&& make build \
&& go mod edit -dropreplace github.com/herumi/bls-eth-go-binary

# Login docker-container for confirmation building linux binary
build-shell:
$(DOCKER_CMD) -it --entrypoint '' ${DOCKER_IMG} /bin/sh
.PHONY: build-shell

# Build linux binary on other platforms

build-linux:
docker run --rm -v `pwd`:/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang:1.14.1-alpine /bin/sh -c "apk add --update git make gcc libc-dev build-base && make build"
# Download, build and add the BSL local library to modules
if [ ! -d $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary ]; then \
mkdir -p $(SRCPATH)/crypto/bls/internal && \
git clone https://github.com/herumi/mcl $(SRCPATH)/crypto/bls/internal/mcl && \
cd $(SRCPATH)/crypto/bls/internal/mcl && \
git reset --hard 10621c6299d3db1c88fd0c27e63654edada08049 && \
git clone https://github.com/herumi/bls $(SRCPATH)/crypto/bls/internal/bls && \
git clone https://github.com/herumi/bls-eth-go-binary $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary && \
cd $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary && \
git reset --hard 41fc56eba7b48e65e410ef11cf5042d62e887017 && \
cd $(SRCPATH); \
fi

# Build Linux binary
$(DOCKER_CMD) ${DOCKER_IMG} /bin/sh -c "$(BUILD_CMD)"

# Remove the BLS local library from modules
rm -rf $(SRCPATH)/crypto/bls/internal/mcl
rm -rf $(SRCPATH)/crypto/bls/internal/bls
rm -rf $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary
.PHONY: build-linux

build-docker-localnode:
Expand Down
2 changes: 1 addition & 1 deletion abci/example/kvstore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ and the Handshake allows any necessary blocks to be replayed.
Validator set changes are effected using the following transaction format:

```
"val:pubkey1!power1,pubkey2!power2,pubkey3!power3"
"val:composite!pubkey1!power1,composite!pubkey2!power2,composite!pubkey3!power3"
```

where `pubkeyN` is a base64-encoded 32-byte ed25519 key and `powerN` is a new voting power for the validator with `pubkeyN` (possibly a new one).
Expand Down
13 changes: 11 additions & 2 deletions abci/example/kvstore/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@ package kvstore

import (
"github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/composite"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmtypes "github.com/tendermint/tendermint/types"
)

// Generates a default private key for use in an example or test.
func GenDefaultPrivKey() crypto.PrivKey {
return composite.GenPrivKey()
}

// RandVal creates one random validator, with a key derived
// from the input value
func RandVal(i int) types.ValidatorUpdate {
pubkey := tmrand.Bytes(32)
pk := GenDefaultPrivKey().PubKey()
pubkey := tmtypes.TM2PB.PubKey(pk)
power := tmrand.Uint16() + 1
v := types.Ed25519ValidatorUpdate(pubkey, int64(power))
v := types.NewValidatorUpdate(tmtypes.ABCIPubKeyTypeComposite, pubkey.Data, int64(power))
return v
}

Expand Down
22 changes: 12 additions & 10 deletions abci/example/kvstore/persistent_kvstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/tendermint/tendermint/abci/example/code"
"github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
)
Expand Down Expand Up @@ -167,26 +166,25 @@ func (app *PersistentKVStoreApplication) Validators() (validators []types.Valida

func MakeValSetChangeTx(pubkey types.PubKey, power int64) []byte {
pubStr := base64.StdEncoding.EncodeToString(pubkey.Data)
return []byte(fmt.Sprintf("val:%s!%d", pubStr, power))
return []byte(fmt.Sprintf("val:%s!%s!%d", pubkey.Type, pubStr, power))
}

func isValidatorTx(tx []byte) bool {
return strings.HasPrefix(string(tx), ValidatorSetChangePrefix)
}

// format is "val:pubkey!power"
// format is "val:keytype!pubkey!power"
// pubkey is a base64-encoded 32-byte ed25519 key
func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.ResponseDeliverTx {
tx = tx[len(ValidatorSetChangePrefix):]

//get the pubkey and power
pubKeyAndPower := strings.Split(string(tx), "!")
if len(pubKeyAndPower) != 2 {
if len(pubKeyAndPower) != 3 {
return types.ResponseDeliverTx{
Code: code.CodeTypeEncodingError,
Log: fmt.Sprintf("Expected 'pubkey!power'. Got %v", pubKeyAndPower)}
Log: fmt.Sprintf("Expected 'keytype!pubkey!power'. Got %v", pubKeyAndPower)}
}
pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1]
keytype, pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1], pubKeyAndPower[2]

// decode the pubkey
pubkey, err := base64.StdEncoding.DecodeString(pubkeyS)
Expand All @@ -205,15 +203,19 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) types.Respon
}

// update
return app.updateValidator(types.Ed25519ValidatorUpdate(pubkey, power))
return app.updateValidator(types.NewValidatorUpdate(keytype, pubkey, power))
}

// add, update, or remove a validator
func (app *PersistentKVStoreApplication) updateValidator(v types.ValidatorUpdate) types.ResponseDeliverTx {
key := []byte("val:" + string(v.PubKey.Data))

pubkey := ed25519.PubKeyEd25519{}
copy(pubkey[:], v.PubKey.Data)
pubkey, err := tmtypes.PB2TM.PubKey(v.PubKey)
if err != nil {
return types.ResponseDeliverTx{
Code: code.CodeTypeEncodingError,
Log: fmt.Sprintf("Error encoding validator: %v", err)}
}

if v.Power == 0 {
// remove validator
Expand Down
7 changes: 5 additions & 2 deletions abci/tests/server/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ import (
"fmt"

abcicli "github.com/tendermint/tendermint/abci/client"
"github.com/tendermint/tendermint/abci/example/kvstore"
"github.com/tendermint/tendermint/abci/types"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmtypes "github.com/tendermint/tendermint/types"
)

func InitChain(client abcicli.Client) error {
total := 10
vals := make([]types.ValidatorUpdate, total)
for i := 0; i < total; i++ {
pubkey := tmrand.Bytes(33)
pk := kvstore.GenDefaultPrivKey().PubKey()
pubkey := tmtypes.TM2PB.PubKey(pk).Data
power := tmrand.Int()
vals[i] = types.Ed25519ValidatorUpdate(pubkey, int64(power))
vals[i] = types.NewValidatorUpdate(tmtypes.ABCIPubKeyTypeComposite, pubkey, int64(power))
}
_, err := client.InitChainSync(types.RequestInitChain{
Validators: vals,
Expand Down
8 changes: 6 additions & 2 deletions abci/types/pubkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ const (
PubKeyEd25519 = "ed25519"
)

func Ed25519ValidatorUpdate(pubkey []byte, power int64) ValidatorUpdate {
func NewValidatorUpdate(keyType string, pubkey []byte, power int64) ValidatorUpdate {
return ValidatorUpdate{
// Address:
PubKey: PubKey{
Type: PubKeyEd25519,
Type: keyType,
Data: pubkey,
},
Power: power,
}
}

func Ed25519ValidatorUpdate(pubkey []byte, power int64) ValidatorUpdate {
return NewValidatorUpdate(PubKeyEd25519, pubkey, power)
}
4 changes: 2 additions & 2 deletions cmd/contract_tests/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"fmt"
"strings"

"github.com/tendermint/tendermint/cmd/contract_tests/unmarshaler"

"github.com/snikch/goodman/hooks"
"github.com/snikch/goodman/transaction"

"github.com/tendermint/tendermint/cmd/contract_tests/unmarshaler"
)

func main() {
Expand Down
5 changes: 3 additions & 2 deletions consensus/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/go-kit/kit/log/term"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"

dbm "github.com/tendermint/tm-db"

abcicli "github.com/tendermint/tendermint/abci/client"
Expand All @@ -27,7 +28,6 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
cfg "github.com/tendermint/tendermint/config"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/crypto/vrf"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
Expand Down Expand Up @@ -495,7 +495,8 @@ func forceProposer(cs *State, vals []*validatorStub, index []int, height []int64
if j+1 < len(height) && height[j+1] > height[j] {
message := types.MakeRoundHash(currentHash, height[j]-1, round[j])
proof, _ := curVal.PrivValidator.GenerateVRFProof(message)
currentHash, _ = vrf.ProofToHash(proof)
pubKey, _ := curVal.PrivValidator.GetPubKey()
currentHash, _ = pubKey.VRFVerify(proof, message)
}
}
if allMatch {
Expand Down
Loading