Browse Source

rpc: simplify the encoding of interface-typed arguments in JSON (#7600)

Add package jsontypes that implements a subset of the custom libs/json 
package. Specifically it handles encoding and decoding of interface types
wrapped in "tagged" JSON objects. It omits the deep reflection on arbitrary
types, preserving only the handling of type tags wrapper encoding.

- Register interface types (Evidence, PubKey, PrivKey) for tagged encoding.
- Update the existing implementations to satisfy the type.
- Register those types with the jsontypes registry.
- Add string tags to 64-bit integer fields where needed.
- Add marshalers to structs that export interface-typed fields.
pull/7606/head
M. J. Fromberger 2 years ago
committed by GitHub
parent
commit
dbe2146d0a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 349 additions and 24 deletions
  1. +7
    -0
      crypto/crypto.go
  2. +10
    -0
      crypto/ed25519/ed25519.go
  3. +10
    -0
      crypto/secp256k1/secp256k1.go
  4. +7
    -1
      crypto/sr25519/encoding.go
  5. +3
    -0
      crypto/sr25519/privkey.go
  6. +3
    -0
      crypto/sr25519/pubkey.go
  7. +109
    -0
      internal/jsontypes/jsontypes.go
  8. +83
    -0
      internal/jsontypes/jsontypes_test.go
  9. +1
    -0
      internal/p2p/conn/secret_connection_test.go
  10. +17
    -0
      privval/file.go
  11. +3
    -1
      rpc/client/http/http.go
  12. +20
    -0
      rpc/client/http/request.go
  13. +2
    -2
      types/block.go
  14. +21
    -8
      types/evidence.go
  15. +15
    -1
      types/genesis.go
  16. +17
    -4
      types/node_key.go
  17. +18
    -4
      types/validator.go
  18. +1
    -1
      types/vote.go
  19. +2
    -2
      version/version.go

+ 7
- 0
crypto/crypto.go View File

@ -2,6 +2,7 @@ package crypto
import (
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/jsontypes"
"github.com/tendermint/tendermint/libs/bytes"
)
@ -25,6 +26,9 @@ type PubKey interface {
VerifySignature(msg []byte, sig []byte) bool
Equals(PubKey) bool
Type() string
// Implementations must support tagged encoding in JSON.
jsontypes.Tagged
}
type PrivKey interface {
@ -33,6 +37,9 @@ type PrivKey interface {
PubKey() PubKey
Equals(PrivKey) bool
Type() string
// Implementations must support tagged encoding in JSON.
jsontypes.Tagged
}
type Symmetric interface {


+ 10
- 0
crypto/ed25519/ed25519.go View File

@ -12,6 +12,7 @@ import (
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/jsontypes"
tmjson "github.com/tendermint/tendermint/libs/json"
)
@ -58,11 +59,17 @@ const (
func init() {
tmjson.RegisterType(PubKey{}, PubKeyName)
tmjson.RegisterType(PrivKey{}, PrivKeyName)
jsontypes.MustRegister(PubKey{})
jsontypes.MustRegister(PrivKey{})
}
// PrivKey implements crypto.PrivKey.
type PrivKey []byte
// TypeTag satisfies the jsontypes.Tagged interface.
func (PrivKey) TypeTag() string { return PrivKeyName }
// Bytes returns the privkey byte format.
func (privKey PrivKey) Bytes() []byte {
return []byte(privKey)
@ -151,6 +158,9 @@ var _ crypto.PubKey = PubKey{}
// PubKeyEd25519 implements crypto.PubKey for the Ed25519 signature scheme.
type PubKey []byte
// TypeTag satisfies the jsontypes.Tagged interface.
func (PubKey) TypeTag() string { return PubKeyName }
// Address is the SHA256-20 of the raw pubkey bytes.
func (pubKey PubKey) Address() crypto.Address {
if len(pubKey) != PubKeySize {


+ 10
- 0
crypto/secp256k1/secp256k1.go View File

@ -10,6 +10,7 @@ import (
secp256k1 "github.com/btcsuite/btcd/btcec"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/internal/jsontypes"
tmjson "github.com/tendermint/tendermint/libs/json"
// necessary for Bitcoin address format
@ -28,6 +29,9 @@ const (
func init() {
tmjson.RegisterType(PubKey{}, PubKeyName)
tmjson.RegisterType(PrivKey{}, PrivKeyName)
jsontypes.MustRegister(PubKey{})
jsontypes.MustRegister(PrivKey{})
}
var _ crypto.PrivKey = PrivKey{}
@ -35,6 +39,9 @@ var _ crypto.PrivKey = PrivKey{}
// PrivKey implements PrivKey.
type PrivKey []byte
// TypeTag satisfies the jsontypes.Tagged interface.
func (PrivKey) TypeTag() string { return PrivKeyName }
// Bytes marshalls the private key using amino encoding.
func (privKey PrivKey) Bytes() []byte {
return []byte(privKey)
@ -138,6 +145,9 @@ const PubKeySize = 33
// This prefix is followed with the x-coordinate.
type PubKey []byte
// TypeTag satisfies the jsontypes.Tagged interface.
func (PubKey) TypeTag() string { return PubKeyName }
// Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
func (pubKey PubKey) Address() crypto.Address {
if len(pubKey) != PubKeySize {


+ 7
- 1
crypto/sr25519/encoding.go View File

@ -1,6 +1,9 @@
package sr25519
import tmjson "github.com/tendermint/tendermint/libs/json"
import (
"github.com/tendermint/tendermint/internal/jsontypes"
tmjson "github.com/tendermint/tendermint/libs/json"
)
const (
PrivKeyName = "tendermint/PrivKeySr25519"
@ -10,4 +13,7 @@ const (
func init() {
tmjson.RegisterType(PubKey{}, PubKeyName)
tmjson.RegisterType(PrivKey{}, PrivKeyName)
jsontypes.MustRegister(PubKey{})
jsontypes.MustRegister(PrivKey{})
}

+ 3
- 0
crypto/sr25519/privkey.go View File

@ -29,6 +29,9 @@ type PrivKey struct {
kp *sr25519.KeyPair
}
// TypeTag satisfies the jsontypes.Tagged interface.
func (PrivKey) TypeTag() string { return PrivKeyName }
// Bytes returns the byte-encoded PrivKey.
func (privKey PrivKey) Bytes() []byte {
if privKey.kp == nil {


+ 3
- 0
crypto/sr25519/pubkey.go View File

@ -23,6 +23,9 @@ const (
// PubKey implements crypto.PubKey.
type PubKey []byte
// TypeTag satisfies the jsontypes.Tagged interface.
func (PubKey) TypeTag() string { return PubKeyName }
// Address is the SHA256-20 of the raw pubkey bytes.
func (pubKey PubKey) Address() crypto.Address {
if len(pubKey) != PubKeySize {


+ 109
- 0
internal/jsontypes/jsontypes.go View File

@ -0,0 +1,109 @@
// Package jsontypes supports decoding for interface types whose concrete
// implementations need to be stored as JSON. To do this, concrete values are
// packaged in wrapper objects having the form:
//
// {
// "type": "<type-tag>",
// "value": <json-encoding-of-value>
// }
//
// This package provides a registry for type tag strings and functions to
// encode and decode wrapper objects.
package jsontypes
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
)
// The Tagged interface must be implemented by a type in order to register it
// with the jsontypes package. The TypeTag method returns a string label that
// is used to distinguish objects of that type.
type Tagged interface {
TypeTag() string
}
// registry records the mapping from type tags to value types. Values in this
// map must be normalized to non-pointer types.
var registry = struct {
types map[string]reflect.Type
}{types: make(map[string]reflect.Type)}
// register adds v to the type registry. It reports an error if the tag
// returned by v is already registered.
func register(v Tagged) error {
tag := v.TypeTag()
if t, ok := registry.types[tag]; ok {
return fmt.Errorf("type tag %q already registered to %v", tag, t)
}
typ := reflect.TypeOf(v)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
registry.types[tag] = typ
return nil
}
// MustRegister adds v to the type registry. It will panic if the tag returned
// by v is already registered. This function is meant for use during program
// initialization.
func MustRegister(v Tagged) {
if err := register(v); err != nil {
panic(err)
}
}
type wrapper struct {
Type string `json:"type"`
Value json.RawMessage `json:"value"`
}
// Marshal marshals a JSON wrapper object containing v. If v == nil, Marshal
// returns the JSON "null" value without error.
func Marshal(v Tagged) ([]byte, error) {
if v == nil {
return []byte("null"), nil
}
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
return json.Marshal(wrapper{
Type: v.TypeTag(),
Value: data,
})
}
// Unmarshal unmarshals a JSON wrapper object into v. It reports an error if
// the data do not encode a valid wrapper object, if the wrapper's type tag is
// not registered with jsontypes, or if the resulting value is not compatible
// with the type of v.
func Unmarshal(data []byte, v interface{}) error {
// Verify that the target is some kind of pointer.
target := reflect.ValueOf(v)
if target.Kind() != reflect.Ptr {
return fmt.Errorf("target %T is not a pointer", v)
}
var w wrapper
dec := json.NewDecoder(bytes.NewReader(data))
dec.DisallowUnknownFields()
if err := dec.Decode(&w); err != nil {
return fmt.Errorf("invalid type wrapper: %w", err)
}
typ, ok := registry.types[w.Type]
if !ok {
return fmt.Errorf("unknown type tag: %q", w.Type)
} else if !typ.AssignableTo(target.Elem().Type()) {
return fmt.Errorf("type %v not assignable to %T", typ, v)
}
obj := reflect.New(typ)
if err := json.Unmarshal(w.Value, obj.Interface()); err != nil {
return fmt.Errorf("decoding wrapped value: %w", err)
}
target.Elem().Set(obj.Elem())
return nil
}

+ 83
- 0
internal/jsontypes/jsontypes_test.go View File

@ -0,0 +1,83 @@
package jsontypes_test
import (
"testing"
"github.com/tendermint/tendermint/internal/jsontypes"
)
type testType struct {
Field string `json:"field"`
}
func (*testType) TypeTag() string { return "test/TaggedType" }
func TestRoundTrip(t *testing.T) {
const wantEncoded = `{"type":"test/TaggedType","value":{"field":"hello"}}`
t.Run("MustRegisterOK", func(t *testing.T) {
defer func() {
if x := recover(); x != nil {
t.Fatalf("Registration panicked: %v", x)
}
}()
jsontypes.MustRegister((*testType)(nil))
})
t.Run("MustRegisterFail", func(t *testing.T) {
defer func() {
if x := recover(); x != nil {
t.Logf("Got expected panic: %v", x)
}
}()
jsontypes.MustRegister((*testType)(nil))
t.Fatal("Registration should not have succeeded")
})
t.Run("MarshalNil", func(t *testing.T) {
bits, err := jsontypes.Marshal(nil)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
if got := string(bits); got != "null" {
t.Errorf("Marshal nil: got %#q, want null", got)
}
})
t.Run("RoundTrip", func(t *testing.T) {
obj := testType{Field: "hello"}
bits, err := jsontypes.Marshal(&obj)
if err != nil {
t.Fatalf("Marshal %T failed: %v", obj, err)
}
if got := string(bits); got != wantEncoded {
t.Errorf("Marshal %T: got %#q, want %#q", obj, got, wantEncoded)
}
var cmp testType
if err := jsontypes.Unmarshal(bits, &cmp); err != nil {
t.Errorf("Unmarshal %#q failed: %v", string(bits), err)
}
if obj != cmp {
t.Errorf("Unmarshal %#q: got %+v, want %+v", string(bits), cmp, obj)
}
})
t.Run("Unregistered", func(t *testing.T) {
obj := testType{Field: "hello"}
bits, err := jsontypes.Marshal(&obj)
if err != nil {
t.Fatalf("Marshal %T failed: %v", obj, err)
}
if got := string(bits); got != wantEncoded {
t.Errorf("Marshal %T: got %#q, want %#q", obj, got, wantEncoded)
}
var cmp struct {
Field string `json:"field"`
}
if err := jsontypes.Unmarshal(bits, &cmp); err != nil {
t.Errorf("Unmarshal %#q: got %+v, want %+v", string(bits), cmp, obj)
}
})
}

+ 1
- 0
internal/p2p/conn/secret_connection_test.go View File

@ -52,6 +52,7 @@ func (pk privKeyWithNilPubKey) Sign(msg []byte) ([]byte, error) { return pk.orig
func (pk privKeyWithNilPubKey) PubKey() crypto.PubKey { return nil }
func (pk privKeyWithNilPubKey) Equals(pk2 crypto.PrivKey) bool { return pk.orig.Equals(pk2) }
func (pk privKeyWithNilPubKey) Type() string { return "privKeyWithNilPubKey" }
func (privKeyWithNilPubKey) TypeTag() string { return "test/privKeyWithNilPubKey" }
func TestSecretConnectionHandshake(t *testing.T) {
fooSecConn, barSecConn := makeSecretConnPair(t)


+ 17
- 0
privval/file.go View File

@ -14,6 +14,7 @@ import (
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/tendermint/tendermint/internal/jsontypes"
"github.com/tendermint/tendermint/internal/libs/protoio"
"github.com/tendermint/tendermint/internal/libs/tempfile"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
@ -55,6 +56,22 @@ type FilePVKey struct {
filePath string
}
func (pvKey FilePVKey) MarshalJSON() ([]byte, error) {
pubk, err := jsontypes.Marshal(pvKey.PubKey)
if err != nil {
return nil, err
}
privk, err := jsontypes.Marshal(pvKey.PrivKey)
if err != nil {
return nil, err
}
return json.Marshal(struct {
Address types.Address `json:"address"`
PubKey json.RawMessage `json:"pub_key"`
PrivKey json.RawMessage `json:"priv_key"`
}{Address: pvKey.Address, PubKey: pubk, PrivKey: privk})
}
// Save persists the FilePVKey to its filePath.
func (pvKey FilePVKey) Save() error {
outFile := pvKey.filePath


+ 3
- 1
rpc/client/http/http.go View File

@ -510,7 +510,9 @@ func (c *baseRPCClient) BroadcastEvidence(
ev types.Evidence,
) (*coretypes.ResultBroadcastEvidence, error) {
result := new(coretypes.ResultBroadcastEvidence)
if err := c.caller.Call(ctx, "broadcast_evidence", map[string]interface{}{"evidence": ev}, result); err != nil {
if err := c.caller.Call(ctx, "broadcast_evidence", evidenceArgs{
Evidence: ev,
}, result); err != nil {
return nil, err
}
return result, nil


+ 20
- 0
rpc/client/http/request.go View File

@ -4,7 +4,11 @@ package http
// from the client to the server.
import (
"encoding/json"
"github.com/tendermint/tendermint/internal/jsontypes"
"github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/types"
)
type abciQueryArgs struct {
@ -57,3 +61,19 @@ type validatorArgs struct {
Page *int `json:"page,string,omitempty"`
PerPage *int `json:"per_page,string,omitempty"`
}
type evidenceArgs struct {
Evidence types.Evidence
}
// MarshalJSON implements json.Marshaler to encode the evidence using the
// wrapped concrete type of the implementation.
func (e evidenceArgs) MarshalJSON() ([]byte, error) {
ev, err := jsontypes.Marshal(e.Evidence)
if err != nil {
return nil, err
}
return json.Marshal(struct {
Evidence json.RawMessage `json:"evidence"`
}{Evidence: ev})
}

+ 2
- 2
types/block.go View File

@ -334,7 +334,7 @@ type Header struct {
// basic block info
Version version.Consensus `json:"version"`
ChainID string `json:"chain_id"`
Height int64 `json:"height"`
Height int64 `json:"height,string"`
Time time.Time `json:"time"`
// prev block info
@ -748,7 +748,7 @@ type Commit struct {
// ValidatorSet order.
// Any peer with a block can gossip signatures by index with a peer without
// recalculating the active ValidatorSet.
Height int64 `json:"height"`
Height int64 `json:"height,string"`
Round int32 `json:"round"`
BlockID BlockID `json:"block_id"`
Signatures []CommitSig `json:"signatures"`


+ 21
- 8
types/evidence.go View File

@ -13,6 +13,7 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/internal/jsontypes"
tmjson "github.com/tendermint/tendermint/libs/json"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@ -28,6 +29,9 @@ type Evidence interface {
String() string // string format of the evidence
Time() time.Time // time of the infraction
ValidateBasic() error // basic consistency check
// Implementations must support tagged encoding in JSON.
jsontypes.Tagged
}
//--------------------------------------------------------------------------------------
@ -38,11 +42,14 @@ type DuplicateVoteEvidence struct {
VoteB *Vote `json:"vote_b"`
// abci specific information
TotalVotingPower int64
ValidatorPower int64
TotalVotingPower int64 `json:",string"`
ValidatorPower int64 `json:",string"`
Timestamp time.Time
}
// TypeTag implements the jsontypes.Tagged interface.
func (*DuplicateVoteEvidence) TypeTag() string { return "tendermint/DuplicateVoteEvidence" }
var _ Evidence = &DuplicateVoteEvidence{}
// NewDuplicateVoteEvidence creates DuplicateVoteEvidence with right ordering given
@ -236,14 +243,17 @@ func DuplicateVoteEvidenceFromProto(pb *tmproto.DuplicateVoteEvidence) (*Duplica
// height, then nodes will treat this as of the Lunatic form, else it is of the Equivocation form.
type LightClientAttackEvidence struct {
ConflictingBlock *LightBlock
CommonHeight int64
CommonHeight int64 `json:",string"`
// abci specific information
ByzantineValidators []*Validator // validators in the validator set that misbehaved in creating the conflicting block
TotalVotingPower int64 // total voting power of the validator set at the common height
TotalVotingPower int64 `json:",string"` // total voting power of the validator set at the common height
Timestamp time.Time // timestamp of the block at the common height
}
// TypeTag implements the jsontypes.Tagged interface.
func (*LightClientAttackEvidence) TypeTag() string { return "tendermint/LightClientAttackEvidence" }
var _ Evidence = &LightClientAttackEvidence{}
// ABCI forms an array of abci evidence for each byzantine validator
@ -365,10 +375,10 @@ func (l *LightClientAttackEvidence) Height() int64 {
// String returns a string representation of LightClientAttackEvidence
func (l *LightClientAttackEvidence) String() string {
return fmt.Sprintf(`LightClientAttackEvidence{
ConflictingBlock: %v,
CommonHeight: %d,
ByzatineValidators: %v,
TotalVotingPower: %d,
ConflictingBlock: %v,
CommonHeight: %d,
ByzatineValidators: %v,
TotalVotingPower: %d,
Timestamp: %v}#%X`,
l.ConflictingBlock.String(), l.CommonHeight, l.ByzantineValidators,
l.TotalVotingPower, l.Timestamp, l.Hash())
@ -630,6 +640,9 @@ func EvidenceFromProto(evidence *tmproto.Evidence) (Evidence, error) {
func init() {
tmjson.RegisterType(&DuplicateVoteEvidence{}, "tendermint/DuplicateVoteEvidence")
tmjson.RegisterType(&LightClientAttackEvidence{}, "tendermint/LightClientAttackEvidence")
jsontypes.MustRegister((*DuplicateVoteEvidence)(nil))
jsontypes.MustRegister((*LightClientAttackEvidence)(nil))
}
//-------------------------------------------- ERRORS --------------------------------------


+ 15
- 1
types/genesis.go View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/internal/jsontypes"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmjson "github.com/tendermint/tendermint/libs/json"
tmtime "github.com/tendermint/tendermint/libs/time"
@ -29,10 +30,23 @@ const (
type GenesisValidator struct {
Address Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
Power int64 `json:"power"`
Power int64 `json:"power,string"`
Name string `json:"name"`
}
func (g GenesisValidator) MarshalJSON() ([]byte, error) {
pk, err := jsontypes.Marshal(g.PubKey)
if err != nil {
return nil, err
}
return json.Marshal(struct {
Address Address `json:"address"`
PubKey json.RawMessage `json:"pub_key"`
Power int64 `json:"power,string"`
Name string `json:"name"`
}{Address: g.Address, PubKey: pk, Power: g.Power, Name: g.Name})
}
// GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set.
type GenesisDoc struct {
GenesisTime time.Time `json:"genesis_time"`


+ 17
- 4
types/node_key.go View File

@ -1,10 +1,12 @@
package types
import (
"encoding/json"
"os"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/internal/jsontypes"
tmjson "github.com/tendermint/tendermint/libs/json"
tmos "github.com/tendermint/tendermint/libs/os"
)
@ -22,14 +24,25 @@ type NodeKey struct {
PrivKey crypto.PrivKey `json:"priv_key"`
}
func (nk NodeKey) MarshalJSON() ([]byte, error) {
pk, err := jsontypes.Marshal(nk.PrivKey)
if err != nil {
return nil, err
}
return json.Marshal(struct {
ID NodeID `json:"id"`
PrivKey json.RawMessage `json:"priv_key"`
}{ID: nk.ID, PrivKey: pk})
}
// PubKey returns the peer's PubKey
func (nodeKey NodeKey) PubKey() crypto.PubKey {
return nodeKey.PrivKey.PubKey()
func (nk NodeKey) PubKey() crypto.PubKey {
return nk.PrivKey.PubKey()
}
// SaveAs persists the NodeKey to filePath.
func (nodeKey NodeKey) SaveAs(filePath string) error {
jsonBytes, err := tmjson.Marshal(nodeKey)
func (nk NodeKey) SaveAs(filePath string) error {
jsonBytes, err := tmjson.Marshal(nk)
if err != nil {
return err
}


+ 18
- 4
types/validator.go View File

@ -2,12 +2,14 @@ package types
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/encoding"
"github.com/tendermint/tendermint/internal/jsontypes"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
@ -15,11 +17,23 @@ import (
// NOTE: The ProposerPriority is not included in Validator.Hash();
// make sure to update that method if changes are made here
type Validator struct {
Address Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
VotingPower int64 `json:"voting_power"`
Address Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
VotingPower int64 `json:"voting_power,string"`
ProposerPriority int64 `json:"proposer_priority,string"`
}
ProposerPriority int64 `json:"proposer_priority"`
func (v Validator) MarshalJSON() ([]byte, error) {
pk, err := jsontypes.Marshal(v.PubKey)
if err != nil {
return nil, err
}
return json.Marshal(struct {
Addr Address `json:"address"`
PubKey json.RawMessage `json:"pub_key"`
Power int64 `json:"voting_power,string"`
Priority int64 `json:"proposer_priority,string"`
}{Addr: v.Address, PubKey: pk, Power: v.VotingPower, Priority: v.ProposerPriority})
}
// NewValidator returns a new validator with the given pubkey and voting power.


+ 1
- 1
types/vote.go View File

@ -49,7 +49,7 @@ type Address = crypto.Address
// consensus.
type Vote struct {
Type tmproto.SignedMsgType `json:"type"`
Height int64 `json:"height"`
Height int64 `json:"height,string"`
Round int32 `json:"round"` // assume there will not be greater than 2_147_483_647 rounds
BlockID BlockID `json:"block_id"` // zero if vote is nil.
Timestamp time.Time `json:"timestamp"`


+ 2
- 2
version/version.go View File

@ -28,8 +28,8 @@ var (
)
type Consensus struct {
Block uint64 `json:"block"`
App uint64 `json:"app"`
Block uint64 `json:"block,string"`
App uint64 `json:"app,string"`
}
func (c Consensus) ToProto() tmversion.Consensus {


Loading…
Cancel
Save