Compare commits

...

9 Commits

Author SHA1 Message Date
Anton Kaliaev
f0327d9c61 fix build after merge 2019-07-22 11:59:44 +04:00
Anton Kaliaev
26b81fb4d4 Merge branch 'master' into anton/block-results 2019-07-22 11:39:53 +04:00
Anton Kaliaev
56a5176f23 Merge branch 'master' into anton/block-results 2019-07-22 11:19:26 +04:00
Anton Kaliaev
486d23b575 rename ABCIResponses.DeliverTx to DeliverTxs
cause it's an array really
2019-07-19 10:35:23 +04:00
Anton Kaliaev
9c8238c8ee update doc 2019-07-19 10:17:30 +04:00
Anton Kaliaev
d2db47cc4a Merge branch 'master' into anton/block-results 2019-07-19 10:08:38 +04:00
Anton Kaliaev
94611e1f81 update changelog entry 2019-07-04 16:29:55 +04:00
Anton Kaliaev
73295be21d rpc: [block_results] include BeginBlock and EndBlock Events 2019-07-04 16:23:42 +04:00
Anton Kaliaev
6a369b69b8 rpc: /block_results fix docs + write test + restructure response
BREAKING

Example response:

```json
{
  "jsonrpc": "2.0",
  "id": "",
  "result": {
    "height": "2109",
    "txs_results": null,
    "validator_updates": null,
    "consensus_param_updates": null
  }
}
```

Old result consisted of ABCIResponses struct and height. Exposing
internal ABCI structures (which we store in state package) in RPC seems
bad to me for the following reasons:

1) high risk of breaking the API when somebody changes internal structs
(HAPPENED HERE!)
2) RPC is aware of ABCI, which I'm not sure we want
2019-07-04 15:21:52 +04:00
11 changed files with 151 additions and 56 deletions

View File

@@ -10,11 +10,25 @@ program](https://hackerone.com/tendermint).
### BREAKING CHANGES:
- CLI/RPC/Config
- [rpc] `/block_results` response format updated (see RPC docs for details)
```
{
"jsonrpc": "2.0",
"id": "",
"result": {
"height": "2109",
"txs_results": null,
"begin_block_events": null,
"end_block_events": null,
"validator_updates": null,
"consensus_param_updates": null
}
}
- Apps
- Go API
- [libs] \#3811 Remove `db` from libs in favor of `https://github.com/tendermint/tm-cmn`
- [libs] \#3811 Remove `db` from libs in favor of `https://github.com/tendermint/tm-cmn`
### FEATURES:
@@ -25,3 +39,4 @@ program](https://hackerone.com/tendermint).
- [p2p] \#3664 p2p/conn: reuse buffer when write/read from secret connection
### BUG FIXES:

View File

@@ -516,7 +516,7 @@ type mockProxyApp struct {
}
func (mock *mockProxyApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {
r := mock.abciResponses.DeliverTx[mock.txCount]
r := mock.abciResponses.DeliverTxs[mock.txCount]
mock.txCount++
if r == nil { //it could be nil because of amino unMarshall, it will cause an empty ResponseDeliverTx to become nil
return abci.ResponseDeliverTx{}

View File

@@ -529,8 +529,8 @@ func TestMockProxyApp(t *testing.T) {
assert.NotPanics(t, func() {
abciResWithEmptyDeliverTx := new(sm.ABCIResponses)
abciResWithEmptyDeliverTx.DeliverTx = make([]*abci.ResponseDeliverTx, 0)
abciResWithEmptyDeliverTx.DeliverTx = append(abciResWithEmptyDeliverTx.DeliverTx, &abci.ResponseDeliverTx{})
abciResWithEmptyDeliverTx.DeliverTxs = make([]*abci.ResponseDeliverTx, 0)
abciResWithEmptyDeliverTx.DeliverTxs = append(abciResWithEmptyDeliverTx.DeliverTxs, &abci.ResponseDeliverTx{})
// called when saveABCIResponses:
bytes := cdc.MustMarshalBinaryBare(abciResWithEmptyDeliverTx)
@@ -543,7 +543,7 @@ func TestMockProxyApp(t *testing.T) {
mock := newMockProxyApp([]byte("mock_hash"), loadedAbciRes)
abciRes := new(sm.ABCIResponses)
abciRes.DeliverTx = make([]*abci.ResponseDeliverTx, len(loadedAbciRes.DeliverTx))
abciRes.DeliverTxs = make([]*abci.ResponseDeliverTx, len(loadedAbciRes.DeliverTxs))
// Execute transactions and get hash.
proxyCb := func(req *abci.Request, res *abci.Response) {
switch r := res.Value.(type) {
@@ -558,7 +558,7 @@ func TestMockProxyApp(t *testing.T) {
logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log)
invalidTxs++
}
abciRes.DeliverTx[txIndex] = txRes
abciRes.DeliverTxs[txIndex] = txRes
txIndex++
}
}

View File

@@ -209,9 +209,9 @@ func TestAppCalls(t *testing.T) {
blockResults, err := c.BlockResults(&txh)
require.Nil(err, "%d: %+v", i, err)
assert.Equal(txh, blockResults.Height)
if assert.Equal(1, len(blockResults.Results.DeliverTx)) {
if assert.Equal(1, len(blockResults.TxsResults)) {
// check success code
assert.EqualValues(0, blockResults.Results.DeliverTx[0].Code)
assert.EqualValues(0, blockResults.TxsResults[0].Code)
}
// check blockchain info, now that we know there is info

View File

@@ -364,25 +364,41 @@ func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, erro
// "jsonrpc": "2.0",
// "id": "",
// "result": {
// "height": "39",
// "results": {
// "deliver_tx": [
// {
// "tags": [
// {
// "key": "YXBwLmNyZWF0b3I=",
// "value": "Q29zbW9zaGkgTmV0b3dva28="
// }
// ]
// }
// ],
// "end_block": {
// "validator_updates": null
// "height": "437",
// "txs_results": [
// {
// "gas_wanted": 1,
// "gas_used": 1,
// "events": [
// {
// "type": "app",
// "attributes": [
// {
// "key": "Y3JlYXRvcg==",
// "value": "Q29zbW9zaGkgTmV0b3dva28="
// },
// {
// "key": "a2V5",
// "value": "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA3NDZhOTQ0NDQ1N2Y2NDE4YmY3MmEyOWExNTkwNThlZDg1YmVjNWU5MDUwMDAwMDBkNmUyZWVhY2VjN2RhOTk4ZjRlNDU3MWEyZWU5NmNhYmU2NGEzNmI0MjljZTQ5NjBkZDRjMWY5ZmJlYTQyNTdlZTUxMDk1NDc3MDYyMDY1Mzg4Yjk4MGIwYWU2ZmRkYzM5YWUzNDhhZjQ3MjczOTM0YWExMTNhNTdkNmEyZDY3OWQ0ZmMyNzlkYjg5Y2I1MTM3OTNmZTYxNTc0M2E3N2Y4NzZkODUwMTkxODAzY2Y5ZGU2NjBhMWVjOThmMDcwNTI3YjJjYThkYWIwNzI5NjRhMmQ0ODI2MzU4OWM5ZGFkNWI3OTI2ODA3OWM3Mjg1YTdhMWNmODIzODllZmY2Y2ExMzczMzk5ZWFiOTI5ZmY0NGZiOGE5NGU0YjY5NGU2NDZlM2UyYmZmN2Y1MTAxN2NhNWE1NjA4YzFlZTFkZWQzMzJhNTYwYzczYmM5MzFmYjJhOTM2NjY0NzBhOTA3MDc5NGNiYzU3ODIyN2NmZDViZGVlYTQwNjcyNzhhYmI2N2ZiNzUxYTg1MzBkZDBhNGFkNDgyN2U1ZjU0MmFjZjY4OWE5N2Y="
// }
// ]
// }
// ]
// },
// "begin_block": {}
// }
// }
// }
// {
// "code": 1,
// "codespace": "ibc",
// "log": "not enough gas",
// "gas_wanted": 1,
// "gas_used": 2,
// },
// ],
// "begin_block_events": null,
// "end_block_events": null,
// "validator_updates": null,
// "consensus_param_updates": null,
// }
//}
// ```
func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockResults, error) {
storeHeight := blockStore.Height()
@@ -396,11 +412,14 @@ func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockR
return nil, err
}
res := &ctypes.ResultBlockResults{
Height: height,
Results: results,
}
return res, nil
return &ctypes.ResultBlockResults{
Height: height,
TxsResults: results.DeliverTxs,
BeginBlockEvents: results.BeginBlock.Events,
EndBlockEvents: results.EndBlock.Events,
ValidatorUpdates: results.EndBlock.ValidatorUpdates,
ConsensusParamUpdates: results.EndBlock.ConsensusParamUpdates,
}, nil
}
func getHeight(currentHeight int64, heightPtr *int64) (int64, error) {

View File

@@ -4,11 +4,18 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
rpctypes "github.com/tendermint/tendermint/rpc/lib/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-cmn/db"
)
func TestBlockchainInfo(t *testing.T) {
cases := []struct {
min, max int64
height int64
@@ -54,5 +61,61 @@ func TestBlockchainInfo(t *testing.T) {
require.Equal(t, 1+max-min, c.resultLength, caseString)
}
}
}
func TestBlockResults(t *testing.T) {
results := &sm.ABCIResponses{
DeliverTxs: []*abci.ResponseDeliverTx{
{Code: 0, Data: []byte{0x01}, Log: "ok"},
{Code: 0, Data: []byte{0x02}, Log: "ok"},
{Code: 1, Log: "not ok"},
},
EndBlock: &abci.ResponseEndBlock{},
BeginBlock: &abci.ResponseBeginBlock{},
}
stateDB = dbm.NewMemDB()
sm.SaveABCIResponses(stateDB, 100, results)
blockStore = mockBlockStore{height: 100}
testCases := []struct {
height int64
wantErr bool
wantRes *ctypes.ResultBlockResults
}{
{-1, true, nil},
{0, true, nil},
{101, true, nil},
{100, false, &ctypes.ResultBlockResults{
Height: 100,
TxsResults: results.DeliverTxs,
BeginBlockEvents: results.BeginBlock.Events,
EndBlockEvents: results.EndBlock.Events,
ValidatorUpdates: results.EndBlock.ValidatorUpdates,
ConsensusParamUpdates: results.EndBlock.ConsensusParamUpdates,
}},
}
for _, tc := range testCases {
res, err := BlockResults(&rpctypes.Context{}, &tc.height)
if tc.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tc.wantRes, res)
}
}
}
type mockBlockStore struct {
height int64
}
func (store mockBlockStore) Height() int64 { return store.height }
func (mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta { return nil }
func (mockBlockStore) LoadBlock(height int64) *types.Block { return nil }
func (mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
func (mockBlockStore) LoadBlockCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) LoadSeenCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
}

View File

@@ -9,7 +9,6 @@ import (
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
@@ -38,8 +37,12 @@ type ResultCommit struct {
// ABCI results from a block
type ResultBlockResults struct {
Height int64 `json:"height"`
Results *state.ABCIResponses `json:"results"`
Height int64 `json:"height"`
TxsResults []*abci.ResponseDeliverTx `json:"txs_results"`
BeginBlockEvents []abci.Event `json:"begin_block_events"`
EndBlockEvents []abci.Event `json:"end_block_events"`
ValidatorUpdates []abci.ValidatorUpdate `json:"validator_updates"`
ConsensusParamUpdates *abci.ConsensusParams `json:"consensus_param_updates"`
}
// NewResultCommit is a helper to initialize the ResultCommit with

View File

@@ -131,7 +131,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
fail.Fail() // XXX
// Save the results before we commit.
saveABCIResponses(blockExec.db, block.Height, abciResponses)
SaveABCIResponses(blockExec.db, block.Height, abciResponses)
fail.Fail() // XXX
@@ -156,7 +156,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
}
// Lock mempool, commit app state, update mempoool.
appHash, err := blockExec.Commit(state, block, abciResponses.DeliverTx)
appHash, err := blockExec.Commit(state, block, abciResponses.DeliverTxs)
if err != nil {
return state, fmt.Errorf("Commit failed for application: %v", err)
}
@@ -261,7 +261,7 @@ func execBlockOnProxyApp(
logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log)
invalidTxs++
}
abciResponses.DeliverTx[txIndex] = txRes
abciResponses.DeliverTxs[txIndex] = txRes
txIndex++
}
}
@@ -463,7 +463,7 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty
Height: block.Height,
Index: uint32(i),
Tx: tx,
Result: *(abciResponses.DeliverTx[i]),
Result: *(abciResponses.DeliverTxs[i]),
}})
}

View File

@@ -43,12 +43,6 @@ func CalcValidatorsKey(height int64) []byte {
return calcValidatorsKey(height)
}
// SaveABCIResponses is an alias for the private saveABCIResponses method in
// store.go, exported exclusively and explicitly for testing.
func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
saveABCIResponses(db, height, abciResponses)
}
// SaveConsensusParamsInfo is an alias for the private saveConsensusParamsInfo
// method in store.go, exported exclusively and explicitly for testing.
func SaveConsensusParamsInfo(db dbm.DB, nextHeight, changeHeight int64, params types.ConsensusParams) {

View File

@@ -92,8 +92,8 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
// Build mock responses.
block := makeBlock(state, 2)
abciResponses := sm.NewABCIResponses(block)
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Events: nil}
abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Events: nil}
abciResponses.DeliverTxs[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Events: nil}
abciResponses.DeliverTxs[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Events: nil}
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{
types.TM2PB.NewValidatorUpdate(ed25519.GenPrivKey().PubKey(), 10),
}}
@@ -162,7 +162,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
for i, tc := range cases {
h := int64(i + 1) // last block height, one below what we save
responses := &sm.ABCIResponses{
DeliverTx: tc.added,
DeliverTxs: tc.added,
EndBlock: &abci.ResponseEndBlock{},
}
sm.SaveABCIResponses(stateDB, h, responses)

View File

@@ -115,9 +115,9 @@ func saveState(db dbm.DB, state State, key []byte) {
// of the various ABCI calls during block processing.
// It is persisted to disk for each height before calling Commit.
type ABCIResponses struct {
DeliverTx []*abci.ResponseDeliverTx `json:"deliver_tx"`
EndBlock *abci.ResponseEndBlock `json:"end_block"`
BeginBlock *abci.ResponseBeginBlock `json:"begin_block"`
DeliverTxs []*abci.ResponseDeliverTx
EndBlock *abci.ResponseEndBlock
BeginBlock *abci.ResponseBeginBlock
}
// NewABCIResponses returns a new ABCIResponses
@@ -128,7 +128,7 @@ func NewABCIResponses(block *types.Block) *ABCIResponses {
resDeliverTxs = nil
}
return &ABCIResponses{
DeliverTx: resDeliverTxs,
DeliverTxs: resDeliverTxs,
}
}
@@ -138,7 +138,7 @@ func (arz *ABCIResponses) Bytes() []byte {
}
func (arz *ABCIResponses) ResultsHash() []byte {
results := types.NewResults(arz.DeliverTx)
results := types.NewResults(arz.DeliverTxs)
return results.Hash()
}
@@ -165,8 +165,9 @@ func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) {
// SaveABCIResponses persists the ABCIResponses to the database.
// This is useful in case we crash after app.Commit and before s.Save().
// Responses are indexed by height so they can also be loaded later to produce Merkle proofs.
func saveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
// Responses are indexed by height so they can also be loaded later to produce
// Merkle proofs.
func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
db.SetSync(calcABCIResponsesKey(height), abciResponses.Bytes())
}