github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/abci/example/counter/counter.go (about)

     1  package counter
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  
     7  	"github.com/gnolang/gno/tm2/pkg/bft/abci/example/errors"
     8  	abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
     9  )
    10  
    11  type CounterApplication struct {
    12  	abci.BaseApplication
    13  
    14  	hashCount int
    15  	txCount   int
    16  	serial    bool
    17  }
    18  
    19  func NewCounterApplication(serial bool) *CounterApplication {
    20  	return &CounterApplication{serial: serial}
    21  }
    22  
    23  func (app *CounterApplication) Info(req abci.RequestInfo) abci.ResponseInfo {
    24  	return abci.ResponseInfo{ResponseBase: abci.ResponseBase{
    25  		Data: []byte(fmt.Sprintf("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)),
    26  	}}
    27  }
    28  
    29  func (app *CounterApplication) SetOption(req abci.RequestSetOption) abci.ResponseSetOption {
    30  	key, value := req.Key, req.Value
    31  	if key == "serial" && value == "on" {
    32  		app.serial = true
    33  	} else {
    34  		/*
    35  			TODO Panic and have the ABCI server pass an exception.
    36  			The client can call SetOptionSync() and get an `error`.
    37  			return abci.ResponseSetOption{
    38  				Error: fmt.Sprintf("Unknown key (%s) or value (%s)", key, value),
    39  			}
    40  		*/
    41  		return abci.ResponseSetOption{}
    42  	}
    43  
    44  	return abci.ResponseSetOption{}
    45  }
    46  
    47  func (app *CounterApplication) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {
    48  	if app.serial {
    49  		if len(req.Tx) > 8 {
    50  			return abci.ResponseDeliverTx{
    51  				ResponseBase: abci.ResponseBase{
    52  					Error: errors.EncodingError{},
    53  					Log:   fmt.Sprintf("Max tx size is 8 bytes, got %d", len(req.Tx)),
    54  				},
    55  			}
    56  		}
    57  		tx8 := make([]byte, 8)
    58  		copy(tx8[len(tx8)-len(req.Tx):], req.Tx)
    59  		txValue := binary.BigEndian.Uint64(tx8)
    60  		if txValue != uint64(app.txCount) {
    61  			return abci.ResponseDeliverTx{
    62  				ResponseBase: abci.ResponseBase{
    63  					Error: errors.BadNonceError{},
    64  					Log:   fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue),
    65  				},
    66  			}
    67  		}
    68  	}
    69  	app.txCount++
    70  	return abci.ResponseDeliverTx{}
    71  }
    72  
    73  func (app *CounterApplication) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
    74  	if app.serial {
    75  		if len(req.Tx) > 8 {
    76  			return abci.ResponseCheckTx{
    77  				ResponseBase: abci.ResponseBase{
    78  					Error: errors.EncodingError{},
    79  					Log:   fmt.Sprintf("Max tx size is 8 bytes, got %d", len(req.Tx)),
    80  				},
    81  			}
    82  		}
    83  		tx8 := make([]byte, 8)
    84  		copy(tx8[len(tx8)-len(req.Tx):], req.Tx)
    85  		txValue := binary.BigEndian.Uint64(tx8)
    86  		if txValue < uint64(app.txCount) {
    87  			return abci.ResponseCheckTx{
    88  				ResponseBase: abci.ResponseBase{
    89  					Error: errors.BadNonceError{},
    90  					Log:   fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue),
    91  				},
    92  			}
    93  		}
    94  	}
    95  	return abci.ResponseCheckTx{}
    96  }
    97  
    98  func (app *CounterApplication) Commit() (resp abci.ResponseCommit) {
    99  	app.hashCount++
   100  	if app.txCount == 0 {
   101  		return abci.ResponseCommit{}
   102  	}
   103  	hash := make([]byte, 8)
   104  	binary.BigEndian.PutUint64(hash, uint64(app.txCount))
   105  	return abci.ResponseCommit{ResponseBase: abci.ResponseBase{Data: hash}}
   106  }
   107  
   108  func (app *CounterApplication) Query(reqQuery abci.RequestQuery) abci.ResponseQuery {
   109  	switch reqQuery.Path {
   110  	case "hash":
   111  		return abci.ResponseQuery{Value: []byte(fmt.Sprintf("%v", app.hashCount))}
   112  	case "tx":
   113  		return abci.ResponseQuery{Value: []byte(fmt.Sprintf("%v", app.txCount))}
   114  	default:
   115  		return abci.ResponseQuery{ResponseBase: abci.ResponseBase{Log: fmt.Sprintf("Invalid query path. Expected hash or tx, got %v", reqQuery.Path)}}
   116  	}
   117  }