diff --git a/crypto/crypto.go b/crypto/crypto.go index 8d44b82f5..4f0dc05e7 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -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 { diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index 3ac7f6d07..8673ff4d5 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -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 { diff --git a/crypto/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go index c2c0c6017..f92b29c1f 100644 --- a/crypto/secp256k1/secp256k1.go +++ b/crypto/secp256k1/secp256k1.go @@ -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 { diff --git a/crypto/sr25519/encoding.go b/crypto/sr25519/encoding.go index c0a8a7925..8827ee0b1 100644 --- a/crypto/sr25519/encoding.go +++ b/crypto/sr25519/encoding.go @@ -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{}) } diff --git a/crypto/sr25519/privkey.go b/crypto/sr25519/privkey.go index f628ca1aa..4e9cc995f 100644 --- a/crypto/sr25519/privkey.go +++ b/crypto/sr25519/privkey.go @@ -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 { diff --git a/crypto/sr25519/pubkey.go b/crypto/sr25519/pubkey.go index 7e701dd1f..717f25c8c 100644 --- a/crypto/sr25519/pubkey.go +++ b/crypto/sr25519/pubkey.go @@ -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 { diff --git a/internal/jsontypes/jsontypes.go b/internal/jsontypes/jsontypes.go new file mode 100644 index 000000000..a4c3c53ff --- /dev/null +++ b/internal/jsontypes/jsontypes.go @@ -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": "", +// "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 +} diff --git a/internal/jsontypes/jsontypes_test.go b/internal/jsontypes/jsontypes_test.go new file mode 100644 index 000000000..b721e2b84 --- /dev/null +++ b/internal/jsontypes/jsontypes_test.go @@ -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) + } + }) +} diff --git a/internal/p2p/conn/secret_connection_test.go b/internal/p2p/conn/secret_connection_test.go index 7bc5e0b34..362c8102f 100644 --- a/internal/p2p/conn/secret_connection_test.go +++ b/internal/p2p/conn/secret_connection_test.go @@ -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) diff --git a/privval/file.go b/privval/file.go index a075323a8..b11346dc7 100644 --- a/privval/file.go +++ b/privval/file.go @@ -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 diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index 7dd6abb76..f10985ae3 100644 --- a/rpc/client/http/http.go +++ b/rpc/client/http/http.go @@ -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 diff --git a/rpc/client/http/request.go b/rpc/client/http/request.go index 5d1d3db5b..a6f85b637 100644 --- a/rpc/client/http/request.go +++ b/rpc/client/http/request.go @@ -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}) +} diff --git a/types/block.go b/types/block.go index e09d1830a..241c360de 100644 --- a/types/block.go +++ b/types/block.go @@ -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"` diff --git a/types/evidence.go b/types/evidence.go index fa530761f..cca6fc899 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -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 -------------------------------------- diff --git a/types/genesis.go b/types/genesis.go index a4b3904ab..d89de6ea2 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -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"` diff --git a/types/node_key.go b/types/node_key.go index aecbd8a21..8f59b6085 100644 --- a/types/node_key.go +++ b/types/node_key.go @@ -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 } diff --git a/types/validator.go b/types/validator.go index ded8156bf..9d48c93e7 100644 --- a/types/validator.go +++ b/types/validator.go @@ -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. diff --git a/types/vote.go b/types/vote.go index 52fb73ec5..ceae65e48 100644 --- a/types/vote.go +++ b/types/vote.go @@ -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"` diff --git a/version/version.go b/version/version.go index e42952f77..483fca031 100644 --- a/version/version.go +++ b/version/version.go @@ -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 {