mirror of
https://github.com/tendermint/tendermint.git
synced 2025-12-23 06:15:19 +00:00
@@ -87,6 +87,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
- [rpc] \#4979 Support EXISTS operator in `/tx_search` query (@melekes)
|
||||
- [p2p] \#4981 Expose `SaveAs` func on NodeKey (@melekes)
|
||||
- [evidence] [#4821](https://github.com/tendermint/tendermint/pull/4821) Amnesia evidence can be detected, verified and committed (@cmwaters)
|
||||
- [rpc] \#5017 Add `/check_tx` endpoint to check transactions without executing them or adding them to the mempool (@melekes)
|
||||
|
||||
### IMPROVEMENTS:
|
||||
|
||||
|
||||
@@ -144,6 +144,10 @@ func (c *Client) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
return c.next.NumUnconfirmedTxs()
|
||||
}
|
||||
|
||||
func (c *Client) CheckTx(tx types.Tx) (*ctypes.ResultCheckTx, error) {
|
||||
return c.next.CheckTx(tx)
|
||||
}
|
||||
|
||||
func (c *Client) NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
return c.next.NetInfo()
|
||||
}
|
||||
|
||||
@@ -706,9 +706,9 @@ func (cache *mapTxCache) Push(tx types.Tx) bool {
|
||||
|
||||
if cache.list.Len() >= cache.size {
|
||||
popped := cache.list.Front()
|
||||
poppedTxHash := popped.Value.([sha256.Size]byte) //nolint:staticcheck // SA5011: possible nil pointer dereference
|
||||
delete(cache.cacheMap, poppedTxHash)
|
||||
if popped != nil {
|
||||
poppedTxHash := popped.Value.([sha256.Size]byte)
|
||||
delete(cache.cacheMap, poppedTxHash)
|
||||
cache.list.Remove(popped)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -959,6 +959,7 @@ func (n *Node) ConfigureRPC() error {
|
||||
}
|
||||
rpccore.SetEnvironment(&rpccore.Environment{
|
||||
ProxyAppQuery: n.proxyApp.Query(),
|
||||
ProxyAppMempool: n.proxyApp.Mempool(),
|
||||
|
||||
StateDB: n.stateDB,
|
||||
BlockStore: n.blockStore,
|
||||
|
||||
@@ -27,6 +27,7 @@ type AppConnMempool interface {
|
||||
Error() error
|
||||
|
||||
CheckTxAsync(types.RequestCheckTx) *abcicli.ReqRes
|
||||
CheckTxSync(types.RequestCheckTx) (*types.ResponseCheckTx, error)
|
||||
|
||||
FlushAsync() *abcicli.ReqRes
|
||||
FlushSync() error
|
||||
@@ -125,6 +126,10 @@ func (app *appConnMempool) CheckTxAsync(req types.RequestCheckTx) *abcicli.ReqRe
|
||||
return app.appConn.CheckTxAsync(req)
|
||||
}
|
||||
|
||||
func (app *appConnMempool) CheckTxSync(req types.RequestCheckTx) (*types.ResponseCheckTx, error) {
|
||||
return app.appConn.CheckTxSync(req)
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implements AppConnQuery (subset of abcicli.Client)
|
||||
|
||||
|
||||
@@ -288,6 +288,15 @@ func (c *baseRPCClient) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *baseRPCClient) CheckTx(tx types.Tx) (*ctypes.ResultCheckTx, error) {
|
||||
result := new(ctypes.ResultCheckTx)
|
||||
_, err := c.caller.Call("check_tx", map[string]interface{}{"tx": tx}, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *baseRPCClient) NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
result := new(ctypes.ResultNetInfo)
|
||||
_, err := c.caller.Call("net_info", map[string]interface{}{}, result)
|
||||
|
||||
@@ -115,6 +115,7 @@ type EventsClient interface {
|
||||
type MempoolClient interface {
|
||||
UnconfirmedTxs(limit *int) (*ctypes.ResultUnconfirmedTxs, error)
|
||||
NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error)
|
||||
CheckTx(tx types.Tx) (*ctypes.ResultCheckTx, error)
|
||||
}
|
||||
|
||||
// EvidenceClient is used for submitting an evidence of the malicious
|
||||
|
||||
@@ -104,6 +104,10 @@ func (c *Local) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
return core.NumUnconfirmedTxs(c.ctx)
|
||||
}
|
||||
|
||||
func (c *Local) CheckTx(tx types.Tx) (*ctypes.ResultCheckTx, error) {
|
||||
return core.CheckTx(c.ctx, tx)
|
||||
}
|
||||
|
||||
func (c *Local) NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
return core.NetInfo(c.ctx)
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@ func (c Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error)
|
||||
return core.BroadcastTxSync(&rpctypes.Context{}, tx)
|
||||
}
|
||||
|
||||
func (c Client) CheckTx(tx types.Tx) (*ctypes.ResultCheckTx, error) {
|
||||
return core.CheckTx(&rpctypes.Context{}, tx)
|
||||
}
|
||||
|
||||
func (c Client) NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
return core.NetInfo(&rpctypes.Context{})
|
||||
}
|
||||
|
||||
@@ -392,6 +392,20 @@ func TestNumUnconfirmedTxs(t *testing.T) {
|
||||
mempool.Flush()
|
||||
}
|
||||
|
||||
func TestCheckTx(t *testing.T) {
|
||||
mempool := node.Mempool()
|
||||
|
||||
for _, c := range GetClients() {
|
||||
_, _, tx := MakeTxKV()
|
||||
|
||||
res, err := c.CheckTx(tx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, abci.CodeTypeOK, res.Code)
|
||||
|
||||
assert.Equal(t, 0, mempool.Size(), "mempool must be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTx(t *testing.T) {
|
||||
// first we broadcast a tx
|
||||
c := getHTTPClient()
|
||||
|
||||
@@ -68,6 +68,7 @@ type peers interface {
|
||||
type Environment struct {
|
||||
// external, thread safe interfaces
|
||||
ProxyAppQuery proxy.AppConnQuery
|
||||
ProxyAppMempool proxy.AppConnMempool
|
||||
|
||||
// interfaces defined in types and above
|
||||
StateDB dbm.DB
|
||||
|
||||
@@ -150,3 +150,14 @@ func NumUnconfirmedTxs(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedTxs, err
|
||||
Total: env.Mempool.Size(),
|
||||
TotalBytes: env.Mempool.TxsBytes()}, nil
|
||||
}
|
||||
|
||||
// CheckTx checks the transaction without executing it. The transaction won't
|
||||
// be added to the mempool either.
|
||||
// More: https://docs.tendermint.com/master/rpc/#/Tx/check_tx
|
||||
func CheckTx(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) {
|
||||
res, err := env.ProxyAppMempool.CheckTxSync(abci.RequestCheckTx{Tx: tx})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ctypes.ResultCheckTx{ResponseCheckTx: *res}, nil
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ var Routes = map[string]*rpc.RPCFunc{
|
||||
"block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash"),
|
||||
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
|
||||
"commit": rpc.NewRPCFunc(Commit, "height"),
|
||||
"check_tx": rpc.NewRPCFunc(CheckTx, "tx"),
|
||||
"tx": rpc.NewRPCFunc(Tx, "hash,prove"),
|
||||
"tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page,order_by"),
|
||||
"validators": rpc.NewRPCFunc(Validators, "height,page,per_page"),
|
||||
|
||||
@@ -174,6 +174,11 @@ type ResultBroadcastTxCommit struct {
|
||||
Height int64 `json:"height"`
|
||||
}
|
||||
|
||||
// ResultCheckTx wraps abci.ResponseCheckTx.
|
||||
type ResultCheckTx struct {
|
||||
abci.ResponseCheckTx
|
||||
}
|
||||
|
||||
// Result of querying for a tx
|
||||
type ResultTx struct {
|
||||
Hash bytes.HexBytes `json:"hash"`
|
||||
|
||||
@@ -153,6 +153,39 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
/check_tx:
|
||||
get:
|
||||
summary: Checks the transaction without executing it.
|
||||
tags:
|
||||
- Tx
|
||||
operationId: broadcast_tx_commit
|
||||
description: |
|
||||
The transaction won't be added to the mempool.
|
||||
|
||||
Please refer to
|
||||
https://docs.tendermint.com/master/tendermint-core/using-tendermint.html#formatting
|
||||
for formatting/encoding rules.
|
||||
parameters:
|
||||
- in: query
|
||||
name: tx
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: "785"
|
||||
description: The transaction
|
||||
responses:
|
||||
200:
|
||||
description: ABCI application's CheckTx response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CheckTxResponse"
|
||||
500:
|
||||
description: empty error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
/subscribe:
|
||||
get:
|
||||
summary: Subscribe for events via WebSocket.
|
||||
@@ -2923,6 +2956,72 @@ components:
|
||||
jsonrpc:
|
||||
type: "string"
|
||||
example: "2.0"
|
||||
CheckTxResponse:
|
||||
type: object
|
||||
required:
|
||||
- "error"
|
||||
- "result"
|
||||
- "id"
|
||||
- "jsonrpc"
|
||||
properties:
|
||||
error:
|
||||
type: "string"
|
||||
example: ""
|
||||
result:
|
||||
required:
|
||||
- "log"
|
||||
- "data"
|
||||
- "code"
|
||||
properties:
|
||||
code:
|
||||
type: "string"
|
||||
example: "0"
|
||||
data:
|
||||
type: "string"
|
||||
example: ""
|
||||
log:
|
||||
type: "string"
|
||||
example: ""
|
||||
info:
|
||||
type: "string"
|
||||
example: ""
|
||||
gas_wanted:
|
||||
type: "string"
|
||||
example: "1"
|
||||
gas_used:
|
||||
type: "string"
|
||||
example: "0"
|
||||
events:
|
||||
type: "array"
|
||||
x-nullable: true
|
||||
items:
|
||||
type: "object"
|
||||
properties:
|
||||
type:
|
||||
type: "string"
|
||||
example: "app"
|
||||
attributes:
|
||||
type: "array"
|
||||
x-nullable: false
|
||||
items:
|
||||
type: "object"
|
||||
properties:
|
||||
key:
|
||||
type: "string"
|
||||
example: "Y3JlYXRvcg=="
|
||||
value:
|
||||
type: "string"
|
||||
example: "Q29zbW9zaGkgTmV0b3dva28="
|
||||
codespace:
|
||||
type: "string"
|
||||
example: "bank"
|
||||
type: "object"
|
||||
id:
|
||||
type: "number"
|
||||
example: 0
|
||||
jsonrpc:
|
||||
type: "string"
|
||||
example: "2.0"
|
||||
BroadcastTxResponse:
|
||||
type: object
|
||||
required:
|
||||
|
||||
Reference in New Issue
Block a user