Browse Source

CheckTx and DeliverTx return ResponseCheckTx and ResponseDeliverTx respectively

Commit now returns ResponseCommit
pull/1780/head
Anton Kaliaev 7 years ago
parent
commit
3a3d508e5c
No known key found for this signature in database GPG Key ID: 7B6881D965918214
7 changed files with 74 additions and 44 deletions
  1. +3
    -3
      client/local_client.go
  2. +20
    -11
      example/counter/counter.go
  3. +8
    -8
      example/dummy/dummy.go
  4. +26
    -13
      example/dummy/persistent_dummy.go
  5. +3
    -3
      types/application.go
  6. +6
    -6
      types/base_app.go
  7. +8
    -0
      types/result.go

+ 3
- 3
client/local_client.go View File

@ -164,14 +164,14 @@ func (app *localClient) SetOptionSync(key string, value string) (res types.Resul
return types.OK.SetLog(log) return types.OK.SetLog(log)
} }
func (app *localClient) DeliverTxSync(tx []byte) (res types.Result) {
func (app *localClient) DeliverTxSync(tx []byte) (res types.ResponseDeliverTx) {
app.mtx.Lock() app.mtx.Lock()
res = app.Application.DeliverTx(tx) res = app.Application.DeliverTx(tx)
app.mtx.Unlock() app.mtx.Unlock()
return res return res
} }
func (app *localClient) CheckTxSync(tx []byte) (res types.Result) {
func (app *localClient) CheckTxSync(tx []byte) (res types.ResponseCheckTx) {
app.mtx.Lock() app.mtx.Lock()
res = app.Application.CheckTx(tx) res = app.Application.CheckTx(tx)
app.mtx.Unlock() app.mtx.Unlock()
@ -185,7 +185,7 @@ func (app *localClient) QuerySync(reqQuery types.RequestQuery) (resQuery types.R
return resQuery, nil return resQuery, nil
} }
func (app *localClient) CommitSync() (res types.Result) {
func (app *localClient) CommitSync() (res types.ResponseCommit) {
app.mtx.Lock() app.mtx.Lock()
res = app.Application.Commit() res = app.Application.Commit()
app.mtx.Unlock() app.mtx.Unlock()


+ 20
- 11
example/counter/counter.go View File

@ -2,6 +2,7 @@ package counter
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
@ -30,45 +31,53 @@ func (app *CounterApplication) SetOption(key string, value string) (log string)
return "" return ""
} }
func (app *CounterApplication) DeliverTx(tx []byte) types.Result {
func (app *CounterApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
if app.serial { if app.serial {
if len(tx) > 8 { if len(tx) > 8 {
return types.ErrEncodingError.SetLog(cmn.Fmt("Max tx size is 8 bytes, got %d", len(tx)))
return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Max tx size is 8 bytes, got %d", len(tx))}
} }
tx8 := make([]byte, 8) tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx) copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8) txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(app.txCount) { if txValue != uint64(app.txCount) {
return types.ErrBadNonce.SetLog(cmn.Fmt("Invalid nonce. Expected %v, got %v", app.txCount, txValue))
return types.ResponseDeliverTx{
Code: types.CodeType_BadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue)}
} }
} }
app.txCount++ app.txCount++
return types.OK
return types.ResponseDeliverTx{Code: types.CodeType_OK}
} }
func (app *CounterApplication) CheckTx(tx []byte) types.Result {
func (app *CounterApplication) CheckTx(tx []byte) types.ResponseCheckTx {
if app.serial { if app.serial {
if len(tx) > 8 { if len(tx) > 8 {
return types.ErrEncodingError.SetLog(cmn.Fmt("Max tx size is 8 bytes, got %d", len(tx)))
return types.ResponseCheckTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Max tx size is 8 bytes, got %d", len(tx))}
} }
tx8 := make([]byte, 8) tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx) copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8) txValue := binary.BigEndian.Uint64(tx8)
if txValue < uint64(app.txCount) { if txValue < uint64(app.txCount) {
return types.ErrBadNonce.SetLog(cmn.Fmt("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue))
return types.ResponseCheckTx{
Code: types.CodeType_BadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)}
} }
} }
return types.OK
return types.ResponseCheckTx{Code: types.CodeType_OK}
} }
func (app *CounterApplication) Commit() types.Result {
func (app *CounterApplication) Commit() (resp types.ResponseCommit) {
app.hashCount++ app.hashCount++
if app.txCount == 0 { if app.txCount == 0 {
return types.OK
return types.ResponseCommit{Code: types.CodeType_OK}
} }
hash := make([]byte, 8) hash := make([]byte, 8)
binary.BigEndian.PutUint64(hash, uint64(app.txCount)) binary.BigEndian.PutUint64(hash, uint64(app.txCount))
return types.NewResultOK(hash, "")
return types.ResponseCommit{Code: types.CodeType_OK, Data: hash}
} }
func (app *CounterApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { func (app *CounterApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery {


+ 8
- 8
example/dummy/dummy.go View File

@ -1,12 +1,12 @@
package dummy package dummy
import ( import (
"fmt"
"strings" "strings"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire" wire "github.com/tendermint/go-wire"
"github.com/tendermint/iavl" "github.com/tendermint/iavl"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
) )
@ -22,25 +22,25 @@ func NewDummyApplication() *DummyApplication {
} }
func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())}
return types.ResponseInfo{Data: fmt.Sprintf("{\"size\":%v}", app.state.Size())}
} }
// tx is either "key=value" or just arbitrary bytes // tx is either "key=value" or just arbitrary bytes
func (app *DummyApplication) DeliverTx(tx []byte) types.Result {
func (app *DummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
parts := strings.Split(string(tx), "=") parts := strings.Split(string(tx), "=")
if len(parts) == 2 { if len(parts) == 2 {
app.state.Set([]byte(parts[0]), []byte(parts[1])) app.state.Set([]byte(parts[0]), []byte(parts[1]))
} else { } else {
app.state.Set(tx, tx) app.state.Set(tx, tx)
} }
return types.OK
return types.ResponseDeliverTx{Code: types.CodeType_OK}
} }
func (app *DummyApplication) CheckTx(tx []byte) types.Result {
return types.OK
func (app *DummyApplication) CheckTx(tx []byte) types.ResponseCheckTx {
return types.ResponseCheckTx{Code: types.CodeType_OK}
} }
func (app *DummyApplication) Commit() types.Result {
func (app *DummyApplication) Commit() types.ResponseCommit {
// Save a new version // Save a new version
var hash []byte var hash []byte
var err error var err error
@ -55,7 +55,7 @@ func (app *DummyApplication) Commit() types.Result {
} }
} }
return types.NewResultOK(hash, "")
return types.ResponseCommit{Code: types.CodeType_OK, Data: hash}
} }
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {


+ 26
- 13
example/dummy/persistent_dummy.go View File

@ -3,6 +3,7 @@ package dummy
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"fmt"
"strconv" "strconv"
"strings" "strings"
@ -61,7 +62,7 @@ func (app *PersistentDummyApplication) SetOption(key string, value string) (log
} }
// tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes // tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes
func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result {
func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {
// if it starts with "val:", update the validator set // if it starts with "val:", update the validator set
// format is "val:pubkey/power" // format is "val:pubkey/power"
if isValidatorTx(tx) { if isValidatorTx(tx) {
@ -74,12 +75,12 @@ func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result {
return app.app.DeliverTx(tx) return app.app.DeliverTx(tx)
} }
func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result {
func (app *PersistentDummyApplication) CheckTx(tx []byte) types.ResponseCheckTx {
return app.app.CheckTx(tx) return app.app.CheckTx(tx)
} }
// Commit will panic if InitChain was not called // Commit will panic if InitChain was not called
func (app *PersistentDummyApplication) Commit() types.Result {
func (app *PersistentDummyApplication) Commit() types.ResponseCommit {
// Save a new version for next height // Save a new version for next height
height := app.app.state.LatestVersion() + 1 height := app.app.state.LatestVersion() + 1
@ -93,7 +94,7 @@ func (app *PersistentDummyApplication) Commit() types.Result {
} }
app.logger.Info("Commit block", "height", height, "root", appHash) app.logger.Info("Commit block", "height", height, "root", appHash)
return types.NewResultOK(appHash, "")
return types.ResponseCommit{Code: types.CodeType_OK, Data: appHash}
} }
func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery {
@ -148,30 +149,38 @@ func isValidatorTx(tx []byte) bool {
} }
// format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx // format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx
func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result {
func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.ResponseDeliverTx {
tx = tx[len(ValidatorSetChangePrefix):] tx = tx[len(ValidatorSetChangePrefix):]
//get the pubkey and power //get the pubkey and power
pubKeyAndPower := strings.Split(string(tx), "/") pubKeyAndPower := strings.Split(string(tx), "/")
if len(pubKeyAndPower) != 2 { if len(pubKeyAndPower) != 2 {
return types.ErrEncodingError.SetLog(cmn.Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower))
return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Expected 'pubkey/power'. Got %v", pubKeyAndPower)}
} }
pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1]
// decode the pubkey, ensuring its go-crypto encoded // decode the pubkey, ensuring its go-crypto encoded
pubkey, err := hex.DecodeString(pubkeyS) pubkey, err := hex.DecodeString(pubkeyS)
if err != nil { if err != nil {
return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%s) is invalid hex", pubkeyS))
return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Pubkey (%s) is invalid hex", pubkeyS)}
} }
_, err = crypto.PubKeyFromBytes(pubkey) _, err = crypto.PubKeyFromBytes(pubkey)
if err != nil { if err != nil {
return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%X) is invalid go-crypto encoded", pubkey))
return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Pubkey (%X) is invalid go-crypto encoded", pubkey)}
} }
// decode the power // decode the power
power, err := strconv.Atoi(powerS) power, err := strconv.Atoi(powerS)
if err != nil { if err != nil {
return types.ErrEncodingError.SetLog(cmn.Fmt("Power (%s) is not an int", powerS))
return types.ResponseDeliverTx{
Code: types.CodeType_EncodingError,
Log: fmt.Sprintf("Power (%s) is not an int", powerS)}
} }
// update // update
@ -179,19 +188,23 @@ func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result {
} }
// add, update, or remove a validator // add, update, or remove a validator
func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types.Result {
func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types.ResponseDeliverTx {
key := []byte("val:" + string(v.PubKey)) key := []byte("val:" + string(v.PubKey))
if v.Power == 0 { if v.Power == 0 {
// remove validator // remove validator
if !app.app.state.Has(key) { if !app.app.state.Has(key) {
return types.ErrUnauthorized.SetLog(cmn.Fmt("Cannot remove non-existent validator %X", key))
return types.ResponseDeliverTx{
Code: types.CodeType_Unauthorized,
Log: fmt.Sprintf("Cannot remove non-existent validator %X", key)}
} }
app.app.state.Remove(key) app.app.state.Remove(key)
} else { } else {
// add or update validator // add or update validator
value := bytes.NewBuffer(make([]byte, 0)) value := bytes.NewBuffer(make([]byte, 0))
if err := types.WriteMessage(v, value); err != nil { if err := types.WriteMessage(v, value); err != nil {
return types.ErrInternalError.SetLog(cmn.Fmt("Error encoding validator: %v", err))
return types.ResponseDeliverTx{
Code: types.CodeType_InternalError,
Log: fmt.Sprintf("Error encoding validator: %v", err)}
} }
app.app.state.Set(key, value.Bytes()) app.app.state.Set(key, value.Bytes())
} }
@ -199,5 +212,5 @@ func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types
// we only update the changes array if we successfully updated the tree // we only update the changes array if we successfully updated the tree
app.changes = append(app.changes, v) app.changes = append(app.changes, v)
return types.OK
return types.ResponseDeliverTx{Code: types.CodeType_OK}
} }

+ 3
- 3
types/application.go View File

@ -13,14 +13,14 @@ type Application interface {
Query(RequestQuery) ResponseQuery // Query for state Query(RequestQuery) ResponseQuery // Query for state
// Mempool Connection // Mempool Connection
CheckTx(tx []byte) Result // Validate a tx for the mempool
CheckTx(tx []byte) ResponseCheckTx // Validate a tx for the mempool
// Consensus Connection // Consensus Connection
InitChain(RequestInitChain) // Initialize blockchain with validators and other info from TendermintCore InitChain(RequestInitChain) // Initialize blockchain with validators and other info from TendermintCore
BeginBlock(RequestBeginBlock) // Signals the beginning of a block BeginBlock(RequestBeginBlock) // Signals the beginning of a block
DeliverTx(tx []byte) Result // Deliver a tx for full processing
DeliverTx(tx []byte) ResponseDeliverTx // Deliver a tx for full processing
EndBlock(height uint64) ResponseEndBlock // Signals the end of a block, returns changes to the validator set EndBlock(height uint64) ResponseEndBlock // Signals the end of a block, returns changes to the validator set
Commit() Result // Commit the state and return the application Merkle root hash
Commit() ResponseCommit // Commit the state and return the application Merkle root hash
} }
//------------------------------------ //------------------------------------


+ 6
- 6
types/base_app.go View File

@ -15,16 +15,16 @@ func (BaseApplication) SetOption(key string, value string) (log string) {
return "" return ""
} }
func (BaseApplication) DeliverTx(tx []byte) Result {
return NewResultOK(nil, "")
func (BaseApplication) DeliverTx(tx []byte) ResponseDeliverTx {
return ResponseDeliverTx{}
} }
func (BaseApplication) CheckTx(tx []byte) Result {
return NewResultOK(nil, "")
func (BaseApplication) CheckTx(tx []byte) ResponseCheckTx {
return ResponseCheckTx{}
} }
func (BaseApplication) Commit() Result {
return NewResultOK([]byte("nil"), "")
func (BaseApplication) Commit() ResponseCommit {
return ResponseCommit{Code: CodeType_OK, Data: []byte("nil")}
} }
func (BaseApplication) Query(req RequestQuery) ResponseQuery { func (BaseApplication) Query(req RequestQuery) ResponseQuery {


+ 8
- 0
types/result.go View File

@ -106,6 +106,10 @@ func (r *ResponseCheckTx) Result() Result {
} }
} }
func (r ResponseCheckTx) IsErr() bool {
return r.Code != CodeType_OK
}
// Convert ResponseDeliverTx to standard Result // Convert ResponseDeliverTx to standard Result
func (r *ResponseDeliverTx) Result() Result { func (r *ResponseDeliverTx) Result() Result {
return Result{ return Result{
@ -116,6 +120,10 @@ func (r *ResponseDeliverTx) Result() Result {
} }
} }
func (r ResponseDeliverTx) IsErr() bool {
return r.Code != CodeType_OK
}
type ResultQuery struct { type ResultQuery struct {
Code CodeType `json:"code"` Code CodeType `json:"code"`
Index int64 `json:"index"` Index int64 `json:"index"`


Loading…
Cancel
Save