You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

286 lines
7.8 KiB

package types
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/gogo/protobuf/jsonpb"
types "github.com/tendermint/tendermint/proto/tendermint/types"
)
const (
CodeTypeOK uint32 = 0
)
// IsOK returns true if Code is OK.
func (r ResponseCheckTx) IsOK() bool {
return r.Code == CodeTypeOK
}
// IsErr returns true if Code is something other than OK.
func (r ResponseCheckTx) IsErr() bool {
return r.Code != CodeTypeOK
}
// IsOK returns true if Code is OK.
func (r ResponseDeliverTx) IsOK() bool {
return r.Code == CodeTypeOK
}
// IsErr returns true if Code is something other than OK.
func (r ResponseDeliverTx) IsErr() bool {
return r.Code != CodeTypeOK
}
// IsOK returns true if Code is OK.
func (r ExecTxResult) IsOK() bool {
return r.Code == CodeTypeOK
}
// IsErr returns true if Code is something other than OK.
func (r ExecTxResult) IsErr() bool {
return r.Code != CodeTypeOK
}
// IsOK returns true if Code is OK.
func (r ResponseQuery) IsOK() bool {
return r.Code == CodeTypeOK
}
// IsErr returns true if Code is something other than OK.
func (r ResponseQuery) IsErr() bool {
return r.Code != CodeTypeOK
}
// IsUnknown returns true if Code is Unknown
func (r ResponseVerifyVoteExtension) IsUnknown() bool {
return r.Result == ResponseVerifyVoteExtension_UNKNOWN
}
// IsOK returns true if Code is OK
func (r ResponseVerifyVoteExtension) IsOK() bool {
return r.Result == ResponseVerifyVoteExtension_ACCEPT
}
// IsErr returns true if Code is something other than OK.
func (r ResponseVerifyVoteExtension) IsErr() bool {
return r.Result != ResponseVerifyVoteExtension_ACCEPT
}
//---------------------------------------------------------------------------
// override JSON marshaling so we emit defaults (ie. disable omitempty)
var (
jsonpbMarshaller = jsonpb.Marshaler{
EnumsAsInts: true,
EmitDefaults: true,
}
jsonpbUnmarshaller = jsonpb.Unmarshaler{}
)
func (r *ResponseCheckTx) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
}
func (r *ResponseCheckTx) UnmarshalJSON(b []byte) error {
reader := bytes.NewBuffer(b)
return jsonpbUnmarshaller.Unmarshal(reader, r)
}
func (r *ResponseDeliverTx) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
}
func (r *ResponseDeliverTx) UnmarshalJSON(b []byte) error {
reader := bytes.NewBuffer(b)
return jsonpbUnmarshaller.Unmarshal(reader, r)
}
func (r *ResponseQuery) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
}
func (r *ResponseQuery) UnmarshalJSON(b []byte) error {
reader := bytes.NewBuffer(b)
return jsonpbUnmarshaller.Unmarshal(reader, r)
}
func (r *ResponseCommit) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
}
func (r *ResponseCommit) UnmarshalJSON(b []byte) error {
reader := bytes.NewBuffer(b)
return jsonpbUnmarshaller.Unmarshal(reader, r)
}
func (r *EventAttribute) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
}
func (r *EventAttribute) UnmarshalJSON(b []byte) error {
reader := bytes.NewBuffer(b)
return jsonpbUnmarshaller.Unmarshal(reader, r)
}
// Some compile time assertions to ensure we don't
// have accidental runtime surprises later on.
// jsonEncodingRoundTripper ensures that asserted
// interfaces implement both MarshalJSON and UnmarshalJSON
type jsonRoundTripper interface {
json.Marshaler
json.Unmarshaler
}
var _ jsonRoundTripper = (*ResponseCommit)(nil)
var _ jsonRoundTripper = (*ResponseQuery)(nil)
var _ jsonRoundTripper = (*ResponseDeliverTx)(nil)
var _ jsonRoundTripper = (*ResponseCheckTx)(nil)
var _ jsonRoundTripper = (*EventAttribute)(nil)
// -----------------------------------------------
// construct Result data
func RespondExtendVote(appDataToSign, appDataSelfAuthenticating []byte) ResponseExtendVote {
return ResponseExtendVote{
VoteExtension: &types.VoteExtension{
AppDataToSign: appDataToSign,
AppDataSelfAuthenticating: appDataSelfAuthenticating,
},
}
}
func RespondVerifyVoteExtension(ok bool) ResponseVerifyVoteExtension {
result := ResponseVerifyVoteExtension_REJECT
if ok {
result = ResponseVerifyVoteExtension_ACCEPT
}
return ResponseVerifyVoteExtension{
Result: result,
}
}
// deterministicExecTxResult constructs a copy of response that omits
// non-deterministic fields. The input response is not modified.
func deterministicExecTxResult(response *ExecTxResult) *ExecTxResult {
return &ExecTxResult{
Code: response.Code,
Data: response.Data,
GasWanted: response.GasWanted,
GasUsed: response.GasUsed,
}
}
// TxResultsToByteSlices encodes the the TxResults as a list of byte
// slices. It strips off the non-deterministic pieces of the TxResults
// so that the resulting data can be used for hash comparisons and used
// in Merkle proofs.
func TxResultsToByteSlices(r []*ExecTxResult) ([][]byte, error) {
s := make([][]byte, len(r))
for i, e := range r {
d := deterministicExecTxResult(e)
b, err := d.Marshal()
if err != nil {
return nil, err
}
s[i] = b
}
return s, nil
}
func (tr *TxRecord) IsIncluded() bool {
return tr.Action == TxRecord_ADDED || tr.Action == TxRecord_UNMODIFIED
}
// IncludedTxs returns all of the TxRecords that are marked for inclusion in the
// proposed block.
func (rpp *ResponsePrepareProposal) IncludedTxs() []*TxRecord {
trs := []*TxRecord{}
for _, tr := range rpp.TxRecords {
if tr.IsIncluded() {
trs = append(trs, tr)
}
}
return trs
}
// RemovedTxs returns all of the TxRecords that are marked for removal from the
// mempool.
func (rpp *ResponsePrepareProposal) RemovedTxs() []*TxRecord {
var trs []*TxRecord
for _, tr := range rpp.TxRecords {
if tr.Action == TxRecord_REMOVED {
trs = append(trs, tr)
}
}
return trs
}
// AddedTxs returns all of the TxRecords that are marked as added to the proposal.
func (rpp *ResponsePrepareProposal) AddedTxs() []*TxRecord {
var trs []*TxRecord
for _, tr := range rpp.TxRecords {
if tr.Action == TxRecord_ADDED {
trs = append(trs, tr)
}
}
return trs
}
// Validate checks that the fields of the ResponsePrepareProposal are properly
// constructed. Validate returns an error if any of the validation checks fail.
func (rpp *ResponsePrepareProposal) Validate(maxSizeBytes int64, otxs [][]byte) error {
if !rpp.ModifiedTx {
// This method currently only checks the validity of the TxRecords field.
// If ModifiedTx is false, then we can ignore the validity of the TxRecords field.
//
// TODO: When implementing VoteExensions, AppSignedUpdates may be modified by the application
// and this method should be updated to validate the AppSignedUpdates.
return nil
}
// TODO: this feels like a large amount allocated data. We move all the Txs into strings
// in the map. The map will be as large as the original byte slice.
// Is there a key we can use?
otxsSet := make(map[string]struct{}, len(otxs))
for _, tx := range otxs {
otxsSet[string(tx)] = struct{}{}
}
ntx := map[string]struct{}{}
var size int64
for _, tr := range rpp.TxRecords {
if tr.IsIncluded() {
size += int64(len(tr.Tx))
if _, ok := ntx[string(tr.Tx)]; ok {
return errors.New("duplicate included transaction")
}
ntx[string(tr.Tx)] = struct{}{}
}
if _, ok := otxsSet[string(tr.Tx)]; ok {
if tr.Action == TxRecord_ADDED {
return fmt.Errorf("unmodified transaction incorrectly marked as %s", tr.Action.String())
}
} else {
if tr.Action == TxRecord_REMOVED || tr.Action == TxRecord_UNMODIFIED {
return fmt.Errorf("new transaction incorrectly marked as %s", tr.Action.String())
}
}
if tr.Action == TxRecord_UNKNOWN {
return fmt.Errorf("transaction incorrectly marked as %s", tr.Action.String())
}
}
if size > maxSizeBytes {
return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes)
}
return nil
}