mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-11 23:32:50 +00:00
Compare commits
23 Commits
sam/abci++
...
cal/proces
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dd5a8303e | ||
|
|
bdda0ad33b | ||
|
|
4be2e2266e | ||
|
|
35bb8e3f8b | ||
|
|
8188ad3f90 | ||
|
|
b54253cada | ||
|
|
227db0267b | ||
|
|
d9d6a2f513 | ||
|
|
b2109ed922 | ||
|
|
b9cb5e3782 | ||
|
|
14e85b220c | ||
|
|
96ac25d5d3 | ||
|
|
fe5c4a2b8e | ||
|
|
e9d17d0e36 | ||
|
|
d6d61a3047 | ||
|
|
fbf26c9a59 | ||
|
|
bd8bbe86d4 | ||
|
|
359f6af103 | ||
|
|
b8ae6501e4 | ||
|
|
0a0812cce9 | ||
|
|
873b90867a | ||
|
|
5cc5110e9e | ||
|
|
51f3118bd6 |
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.17"
|
||||
go-version: "1.18"
|
||||
- uses: actions/checkout@v3
|
||||
- uses: technote-space/get-diff-action@v6
|
||||
with:
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.17"
|
||||
go-version: "1.18"
|
||||
- uses: actions/checkout@v3
|
||||
- uses: technote-space/get-diff-action@v6
|
||||
with:
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.17"
|
||||
go-version: "1.18"
|
||||
- uses: actions/checkout@v3
|
||||
- uses: technote-space/get-diff-action@v6
|
||||
with:
|
||||
|
||||
4
.github/workflows/check-generated.yml
vendored
4
.github/workflows/check-generated.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
||||
2
.github/workflows/e2e-manual.yml
vendored
2
.github/workflows/e2e-manual.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
2
.github/workflows/e2e-nightly-34x.yml
vendored
2
.github/workflows/e2e-nightly-34x.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
||||
2
.github/workflows/e2e-nightly-main.yml
vendored
2
.github/workflows/e2e-nightly-main.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
2
.github/workflows/e2e.yml
vendored
2
.github/workflows/e2e.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
- uses: actions/checkout@v3
|
||||
- uses: technote-space/get-diff-action@v6
|
||||
with:
|
||||
|
||||
2
.github/workflows/fuzz-nightly.yml
vendored
2
.github/workflows/fuzz-nightly.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
- uses: technote-space/get-diff-action@v6
|
||||
with:
|
||||
PATTERNS: |
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
# Required: the version of golangci-lint is required and
|
||||
# must be specified without patch version: we always use the
|
||||
# latest patch version.
|
||||
version: v1.45
|
||||
version: v1.47.3
|
||||
args: --timeout 10m
|
||||
github-token: ${{ secrets.github_token }}
|
||||
if: env.GIT_DIFF
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18'
|
||||
|
||||
- name: Build
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.17"
|
||||
go-version: "1.18"
|
||||
- uses: actions/checkout@v3
|
||||
- uses: technote-space/get-diff-action@v6
|
||||
with:
|
||||
|
||||
@@ -21,7 +21,7 @@ linters:
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- staticcheck
|
||||
- structcheck
|
||||
# - structcheck // to be fixed by golangci-lint
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
|
||||
@@ -51,7 +51,7 @@ to notify you of vulnerabilities and fixes in Tendermint Core. You can subscribe
|
||||
|
||||
| Requirement | Notes |
|
||||
| ----------- | ---------------- |
|
||||
| Go version | Go1.15 or higher |
|
||||
| Go version | Go1.18 or higher |
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ type Client interface {
|
||||
OfferSnapshotAsync(types.RequestOfferSnapshot) *ReqRes
|
||||
LoadSnapshotChunkAsync(types.RequestLoadSnapshotChunk) *ReqRes
|
||||
ApplySnapshotChunkAsync(types.RequestApplySnapshotChunk) *ReqRes
|
||||
ProcessProposalAsync(types.RequestProcessProposal) *ReqRes
|
||||
|
||||
FlushSync() error
|
||||
EchoSync(msg string) (*types.ResponseEcho, error)
|
||||
@@ -60,6 +61,7 @@ type Client interface {
|
||||
OfferSnapshotSync(types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
|
||||
LoadSnapshotChunkSync(types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
|
||||
ApplySnapshotChunkSync(types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error)
|
||||
ProcessProposalSync(types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
@@ -309,6 +309,16 @@ func (cli *grpcClient) PrepareProposalAsync(params types.RequestPrepareProposal)
|
||||
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_PrepareProposal{PrepareProposal: res}})
|
||||
}
|
||||
|
||||
func (cli *grpcClient) ProcessProposalAsync(params types.RequestProcessProposal) *ReqRes {
|
||||
req := types.ToRequestProcessProposal(params)
|
||||
res, err := cli.client.ProcessProposal(context.Background(), req.GetProcessProposal(), grpc.WaitForReady(true))
|
||||
if err != nil {
|
||||
cli.StopForError(err)
|
||||
}
|
||||
|
||||
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_ProcessProposal{ProcessProposal: res}})
|
||||
}
|
||||
|
||||
// finishAsyncCall creates a ReqRes for an async call, and immediately populates it
|
||||
// with the response. We don't complete it until it's been ordered via the channel.
|
||||
func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes {
|
||||
@@ -432,3 +442,8 @@ func (cli *grpcClient) PrepareProposalSync(
|
||||
reqres := cli.PrepareProposalAsync(params)
|
||||
return cli.finishSyncCall(reqres).GetPrepareProposal(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *grpcClient) ProcessProposalSync(params types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
reqres := cli.ProcessProposalAsync(params)
|
||||
return cli.finishSyncCall(reqres).GetProcessProposal(), cli.Error()
|
||||
}
|
||||
|
||||
@@ -218,6 +218,17 @@ func (app *localClient) PrepareProposalAsync(req types.RequestPrepareProposal) *
|
||||
)
|
||||
}
|
||||
|
||||
func (app *localClient) ProcessProposalAsync(req types.RequestProcessProposal) *ReqRes {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
res := app.Application.ProcessProposal(req)
|
||||
return app.callback(
|
||||
types.ToRequestProcessProposal(req),
|
||||
types.ToResponseProcessProposal(res),
|
||||
)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
func (app *localClient) FlushSync() error {
|
||||
@@ -342,6 +353,14 @@ func (app *localClient) PrepareProposalSync(req types.RequestPrepareProposal) (*
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (app *localClient) ProcessProposalSync(req types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
res := app.Application.ProcessProposal(req)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
func (app *localClient) callback(req *types.Request, res *types.Response) *ReqRes {
|
||||
|
||||
@@ -614,6 +614,45 @@ func (_m *Client) PrepareProposalSync(_a0 types.RequestPrepareProposal) (*types.
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ProcessProposalAsync provides a mock function with given fields: _a0
|
||||
func (_m *Client) ProcessProposalAsync(_a0 types.RequestProcessProposal) *abcicli.ReqRes {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *abcicli.ReqRes
|
||||
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) *abcicli.ReqRes); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*abcicli.ReqRes)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ProcessProposalSync provides a mock function with given fields: _a0
|
||||
func (_m *Client) ProcessProposalSync(_a0 types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *types.ResponseProcessProposal
|
||||
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) *types.ResponseProcessProposal); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseProcessProposal)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(types.RequestProcessProposal) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// QueryAsync provides a mock function with given fields: _a0
|
||||
func (_m *Client) QueryAsync(_a0 types.RequestQuery) *abcicli.ReqRes {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
@@ -283,6 +283,10 @@ func (cli *socketClient) PrepareProposalAsync(req types.RequestPrepareProposal)
|
||||
return cli.queueRequest(types.ToRequestPrepareProposal(req))
|
||||
}
|
||||
|
||||
func (cli *socketClient) ProcessProposalAsync(req types.RequestProcessProposal) *ReqRes {
|
||||
return cli.queueRequest(types.ToRequestProcessProposal(req))
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func (cli *socketClient) FlushSync() error {
|
||||
@@ -430,6 +434,15 @@ func (cli *socketClient) PrepareProposalSync(req types.RequestPrepareProposal) (
|
||||
return reqres.Response.GetPrepareProposal(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *socketClient) ProcessProposalSync(req types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
reqres := cli.queueRequest(types.ToRequestProcessProposal(req))
|
||||
if err := cli.FlushSync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reqres.Response.GetProcessProposal(), cli.Error()
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func (cli *socketClient) queueRequest(req *types.Request) *ReqRes {
|
||||
@@ -507,6 +520,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
|
||||
_, ok = res.Value.(*types.Response_OfferSnapshot)
|
||||
case *types.Request_PrepareProposal:
|
||||
_, ok = res.Value.(*types.Response_PrepareProposal)
|
||||
case *types.Request_ProcessProposal:
|
||||
_, ok = res.Value.(*types.Response_ProcessProposal)
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -170,3 +170,13 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo
|
||||
|
||||
return resQuery
|
||||
}
|
||||
|
||||
func (app *Application) ProcessProposal(
|
||||
req types.RequestProcessProposal) types.ResponseProcessProposal {
|
||||
for _, tx := range req.Txs {
|
||||
if len(tx) == 0 {
|
||||
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}
|
||||
}
|
||||
}
|
||||
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
@@ -179,6 +179,16 @@ func (app *PersistentKVStoreApplication) PrepareProposal(
|
||||
return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs, req.MaxTxBytes)}
|
||||
}
|
||||
|
||||
func (app *PersistentKVStoreApplication) ProcessProposal(
|
||||
req types.RequestProcessProposal) types.ResponseProcessProposal {
|
||||
for _, tx := range req.Txs {
|
||||
if len(tx) == 0 {
|
||||
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}
|
||||
}
|
||||
}
|
||||
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// update validators
|
||||
|
||||
|
||||
@@ -233,6 +233,9 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
|
||||
case *types.Request_PrepareProposal:
|
||||
res := s.app.PrepareProposal(*r.PrepareProposal)
|
||||
responses <- types.ToResponsePrepareProposal(res)
|
||||
case *types.Request_ProcessProposal:
|
||||
res := s.app.ProcessProposal(*r.ProcessProposal)
|
||||
responses <- types.ToResponseProcessProposal(res)
|
||||
case *types.Request_LoadSnapshotChunk:
|
||||
res := s.app.LoadSnapshotChunk(*r.LoadSnapshotChunk)
|
||||
responses <- types.ToResponseLoadSnapshotChunk(res)
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
context "golang.org/x/net/context"
|
||||
)
|
||||
|
||||
//go:generate mockery --case underscore --name Application
|
||||
//go:generate ../../scripts/mockery_generate.sh Application
|
||||
|
||||
// Application is an interface that enables any finite, deterministic state machine
|
||||
// to be driven by a blockchain-based replication engine via the ABCI.
|
||||
// All methods take a RequestXxx argument and return a ResponseXxx argument,
|
||||
@@ -21,6 +22,7 @@ type Application interface {
|
||||
// Consensus Connection
|
||||
InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore
|
||||
PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal
|
||||
ProcessProposal(RequestProcessProposal) ResponseProcessProposal
|
||||
BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block
|
||||
DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing
|
||||
EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set
|
||||
@@ -113,6 +115,11 @@ func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepa
|
||||
return ResponsePrepareProposal{TxRecords: trs}
|
||||
}
|
||||
|
||||
func (BaseApplication) ProcessProposal(req RequestProcessProposal) ResponseProcessProposal {
|
||||
return ResponseProcessProposal{
|
||||
Status: ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
// GRPCApplication is a GRPC wrapper for Application
|
||||
@@ -206,3 +213,9 @@ func (app *GRPCApplication) PrepareProposal(
|
||||
res := app.app.PrepareProposal(*req)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (app *GRPCApplication) ProcessProposal(
|
||||
ctx context.Context, req *RequestProcessProposal) (*ResponseProcessProposal, error) {
|
||||
res := app.app.ProcessProposal(*req)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -165,6 +165,12 @@ func ToRequestPrepareProposal(req RequestPrepareProposal) *Request {
|
||||
}
|
||||
}
|
||||
|
||||
func ToRequestProcessProposal(req RequestProcessProposal) *Request {
|
||||
return &Request{
|
||||
Value: &Request_ProcessProposal{&req},
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func ToResponseException(errStr string) *Response {
|
||||
@@ -268,3 +274,9 @@ func ToResponsePrepareProposal(res ResponsePrepareProposal) *Response {
|
||||
Value: &Response_PrepareProposal{&res},
|
||||
}
|
||||
}
|
||||
|
||||
func ToResponseProcessProposal(res ResponseProcessProposal) *Response {
|
||||
return &Response{
|
||||
Value: &Response_ProcessProposal{&res},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
// Code generated by mockery. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -180,6 +180,20 @@ func (_m *Application) PrepareProposal(_a0 types.RequestPrepareProposal) types.R
|
||||
return r0
|
||||
}
|
||||
|
||||
// ProcessProposal provides a mock function with given fields: _a0
|
||||
func (_m *Application) ProcessProposal(_a0 types.RequestProcessProposal) types.ResponseProcessProposal {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 types.ResponseProcessProposal
|
||||
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) types.ResponseProcessProposal); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Get(0).(types.ResponseProcessProposal)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Query provides a mock function with given fields: _a0
|
||||
func (_m *Application) Query(_a0 types.RequestQuery) types.ResponseQuery {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
@@ -84,6 +84,17 @@ func (m BaseMock) PrepareProposal(input types.RequestPrepareProposal) types.Resp
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m BaseMock) ProcessProposal(input types.RequestProcessProposal) types.ResponseProcessProposal {
|
||||
var ret types.ResponseProcessProposal
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ret = m.base.ProcessProposal(input)
|
||||
}
|
||||
}()
|
||||
ret = m.Application.ProcessProposal(input)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Commit the state and return the application Merkle root hash
|
||||
func (m BaseMock) Commit() types.ResponseCommit {
|
||||
var ret types.ResponseCommit
|
||||
|
||||
@@ -41,6 +41,11 @@ func (r ResponseQuery) IsErr() bool {
|
||||
return r.Code != CodeTypeOK
|
||||
}
|
||||
|
||||
// IsOK returns true if Code is OK
|
||||
func (r ResponseProcessProposal) IsOK() bool {
|
||||
return r.Status == ResponseProcessProposal_ACCEPT
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// override JSON marshaling so we emit defaults (ie. disable omitempty)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -448,8 +448,8 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
case <-done:
|
||||
case <-tick.C:
|
||||
for i, reactor := range reactors {
|
||||
t.Log(fmt.Sprintf("Consensus Reactor %v", i))
|
||||
t.Log(fmt.Sprintf("%v", reactor))
|
||||
t.Logf("Consensus Reactor %v", i)
|
||||
t.Logf("%v", reactor)
|
||||
}
|
||||
t.Fatalf("Timed out waiting for all validators to commit first block")
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log/term"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"path"
|
||||
@@ -462,12 +463,16 @@ func loadPrivValidator(config *cfg.Config) *privval.FilePV {
|
||||
}
|
||||
|
||||
func randState(nValidators int) (*State, []*validatorStub) {
|
||||
return randStateWithApp(nValidators, counter.NewApplication(true))
|
||||
}
|
||||
|
||||
func randStateWithApp(nValidators int, app abci.Application) (*State, []*validatorStub) {
|
||||
// Get State
|
||||
state, privVals := randGenesisState(nValidators, false, 10)
|
||||
|
||||
vss := make([]*validatorStub, nValidators)
|
||||
|
||||
cs := newState(state, privVals[0], counter.NewApplication(true))
|
||||
cs := newState(state, privVals[0], app)
|
||||
|
||||
for i := 0; i < nValidators; i++ {
|
||||
vss[i] = newValidatorStub(privVals[i], int32(i))
|
||||
@@ -682,6 +687,33 @@ func ensureVote(voteCh <-chan tmpubsub.Message, height int64, round int32,
|
||||
}
|
||||
}
|
||||
|
||||
func ensurePrevoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte) {
|
||||
t.Helper()
|
||||
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrevoteType)
|
||||
}
|
||||
|
||||
func ensureVoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte, voteType tmproto.SignedMsgType) {
|
||||
t.Helper()
|
||||
select {
|
||||
case <-time.After(ensureTimeout):
|
||||
t.Fatal("Timeout expired while waiting for NewVote event")
|
||||
case msg := <-voteCh:
|
||||
voteEvent, ok := msg.Data().(types.EventDataVote)
|
||||
require.True(t, ok, "expected a EventDataVote, got %T. Wrong subscription channel?",
|
||||
msg.Data())
|
||||
|
||||
vote := voteEvent.Vote
|
||||
assert.Equal(t, height, vote.Height, "expected height %d, but got %d", height, vote.Height)
|
||||
assert.Equal(t, round, vote.Round, "expected round %d, but got %d", round, vote.Round)
|
||||
assert.Equal(t, voteType, vote.Type, "expected type %s, but got %s", voteType, vote.Type)
|
||||
if hash == nil {
|
||||
require.Nil(t, vote.BlockID.Hash, "Expected prevote to be for nil, got %X", vote.BlockID.Hash)
|
||||
} else {
|
||||
require.True(t, bytes.Equal(vote.BlockID.Hash, hash), "Expected prevote to be for %X, got %X", hash, vote.BlockID.Hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ensurePrecommitTimeout(ch <-chan tmpubsub.Message) {
|
||||
select {
|
||||
case <-time.After(ensureTimeout):
|
||||
|
||||
@@ -274,3 +274,8 @@ func (app *CounterApplication) PrepareProposal(
|
||||
}
|
||||
return abci.ResponsePrepareProposal{TxRecords: trs}
|
||||
}
|
||||
|
||||
func (app *CounterApplication) ProcessProposal(
|
||||
req abci.RequestProcessProposal) abci.ResponseProcessProposal {
|
||||
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
@@ -1278,11 +1278,36 @@ func (cs *State) defaultDoPrevote(height int64, round int32) {
|
||||
return
|
||||
}
|
||||
|
||||
// Validate proposal block
|
||||
// Validate proposal block, from Tendermint's perspective
|
||||
err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock)
|
||||
if err != nil {
|
||||
// ProposalBlock is invalid, prevote nil.
|
||||
logger.Error("prevote step: ProposalBlock is invalid", "err", err)
|
||||
logger.Error("prevote step: consensus deems this block invalid; prevoting nil",
|
||||
"err", err)
|
||||
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Before prevoting on the block received from the proposer for the current round and height,
|
||||
we request the Application, via `ProcessProposal` ABCI call, to confirm that the block is
|
||||
valid. If the Application does not accept the block, Tendermint prevotes `nil`.
|
||||
|
||||
WARNING: misuse of block rejection by the Application can seriously compromise Tendermint's
|
||||
liveness properties. Please see `PrepareProosal`-`ProcessProposal` coherence and determinism
|
||||
properties in the ABCI++ specification.
|
||||
*/
|
||||
isAppValid, err := cs.blockExec.ProcessProposal(cs.ProposalBlock, cs.state)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf(
|
||||
"state machine returned an error (%v) when calling ProcessProposal", err,
|
||||
))
|
||||
}
|
||||
|
||||
// Vote nil if the Application rejected the block
|
||||
if !isAppValid {
|
||||
logger.Error("prevote step: state machine rejected a proposed block; this should not happen:"+
|
||||
"the proposer may be misbehaving; prevoting nil", "err", err)
|
||||
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,11 +8,15 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/counter"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
abcimocks "github.com/tendermint/tendermint/abci/types/mocks"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
@@ -1368,6 +1372,55 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) {
|
||||
assert.True(t, rs.ValidRound == round)
|
||||
}
|
||||
|
||||
func TestProcessProposalAccept(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
accept bool
|
||||
expectedNilPrevote bool
|
||||
}{
|
||||
{
|
||||
name: "accepted block is prevoted",
|
||||
accept: true,
|
||||
expectedNilPrevote: false,
|
||||
},
|
||||
{
|
||||
name: "rejected block is not prevoted",
|
||||
accept: false,
|
||||
expectedNilPrevote: true,
|
||||
},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
m := abcimocks.NewApplication(t)
|
||||
status := abci.ResponseProcessProposal_REJECT
|
||||
if testCase.accept {
|
||||
status = abci.ResponseProcessProposal_ACCEPT
|
||||
}
|
||||
m.On("ProcessProposal", mock.Anything).Return(abci.ResponseProcessProposal{Status: status})
|
||||
m.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{}).Maybe()
|
||||
cs1, _ := randStateWithApp(4, m)
|
||||
height, round := cs1.Height, cs1.Round
|
||||
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
pv1, err := cs1.privValidator.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
addr := pv1.Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
rs := cs1.GetRoundState()
|
||||
var prevoteHash tmbytes.HexBytes
|
||||
if !testCase.expectedNilPrevote {
|
||||
prevoteHash = rs.ProposalBlock.Hash()
|
||||
}
|
||||
ensurePrevoteMatch(t, voteCh, height, round, prevoteHash)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 4 vals, 3 Nil Precommits at P0
|
||||
// What we want:
|
||||
// P0 waits for timeoutPrecommit before starting next round
|
||||
|
||||
@@ -80,6 +80,15 @@ type RoundState struct {
|
||||
LockedBlock *types.Block `json:"locked_block"`
|
||||
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
|
||||
|
||||
// The variables below starting with "Valid..." derive their name from
|
||||
// the algorithm presented in this paper:
|
||||
// [The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938).
|
||||
// Therefore, "Valid...":
|
||||
// * means that the block or round that the variable refers to has
|
||||
// received 2/3+ non-`nil` prevotes (a.k.a. a *polka*)
|
||||
// * has nothing to do with whether the Application returned "Accept" in its
|
||||
// response to `ProcessProposal`, or "Reject"
|
||||
|
||||
// Last known round with POL for non-nil valid block.
|
||||
ValidRound int32 `json:"valid_round"`
|
||||
ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above.
|
||||
@@ -186,8 +195,8 @@ func (rs *RoundState) StringIndented(indent string) string {
|
||||
%s ProposalBlock: %v %v
|
||||
%s LockedRound: %v
|
||||
%s LockedBlock: %v %v
|
||||
%s ValidRound: %v
|
||||
%s ValidBlock: %v %v
|
||||
%s ValidRound: %v
|
||||
%s ValidBlock: %v %v
|
||||
%s Votes: %v
|
||||
%s LastCommit: %v
|
||||
%s LastValidators:%v
|
||||
|
||||
@@ -406,7 +406,6 @@ func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) (*store.Blo
|
||||
for i := int64(1); i <= state.LastBlockHeight; i++ {
|
||||
lastCommit := makeCommit(i-1, valAddr)
|
||||
block := sf.MakeBlock(state, i, lastCommit)
|
||||
|
||||
block.Header.Time = defaultEvidenceTime.Add(time.Duration(i) * time.Minute)
|
||||
block.Header.Version = tmversion.Consensus{Block: version.BlockProtocol, App: 1}
|
||||
const parts = 1
|
||||
|
||||
199
go.mod
199
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/tendermint/tendermint
|
||||
|
||||
go 1.16
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.0
|
||||
@@ -38,7 +38,7 @@ require (
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/tendermint/tm-db v0.6.6
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
|
||||
google.golang.org/grpc v1.48.0
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
)
|
||||
@@ -51,3 +51,198 @@ require (
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca
|
||||
github.com/vektra/mockery/v2 v2.14.0
|
||||
)
|
||||
|
||||
require (
|
||||
4d63.com/gochecknoglobals v0.1.0 // indirect
|
||||
github.com/Antonboom/errname v0.1.7 // indirect
|
||||
github.com/Antonboom/nilnil v0.1.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/DataDog/zstd v1.4.1 // indirect
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v2 v2.2.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/OpenPeeDeeP/depguard v1.1.0 // indirect
|
||||
github.com/alexkohler/prealloc v1.0.0 // indirect
|
||||
github.com/alingse/asasalint v0.0.10 // indirect
|
||||
github.com/ashanbrown/forbidigo v1.3.0 // indirect
|
||||
github.com/ashanbrown/makezero v1.1.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bkielbasa/cyclop v1.2.0 // indirect
|
||||
github.com/blizzy78/varnamelen v0.8.0 // indirect
|
||||
github.com/bombsimon/wsl/v3 v3.3.0 // indirect
|
||||
github.com/breml/bidichk v0.2.3 // indirect
|
||||
github.com/breml/errchkjson v0.3.0 // indirect
|
||||
github.com/butuzov/ireturn v0.1.1 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/charithe/durationcheck v0.0.9 // indirect
|
||||
github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4 // indirect
|
||||
github.com/containerd/continuity v0.3.0 // indirect
|
||||
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/daixiang0/gci v0.4.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/denis-tingaikin/go-header v0.4.3 // indirect
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/esimonov/ifshort v1.0.4 // indirect
|
||||
github.com/ettle/strcase v0.1.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/firefart/nonamedreturns v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||
github.com/go-critic/go-critic v0.6.3 // indirect
|
||||
github.com/go-toolsmith/astcast v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astcopy v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astequal v1.0.1 // indirect
|
||||
github.com/go-toolsmith/astfmt v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astp v1.0.0 // indirect
|
||||
github.com/go-toolsmith/strparse v1.0.0 // indirect
|
||||
github.com/go-toolsmith/typep v1.0.2 // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
||||
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect
|
||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect
|
||||
github.com/golangci/misspell v0.3.5 // indirect
|
||||
github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
|
||||
github.com/google/btree v1.0.0 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect
|
||||
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
|
||||
github.com/gostaticanalysis/comment v1.4.2 // indirect
|
||||
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
|
||||
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
|
||||
github.com/gtank/ristretto255 v0.1.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect
|
||||
github.com/jgautheron/goconst v1.5.1 // indirect
|
||||
github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f // indirect
|
||||
github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b // indirect
|
||||
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/julz/importas v0.1.0 // indirect
|
||||
github.com/kisielk/errcheck v1.6.1 // indirect
|
||||
github.com/kisielk/gotool v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/kulti/thelper v0.6.3 // indirect
|
||||
github.com/kunwardeep/paralleltest v1.0.6 // indirect
|
||||
github.com/kyoh86/exportloopref v0.1.8 // indirect
|
||||
github.com/ldez/gomoddirectives v0.2.3 // indirect
|
||||
github.com/ldez/tagliatelle v0.3.1 // indirect
|
||||
github.com/leonklingele/grouper v1.1.0 // indirect
|
||||
github.com/lufeee/execinquery v1.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/maratori/testpackage v1.1.0 // indirect
|
||||
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
|
||||
github.com/mgechev/revive v1.2.1 // indirect
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moricho/tparallel v0.2.1 // indirect
|
||||
github.com/nakabonne/nestif v0.3.1 // indirect
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
||||
github.com/nishanths/exhaustive v0.8.1 // indirect
|
||||
github.com/nishanths/predeclared v0.2.2 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/opencontainers/runc v1.1.3 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/profile v1.6.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polyfloyd/go-errorlint v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a // indirect
|
||||
github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
|
||||
github.com/rs/zerolog v1.27.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryancurrah/gomodguard v1.2.3 // indirect
|
||||
github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect
|
||||
github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect
|
||||
github.com/securego/gosec/v2 v2.12.0 // indirect
|
||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/sivchari/containedctx v1.0.2 // indirect
|
||||
github.com/sivchari/nosnakecase v1.5.0 // indirect
|
||||
github.com/sivchari/tenv v1.7.0 // indirect
|
||||
github.com/sonatard/noctx v0.0.1 // indirect
|
||||
github.com/sourcegraph/go-diff v0.6.1 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
|
||||
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
|
||||
github.com/stretchr/objx v0.4.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.0 // indirect
|
||||
github.com/sylvia7788/contextcheck v1.0.4 // indirect
|
||||
github.com/tdakkota/asciicheck v0.1.1 // indirect
|
||||
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
|
||||
github.com/tetafro/godot v1.4.11 // indirect
|
||||
github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect
|
||||
github.com/tomarrell/wrapcheck/v2 v2.6.2 // indirect
|
||||
github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect
|
||||
github.com/ultraware/funlen v0.0.3 // indirect
|
||||
github.com/ultraware/whitespace v0.0.5 // indirect
|
||||
github.com/uudashr/gocognit v1.0.6 // indirect
|
||||
github.com/yagipy/maintidx v1.0.0 // indirect
|
||||
github.com/yeya24/promlinter v0.2.0 // indirect
|
||||
gitlab.com/bosi/decorder v0.2.2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220727055044-e65921a090b8 // indirect
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
honnef.co/go/tools v0.3.2 // indirect
|
||||
mvdan.cc/gofumpt v0.3.1 // indirect
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
|
||||
mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect
|
||||
)
|
||||
|
||||
92
internal/test/block.go
Normal file
92
internal/test/block.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultTestChainID = "test-chain"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultTestTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
)
|
||||
|
||||
func RandomAddress() []byte {
|
||||
return crypto.CRandBytes(crypto.AddressSize)
|
||||
}
|
||||
|
||||
func RandomHash() []byte {
|
||||
return crypto.CRandBytes(tmhash.Size)
|
||||
}
|
||||
|
||||
func MakeBlockID() types.BlockID {
|
||||
return MakeBlockIDWithHash(RandomHash())
|
||||
}
|
||||
|
||||
func MakeBlockIDWithHash(hash []byte) types.BlockID {
|
||||
return types.BlockID{
|
||||
Hash: hash,
|
||||
PartSetHeader: types.PartSetHeader{
|
||||
Total: 100,
|
||||
Hash: RandomHash(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// MakeHeader fills the rest of the contents of the header such that it passes
|
||||
// validate basic
|
||||
func MakeHeader(t *testing.T, h *types.Header) *types.Header {
|
||||
t.Helper()
|
||||
if h.Version.Block == 0 {
|
||||
h.Version.Block = version.BlockProtocol
|
||||
}
|
||||
if h.Height == 0 {
|
||||
h.Height = 1
|
||||
}
|
||||
if h.LastBlockID.IsZero() {
|
||||
h.LastBlockID = MakeBlockID()
|
||||
}
|
||||
if h.ChainID == "" {
|
||||
h.ChainID = DefaultTestChainID
|
||||
}
|
||||
if len(h.LastCommitHash) == 0 {
|
||||
h.LastCommitHash = RandomHash()
|
||||
}
|
||||
if len(h.DataHash) == 0 {
|
||||
h.DataHash = RandomHash()
|
||||
}
|
||||
if len(h.ValidatorsHash) == 0 {
|
||||
h.ValidatorsHash = RandomHash()
|
||||
}
|
||||
if len(h.NextValidatorsHash) == 0 {
|
||||
h.NextValidatorsHash = RandomHash()
|
||||
}
|
||||
if len(h.ConsensusHash) == 0 {
|
||||
h.ConsensusHash = RandomHash()
|
||||
}
|
||||
if len(h.AppHash) == 0 {
|
||||
h.AppHash = RandomHash()
|
||||
}
|
||||
if len(h.LastResultsHash) == 0 {
|
||||
h.LastResultsHash = RandomHash()
|
||||
}
|
||||
if len(h.EvidenceHash) == 0 {
|
||||
h.EvidenceHash = RandomHash()
|
||||
}
|
||||
if len(h.ProposerAddress) == 0 {
|
||||
h.ProposerAddress = RandomAddress()
|
||||
}
|
||||
|
||||
require.NoError(t, h.ValidateBasic())
|
||||
|
||||
return h
|
||||
}
|
||||
6
internal/test/doc.go
Normal file
6
internal/test/doc.go
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
Package factory provides generation code for common structs in Tendermint.
|
||||
It is used primarily for the testing of internal components such as statesync,
|
||||
consensus, blocksync etc..
|
||||
*/
|
||||
package factory
|
||||
11
internal/test/factory_test.go
Normal file
11
internal/test/factory_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func TestMakeHeader(t *testing.T) {
|
||||
MakeHeader(t, &types.Header{})
|
||||
}
|
||||
34
internal/test/genesis.go
Normal file
34
internal/test/genesis.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func GenesisDoc(
|
||||
config *cfg.Config,
|
||||
time time.Time,
|
||||
validators []*types.Validator,
|
||||
consensusParams *tmproto.ConsensusParams,
|
||||
) *types.GenesisDoc {
|
||||
|
||||
genesisValidators := make([]types.GenesisValidator, len(validators))
|
||||
|
||||
for i := range validators {
|
||||
genesisValidators[i] = types.GenesisValidator{
|
||||
Power: validators[i].VotingPower,
|
||||
PubKey: validators[i].PubKey,
|
||||
}
|
||||
}
|
||||
|
||||
return &types.GenesisDoc{
|
||||
GenesisTime: time,
|
||||
InitialHeight: 1,
|
||||
ChainID: config.ChainID(),
|
||||
Validators: genesisValidators,
|
||||
ConsensusParams: consensusParams,
|
||||
}
|
||||
}
|
||||
11
internal/test/tx.go
Normal file
11
internal/test/tx.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package factory
|
||||
|
||||
import "github.com/tendermint/tendermint/types"
|
||||
|
||||
func MakeNTxs(height, n int64) []types.Tx {
|
||||
txs := make([]types.Tx, n)
|
||||
for i := range txs {
|
||||
txs[i] = types.Tx([]byte{byte(height), byte(i / 256), byte(i % 256)})
|
||||
}
|
||||
return txs
|
||||
}
|
||||
41
internal/test/validator.go
Normal file
41
internal/test/validator.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func Validator(ctx context.Context, votingPower int64) (*types.Validator, types.PrivValidator, error) {
|
||||
privVal := types.NewMockPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
val := types.NewValidator(pubKey, votingPower)
|
||||
return val, privVal, nil
|
||||
}
|
||||
|
||||
func ValidatorSet(ctx context.Context, t *testing.T, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) {
|
||||
var (
|
||||
valz = make([]*types.Validator, numValidators)
|
||||
privValidators = make([]types.PrivValidator, numValidators)
|
||||
)
|
||||
t.Helper()
|
||||
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privValidator, err := Validator(ctx, votingPower)
|
||||
require.NoError(t, err)
|
||||
valz[i] = val
|
||||
privValidators[i] = privValidator
|
||||
}
|
||||
|
||||
sort.Sort(types.PrivValidatorsByAddress(privValidators))
|
||||
|
||||
return types.NewValidatorSet(valz), privValidators
|
||||
}
|
||||
44
internal/test/vote.go
Normal file
44
internal/test/vote.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func MakeVote(
|
||||
ctx context.Context,
|
||||
val types.PrivValidator,
|
||||
chainID string,
|
||||
valIndex int32,
|
||||
height int64,
|
||||
round int32,
|
||||
step int,
|
||||
blockID types.BlockID,
|
||||
time time.Time,
|
||||
) (*types.Vote, error) {
|
||||
pubKey, err := val.GetPubKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := &types.Vote{
|
||||
ValidatorAddress: pubKey.Address(),
|
||||
ValidatorIndex: valIndex,
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: tmproto.SignedMsgType(step),
|
||||
BlockID: blockID,
|
||||
Timestamp: time,
|
||||
}
|
||||
|
||||
vpb := v.ToProto()
|
||||
if err := val.SignVote(chainID, vpb); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v.Signature = vpb.Signature
|
||||
return v, nil
|
||||
}
|
||||
@@ -69,6 +69,8 @@ type DBContext struct {
|
||||
// DBProvider takes a DBContext and returns an instantiated DB.
|
||||
type DBProvider func(*DBContext) (dbm.DB, error)
|
||||
|
||||
const readHeaderTimeout = 10 * time.Second
|
||||
|
||||
// DefaultDBProvider returns a database using the DBBackend and DBDir
|
||||
// specified in the ctx.Config.
|
||||
func DefaultDBProvider(ctx *DBContext) (dbm.DB, error) {
|
||||
@@ -1220,6 +1222,7 @@ func (n *Node) startPrometheusServer(addr string) *http.Server {
|
||||
promhttp.HandlerOpts{MaxRequestsInFlight: n.config.Instrumentation.MaxOpenConnections},
|
||||
),
|
||||
),
|
||||
ReadHeaderTimeout: readHeaderTimeout,
|
||||
}
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
|
||||
@@ -79,9 +79,9 @@ func TestTransportMultiplexConnFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err = mt.Accept(peerConfig{})
|
||||
if err, ok := err.(ErrRejected); ok {
|
||||
if !err.IsFiltered() {
|
||||
t.Errorf("expected peer to be filtered, got %v", err)
|
||||
if e, ok := err.(ErrRejected); ok {
|
||||
if !e.IsFiltered() {
|
||||
t.Errorf("expected peer to be filtered, got %v", e)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected ErrRejected, got %v", err)
|
||||
@@ -386,9 +386,9 @@ func TestTransportMultiplexValidateNodeInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err := mt.Accept(peerConfig{})
|
||||
if err, ok := err.(ErrRejected); ok {
|
||||
if !err.IsNodeInfoInvalid() {
|
||||
t.Errorf("expected NodeInfo to be invalid, got %v", err)
|
||||
if e, ok := err.(ErrRejected); ok {
|
||||
if !e.IsNodeInfoInvalid() {
|
||||
t.Errorf("expected NodeInfo to be invalid, got %v", e)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected ErrRejected, got %v", err)
|
||||
@@ -425,9 +425,9 @@ func TestTransportMultiplexRejectMissmatchID(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err := mt.Accept(peerConfig{})
|
||||
if err, ok := err.(ErrRejected); ok {
|
||||
if !err.IsAuthFailure() {
|
||||
t.Errorf("expected auth failure, got %v", err)
|
||||
if e, ok := err.(ErrRejected); ok {
|
||||
if !e.IsAuthFailure() {
|
||||
t.Errorf("expected auth failure, got %v", e)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected ErrRejected, got %v", err)
|
||||
@@ -453,9 +453,9 @@ func TestTransportMultiplexDialRejectWrongID(t *testing.T) {
|
||||
_, err := dialer.Dial(*addr, peerConfig{})
|
||||
if err != nil {
|
||||
t.Logf("connection failed: %v", err)
|
||||
if err, ok := err.(ErrRejected); ok {
|
||||
if !err.IsAuthFailure() {
|
||||
t.Errorf("expected auth failure, got %v", err)
|
||||
if e, ok := err.(ErrRejected); ok {
|
||||
if !e.IsAuthFailure() {
|
||||
t.Errorf("expected auth failure, got %v", e)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected ErrRejected, got %v", err)
|
||||
@@ -490,9 +490,9 @@ func TestTransportMultiplexRejectIncompatible(t *testing.T) {
|
||||
}()
|
||||
|
||||
_, err := mt.Accept(peerConfig{})
|
||||
if err, ok := err.(ErrRejected); ok {
|
||||
if !err.IsIncompatible() {
|
||||
t.Errorf("expected to reject incompatible, got %v", err)
|
||||
if e, ok := err.(ErrRejected); ok {
|
||||
if !e.IsIncompatible() {
|
||||
t.Errorf("expected to reject incompatible, got %v", e)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected ErrRejected, got %v", err)
|
||||
@@ -517,9 +517,9 @@ func TestTransportMultiplexRejectSelf(t *testing.T) {
|
||||
}()
|
||||
|
||||
if err := <-errc; err != nil {
|
||||
if err, ok := err.(ErrRejected); ok {
|
||||
if !err.IsSelf() {
|
||||
t.Errorf("expected to reject self, got: %v", err)
|
||||
if e, ok := err.(ErrRejected); ok {
|
||||
if !e.IsSelf() {
|
||||
t.Errorf("expected to reject self, got: %v", e)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected ErrRejected, got %v", err)
|
||||
|
||||
@@ -37,6 +37,7 @@ message Request {
|
||||
RequestLoadSnapshotChunk load_snapshot_chunk = 14;
|
||||
RequestApplySnapshotChunk apply_snapshot_chunk = 15;
|
||||
RequestPrepareProposal prepare_proposal = 16;
|
||||
RequestProcessProposal process_proposal = 17;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +77,10 @@ message RequestQuery {
|
||||
}
|
||||
|
||||
message RequestBeginBlock {
|
||||
bytes hash = 1;
|
||||
tendermint.types.Header header = 2 [(gogoproto.nullable) = false];
|
||||
LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false];
|
||||
repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false];
|
||||
bytes hash = 1;
|
||||
tendermint.types.Header header = 2 [(gogoproto.nullable) = false];
|
||||
CommitInfo last_commit_info = 3 [(gogoproto.nullable) = false];
|
||||
repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
enum CheckTxType {
|
||||
@@ -137,6 +138,19 @@ message RequestPrepareProposal {
|
||||
int64 max_tx_bytes = 6;
|
||||
}
|
||||
|
||||
message RequestProcessProposal {
|
||||
repeated bytes txs = 1;
|
||||
CommitInfo proposed_last_commit = 2 [(gogoproto.nullable) = false];
|
||||
repeated Evidence misbehavior = 3 [(gogoproto.nullable) = false];
|
||||
// hash is the merkle root hash of the fields of the proposed block.
|
||||
bytes hash = 4;
|
||||
int64 height = 5;
|
||||
google.protobuf.Timestamp time = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
bytes next_validators_hash = 7;
|
||||
// address of the public key of the original proposer of the block.
|
||||
bytes proposer_address = 8;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Response types
|
||||
|
||||
@@ -159,7 +173,7 @@ message Response {
|
||||
ResponseLoadSnapshotChunk load_snapshot_chunk = 15;
|
||||
ResponseApplySnapshotChunk apply_snapshot_chunk = 16;
|
||||
ResponsePrepareProposal prepare_proposal = 17;
|
||||
|
||||
ResponseProcessProposal process_proposal = 18;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +263,7 @@ message ResponseDeliverTx {
|
||||
}
|
||||
|
||||
message ResponseEndBlock {
|
||||
repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable) = false];
|
||||
repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable) = false];
|
||||
ConsensusParams consensus_param_updates = 2;
|
||||
repeated Event events = 3
|
||||
[(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
|
||||
@@ -298,7 +312,17 @@ message ResponseApplySnapshotChunk {
|
||||
}
|
||||
|
||||
message ResponsePrepareProposal {
|
||||
repeated TxRecord tx_records = 1;
|
||||
repeated TxRecord tx_records = 1;
|
||||
}
|
||||
|
||||
message ResponseProcessProposal {
|
||||
ProposalStatus status = 1;
|
||||
|
||||
enum ProposalStatus {
|
||||
UNKNOWN = 0;
|
||||
ACCEPT = 1;
|
||||
REJECT = 2;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
@@ -321,7 +345,7 @@ message BlockParams {
|
||||
int64 max_gas = 2;
|
||||
}
|
||||
|
||||
message LastCommitInfo {
|
||||
message CommitInfo {
|
||||
int32 round = 1;
|
||||
repeated VoteInfo votes = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
@@ -456,4 +480,5 @@ service ABCIApplication {
|
||||
rpc ApplySnapshotChunk(RequestApplySnapshotChunk)
|
||||
returns (ResponseApplySnapshotChunk);
|
||||
rpc PrepareProposal(RequestPrepareProposal) returns (ResponsePrepareProposal);
|
||||
rpc ProcessProposal(RequestProcessProposal) returns (ResponseProcessProposal);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func (m *NewRoundStep) GetLastCommitRound() int32 {
|
||||
}
|
||||
|
||||
// NewValidBlock is sent when a validator observes a valid block B in some round r,
|
||||
//i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
|
||||
// i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
|
||||
// In case the block is also committed, then IsCommit flag is set to true.
|
||||
type NewValidBlock struct {
|
||||
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
|
||||
|
||||
@@ -18,7 +18,7 @@ message NewRoundStep {
|
||||
}
|
||||
|
||||
// NewValidBlock is sent when a validator observes a valid block B in some round r,
|
||||
//i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
|
||||
// i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
|
||||
// In case the block is also committed, then IsCommit flag is set to true.
|
||||
message NewValidBlock {
|
||||
int64 height = 1;
|
||||
|
||||
@@ -17,20 +17,20 @@ message Evidence {
|
||||
|
||||
// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes.
|
||||
message DuplicateVoteEvidence {
|
||||
tendermint.types.Vote vote_a = 1;
|
||||
tendermint.types.Vote vote_b = 2;
|
||||
int64 total_voting_power = 3;
|
||||
int64 validator_power = 4;
|
||||
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
tendermint.types.Vote vote_a = 1;
|
||||
tendermint.types.Vote vote_b = 2;
|
||||
int64 total_voting_power = 3;
|
||||
int64 validator_power = 4;
|
||||
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
}
|
||||
|
||||
// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client.
|
||||
message LightClientAttackEvidence {
|
||||
tendermint.types.LightBlock conflicting_block = 1;
|
||||
int64 common_height = 2;
|
||||
tendermint.types.LightBlock conflicting_block = 1;
|
||||
int64 common_height = 2;
|
||||
repeated tendermint.types.Validator byzantine_validators = 3;
|
||||
int64 total_voting_power = 4;
|
||||
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
int64 total_voting_power = 4;
|
||||
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
}
|
||||
|
||||
message EvidenceList {
|
||||
|
||||
@@ -106,10 +106,10 @@ message Vote {
|
||||
|
||||
// Commit contains the evidence that a block was committed by a set of validators.
|
||||
message Commit {
|
||||
int64 height = 1;
|
||||
int32 round = 2;
|
||||
BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"];
|
||||
repeated CommitSig signatures = 4 [(gogoproto.nullable) = false];
|
||||
int64 height = 1;
|
||||
int32 round = 2;
|
||||
BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"];
|
||||
repeated CommitSig signatures = 4 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// CommitSig is a part of the Vote included in a Commit.
|
||||
|
||||
@@ -15,8 +15,8 @@ type AppConnConsensus interface {
|
||||
Error() error
|
||||
|
||||
InitChainSync(types.RequestInitChain) (*types.ResponseInitChain, error)
|
||||
|
||||
PrepareProposalSync(types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error)
|
||||
ProcessProposalSync(types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
|
||||
BeginBlockSync(types.RequestBeginBlock) (*types.ResponseBeginBlock, error)
|
||||
DeliverTxAsync(types.RequestDeliverTx) *abcicli.ReqRes
|
||||
EndBlockSync(types.RequestEndBlock) (*types.ResponseEndBlock, error)
|
||||
@@ -85,6 +85,10 @@ func (app *appConnConsensus) PrepareProposalSync(
|
||||
return app.appConn.PrepareProposalSync(req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) ProcessProposalSync(req types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
return app.appConn.ProcessProposalSync(req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) BeginBlockSync(req types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
|
||||
return app.appConn.BeginBlockSync(req)
|
||||
}
|
||||
|
||||
@@ -159,6 +159,29 @@ func (_m *AppConnConsensus) PrepareProposalSync(_a0 types.RequestPrepareProposal
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ProcessProposalSync provides a mock function with given fields: _a0
|
||||
func (_m *AppConnConsensus) ProcessProposalSync(_a0 types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *types.ResponseProcessProposal
|
||||
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) *types.ResponseProcessProposal); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseProcessProposal)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(types.RequestProcessProposal) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SetResponseCallback provides a mock function with given fields: _a0
|
||||
func (_m *AppConnConsensus) SetResponseCallback(_a0 abcicli.Callback) {
|
||||
_m.Called(_a0)
|
||||
|
||||
@@ -53,10 +53,11 @@ func DefaultConfig() *Config {
|
||||
func Serve(listener net.Listener, handler http.Handler, logger log.Logger, config *Config) error {
|
||||
logger.Info("serve", "msg", log.NewLazySprintf("Starting RPC HTTP server on %s", listener.Addr()))
|
||||
s := &http.Server{
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: config.MaxBodyBytes}, logger),
|
||||
ReadTimeout: config.ReadTimeout,
|
||||
WriteTimeout: config.WriteTimeout,
|
||||
MaxHeaderBytes: config.MaxHeaderBytes,
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: config.MaxBodyBytes}, logger),
|
||||
ReadTimeout: config.ReadTimeout,
|
||||
ReadHeaderTimeout: config.ReadTimeout,
|
||||
WriteTimeout: config.WriteTimeout,
|
||||
MaxHeaderBytes: config.MaxHeaderBytes,
|
||||
}
|
||||
err := s.Serve(listener)
|
||||
logger.Info("RPC HTTP server stopped", "err", err)
|
||||
@@ -78,10 +79,11 @@ func ServeTLS(
|
||||
logger.Info("serve tls", "msg", log.NewLazySprintf("Starting RPC HTTPS server on %s (cert: %q, key: %q)",
|
||||
listener.Addr(), certFile, keyFile))
|
||||
s := &http.Server{
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: config.MaxBodyBytes}, logger),
|
||||
ReadTimeout: config.ReadTimeout,
|
||||
WriteTimeout: config.WriteTimeout,
|
||||
MaxHeaderBytes: config.MaxHeaderBytes,
|
||||
Handler: RecoverAndLogHandler(maxBytesHandler{h: handler, n: config.MaxBodyBytes}, logger),
|
||||
ReadTimeout: config.ReadTimeout,
|
||||
ReadHeaderTimeout: config.ReadTimeout,
|
||||
WriteTimeout: config.WriteTimeout,
|
||||
MaxHeaderBytes: config.MaxHeaderBytes,
|
||||
}
|
||||
err := s.ServeTLS(listener, certFile, keyFile)
|
||||
|
||||
|
||||
15
scripts/mockery_generate.sh
Executable file
15
scripts/mockery_generate.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Invoke Mockery v2 to update generated mocks for the given type.
|
||||
#
|
||||
# This script runs a locally-installed "mockery" if available, otherwise it
|
||||
# runs the published Docker container. This legerdemain is so that the CI build
|
||||
# and a local build can work off the same script.
|
||||
#
|
||||
if ! which mockery ; then
|
||||
mockery() {
|
||||
docker run --rm -v "$PWD":/w --workdir=/w vektra/mockery:v2.12.3
|
||||
}
|
||||
fi
|
||||
|
||||
mockery --disable-version-string --case underscore --name "$@"
|
||||
@@ -112,7 +112,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
|
||||
txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
|
||||
block := state.MakeBlock(height, txs, commit, evidence, proposerAddr)
|
||||
|
||||
localLastCommit := getBeginBlockValidatorInfo(block, blockExec.store, state.InitialHeight)
|
||||
localLastCommit := buildLastCommitInfo(block, blockExec.store, state.InitialHeight)
|
||||
rpp, err := blockExec.proxyApp.PrepareProposalSync(
|
||||
abci.RequestPrepareProposal{
|
||||
Hash: block.Hash(),
|
||||
@@ -149,6 +149,27 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
|
||||
return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) ProcessProposal(
|
||||
block *types.Block,
|
||||
state State,
|
||||
) (bool, error) {
|
||||
resp, err := blockExec.proxyApp.ProcessProposalSync(abci.RequestProcessProposal{
|
||||
Hash: block.Header.Hash(),
|
||||
Height: block.Header.Height,
|
||||
Time: block.Header.Time,
|
||||
Txs: block.Data.Txs.ToSliceOfBytes(),
|
||||
ProposedLastCommit: buildLastCommitInfo(block, blockExec.store, state.InitialHeight),
|
||||
Misbehavior: block.Evidence.Evidence.ToABCI(),
|
||||
ProposerAddress: block.ProposerAddress,
|
||||
NextValidatorsHash: block.NextValidatorsHash,
|
||||
})
|
||||
if err != nil {
|
||||
return false, ErrInvalidBlock(err)
|
||||
}
|
||||
|
||||
return resp.IsOK(), nil
|
||||
}
|
||||
|
||||
// ValidateBlock validates the given block against the given state.
|
||||
// If the block is invalid, it returns an error.
|
||||
// Validation does not mutate state, but does require historical information from the stateDB,
|
||||
@@ -329,7 +350,7 @@ func execBlockOnProxyApp(
|
||||
}
|
||||
proxyAppConn.SetResponseCallback(proxyCb)
|
||||
|
||||
commitInfo := getBeginBlockValidatorInfo(block, store, initialHeight)
|
||||
commitInfo := buildLastCommitInfo(block, store, initialHeight)
|
||||
|
||||
byzVals := make([]abci.Evidence, 0)
|
||||
for _, evidence := range block.Evidence.Evidence {
|
||||
@@ -373,47 +394,48 @@ func execBlockOnProxyApp(
|
||||
return abciResponses, nil
|
||||
}
|
||||
|
||||
func getBeginBlockValidatorInfo(block *types.Block, store Store,
|
||||
initialHeight int64) abci.LastCommitInfo {
|
||||
voteInfos := make([]abci.VoteInfo, block.LastCommit.Size())
|
||||
// Initial block -> LastCommitInfo.Votes are empty.
|
||||
// Remember that the first LastCommit is intentionally empty, so it makes
|
||||
// sense for LastCommitInfo.Votes to also be empty.
|
||||
if block.Height > initialHeight {
|
||||
lastValSet, err := store.LoadValidators(block.Height - 1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) abci.CommitInfo {
|
||||
if block.Height == initialHeight {
|
||||
// there is no last commit for the initial height.
|
||||
// return an empty value.
|
||||
return abci.CommitInfo{}
|
||||
}
|
||||
|
||||
// Sanity check that commit size matches validator set size - only applies
|
||||
// after first block.
|
||||
var (
|
||||
commitSize = block.LastCommit.Size()
|
||||
valSetLen = len(lastValSet.Validators)
|
||||
)
|
||||
if commitSize != valSetLen {
|
||||
panic(fmt.Sprintf(
|
||||
"commit size (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
|
||||
commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators,
|
||||
))
|
||||
}
|
||||
lastValSet, err := store.LoadValidators(block.Height - 1)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to load validator set at height %d: %w", block.Height-1, err))
|
||||
}
|
||||
|
||||
for i, val := range lastValSet.Validators {
|
||||
commitSig := block.LastCommit.Signatures[i]
|
||||
voteInfos[i] = abci.VoteInfo{
|
||||
Validator: types.TM2PB.Validator(val),
|
||||
SignedLastBlock: !commitSig.Absent(),
|
||||
}
|
||||
var (
|
||||
commitSize = block.LastCommit.Size()
|
||||
valSetLen = len(lastValSet.Validators)
|
||||
)
|
||||
|
||||
// ensure that the size of the validator set in the last commit matches
|
||||
// the size of the validator set in the state store.
|
||||
if commitSize != valSetLen {
|
||||
panic(fmt.Sprintf(
|
||||
"commit size (%d) doesn't match validator set length (%d) at height %d\n\n%v\n\n%v",
|
||||
commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators,
|
||||
))
|
||||
}
|
||||
|
||||
votes := make([]abci.VoteInfo, block.LastCommit.Size())
|
||||
for i, val := range lastValSet.Validators {
|
||||
commitSig := block.LastCommit.Signatures[i]
|
||||
votes[i] = abci.VoteInfo{
|
||||
Validator: types.TM2PB.Validator(val),
|
||||
SignedLastBlock: commitSig.BlockIDFlag != types.BlockIDFlagAbsent,
|
||||
}
|
||||
}
|
||||
|
||||
return abci.LastCommitInfo{
|
||||
return abci.CommitInfo{
|
||||
Round: block.LastCommit.Round,
|
||||
Votes: voteInfos,
|
||||
Votes: votes,
|
||||
}
|
||||
}
|
||||
|
||||
func extendedCommitInfo(c abci.LastCommitInfo, votes []*types.Vote) abci.ExtendedCommitInfo {
|
||||
func extendedCommitInfo(c abci.CommitInfo, votes []*types.Vote) abci.ExtendedCommitInfo {
|
||||
vs := make([]abci.ExtendedVoteInfo, len(c.Votes))
|
||||
for i := range vs {
|
||||
vs[i] = abci.ExtendedVoteInfo{
|
||||
|
||||
@@ -245,6 +245,85 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
||||
assert.Equal(t, abciEv, app.ByzantineValidators)
|
||||
}
|
||||
|
||||
func TestProcessProposal(t *testing.T) {
|
||||
const height = 2
|
||||
txs := factory.MakeNTxs(height, 10)
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
app := abcimocks.NewBaseMock()
|
||||
app.On("ProcessProposal", mock.Anything).Return(abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT})
|
||||
|
||||
cc := proxy.NewLocalClientCreator(app)
|
||||
proxyApp := proxy.NewAppConns(cc)
|
||||
err := proxyApp.Start()
|
||||
require.NoError(t, err)
|
||||
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
|
||||
|
||||
state, stateDB, privVals := makeState(1, height)
|
||||
stateStore := sm.NewStore(stateDB)
|
||||
|
||||
eventBus := types.NewEventBus()
|
||||
err = eventBus.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
blockExec := sm.NewBlockExecutor(
|
||||
stateStore,
|
||||
logger,
|
||||
proxyApp.Consensus(),
|
||||
new(mpmocks.Mempool),
|
||||
sm.EmptyEvidencePool{},
|
||||
)
|
||||
|
||||
block0 := sf.MakeBlock(state, height-1, new(types.Commit))
|
||||
lastCommitSig := []types.CommitSig{}
|
||||
partSet, err := block0.MakePartSet(types.BlockPartSizeBytes)
|
||||
require.NoError(t, err)
|
||||
blockID := types.BlockID{Hash: block0.Hash(), PartSetHeader: partSet.Header()}
|
||||
voteInfos := []abci.VoteInfo{}
|
||||
for _, privVal := range privVals {
|
||||
vote, err := types.MakeVote(height, blockID, state.Validators, privVal, block0.Header.ChainID, time.Now())
|
||||
require.NoError(t, err)
|
||||
pk, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
addr := pk.Address()
|
||||
voteInfos = append(voteInfos,
|
||||
abci.VoteInfo{
|
||||
SignedLastBlock: true,
|
||||
Validator: abci.Validator{
|
||||
Address: addr,
|
||||
Power: 1000,
|
||||
},
|
||||
})
|
||||
lastCommitSig = append(lastCommitSig, vote.CommitSig())
|
||||
}
|
||||
|
||||
block1 := sf.MakeBlock(state, height, &types.Commit{
|
||||
Height: height - 1,
|
||||
Signatures: lastCommitSig,
|
||||
})
|
||||
block1.Txs = txs
|
||||
|
||||
expectedRpp := abci.RequestProcessProposal{
|
||||
Txs: block1.Txs.ToSliceOfBytes(),
|
||||
Hash: block1.Hash(),
|
||||
Height: block1.Header.Height,
|
||||
Time: block1.Header.Time,
|
||||
Misbehavior: block1.Evidence.Evidence.ToABCI(),
|
||||
ProposedLastCommit: abci.CommitInfo{
|
||||
Round: 0,
|
||||
Votes: voteInfos,
|
||||
},
|
||||
NextValidatorsHash: block1.NextValidatorsHash,
|
||||
ProposerAddress: block1.ProposerAddress,
|
||||
}
|
||||
|
||||
acceptBlock, err := blockExec.ProcessProposal(block1, state)
|
||||
require.NoError(t, err)
|
||||
require.True(t, acceptBlock)
|
||||
app.AssertExpectations(t)
|
||||
app.AssertCalled(t, "ProcessProposal", expectedRpp)
|
||||
}
|
||||
|
||||
func TestValidateValidatorUpdates(t *testing.T) {
|
||||
pubkey1 := ed25519.GenPrivKey().PubKey()
|
||||
pubkey2 := ed25519.GenPrivKey().PubKey()
|
||||
|
||||
@@ -170,7 +170,6 @@ func makeHeaderPartsResponsesValPowerChange(
|
||||
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
|
||||
|
||||
block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
|
||||
|
||||
abciResponses := &tmstate.ABCIResponses{
|
||||
BeginBlock: &abci.ResponseBeginBlock{},
|
||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
||||
@@ -265,3 +264,12 @@ func (app *testApp) Commit() abci.ResponseCommit {
|
||||
func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
|
||||
return
|
||||
}
|
||||
|
||||
func (app *testApp) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal {
|
||||
for _, tx := range req.Txs {
|
||||
if len(tx) == 0 {
|
||||
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}
|
||||
}
|
||||
}
|
||||
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
@@ -275,6 +275,18 @@ func (app *Application) PrepareProposal(
|
||||
return abci.ResponsePrepareProposal{TxRecords: trs}
|
||||
}
|
||||
|
||||
// ProcessProposal implements part of the Application interface.
|
||||
// It accepts any proposal that does not contain a malformed transaction.
|
||||
func (app *Application) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal {
|
||||
for _, tx := range req.Txs {
|
||||
_, _, err := parseTx(tx)
|
||||
if err != nil {
|
||||
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}
|
||||
}
|
||||
}
|
||||
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
func (app *Application) Rollback() error {
|
||||
return app.state.Rollback()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# We need to build in a Linux environment to support C libraries, e.g. RocksDB.
|
||||
# We use Debian instead of Alpine, so that we can use binary database packages
|
||||
# instead of spending time compiling them.
|
||||
FROM golang:1.15
|
||||
FROM golang:1.18
|
||||
|
||||
RUN apt-get -qq update -y && apt-get -qq upgrade -y >/dev/null
|
||||
RUN apt-get -qq install -y libleveldb-dev librocksdb-dev >/dev/null
|
||||
|
||||
@@ -1215,6 +1215,7 @@ func (n *Node) startPrometheusServer(addr string) *http.Server {
|
||||
promhttp.HandlerOpts{MaxRequestsInFlight: n.config.Instrumentation.MaxOpenConnections},
|
||||
),
|
||||
),
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
|
||||
Reference in New Issue
Block a user