package types import ( "fmt" "reflect" "time" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" cryptoenc "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/crypto/sr25519" tmproto "github.com/tendermint/tendermint/proto/types" ) //------------------------------------------------------- // Use strings to distinguish types in ABCI messages const ( ABCIEvidenceTypeDuplicateVote = "duplicate/vote" ABCIEvidenceTypeMock = "mock/evidence" ) const ( ABCIPubKeyTypeEd25519 = "ed25519" ABCIPubKeyTypeSr25519 = "sr25519" ABCIPubKeyTypeSecp256k1 = "secp256k1" ) // TODO: Make non-global by allowing for registration of more pubkey types var ABCIPubKeyTypesToNames = map[string]string{ ABCIPubKeyTypeEd25519: ed25519.PubKeyName, ABCIPubKeyTypeSr25519: sr25519.PubKeyName, ABCIPubKeyTypeSecp256k1: secp256k1.PubKeyName, } //------------------------------------------------------- // TM2PB is used for converting Tendermint ABCI to protobuf ABCI. // UNSTABLE var TM2PB = tm2pb{} type tm2pb struct{} func (tm2pb) Header(header *Header) tmproto.Header { return tmproto.Header{ Version: header.Version, ChainID: header.ChainID, Height: header.Height, Time: header.Time, LastBlockId: header.LastBlockID.ToProto(), LastCommitHash: header.LastCommitHash, DataHash: header.DataHash, ValidatorsHash: header.ValidatorsHash, NextValidatorsHash: header.NextValidatorsHash, ConsensusHash: header.ConsensusHash, AppHash: header.AppHash, LastResultsHash: header.LastResultsHash, EvidenceHash: header.EvidenceHash, ProposerAddress: header.ProposerAddress, } } func (tm2pb) Validator(val *Validator) abci.Validator { return abci.Validator{ Address: val.PubKey.Address(), Power: val.VotingPower, } } func (tm2pb) BlockID(blockID BlockID) abci.BlockID { return abci.BlockID{ Hash: blockID.Hash, PartsHeader: TM2PB.PartSetHeader(blockID.PartsHeader), } } func (tm2pb) PartSetHeader(header PartSetHeader) abci.PartSetHeader { return abci.PartSetHeader{ Total: int32(header.Total), Hash: header.Hash, } } // XXX: panics on unknown pubkey type func (tm2pb) ValidatorUpdate(val *Validator) abci.ValidatorUpdate { pk, err := cryptoenc.PubKeyToProto(val.PubKey) if err != nil { panic(err) } return abci.ValidatorUpdate{ PubKey: pk, Power: val.VotingPower, } } // XXX: panics on nil or unknown pubkey type func (tm2pb) ValidatorUpdates(vals *ValidatorSet) []abci.ValidatorUpdate { validators := make([]abci.ValidatorUpdate, vals.Size()) for i, val := range vals.Validators { validators[i] = TM2PB.ValidatorUpdate(val) } return validators } func (tm2pb) ConsensusParams(params *tmproto.ConsensusParams) *abci.ConsensusParams { return &abci.ConsensusParams{ Block: &abci.BlockParams{ MaxBytes: params.Block.MaxBytes, MaxGas: params.Block.MaxGas, }, Evidence: ¶ms.Evidence, Validator: ¶ms.Validator, } } // ABCI Evidence includes information from the past that's not included in the evidence itself // so Evidence types stays compact. // XXX: panics on nil or unknown pubkey type func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.Evidence { addr := ev.Address() _, val := valSet.GetByAddress(addr) if val == nil { // should already have checked this panic(val) } // set type var evType string switch ev.(type) { case *DuplicateVoteEvidence: evType = ABCIEvidenceTypeDuplicateVote case *PhantomValidatorEvidence: evType = "phantom" case *LunaticValidatorEvidence: evType = "lunatic" case *PotentialAmnesiaEvidence: evType = "potential_amnesia" case MockEvidence: // XXX: not great to have test types in production paths ... evType = ABCIEvidenceTypeMock default: panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev))) } return abci.Evidence{ Type: evType, Validator: TM2PB.Validator(val), Height: ev.Height(), Time: evTime, TotalVotingPower: valSet.TotalVotingPower(), } } // XXX: panics on nil or unknown pubkey type func (tm2pb) NewValidatorUpdate(pubkey crypto.PubKey, power int64) abci.ValidatorUpdate { pubkeyABCI, err := cryptoenc.PubKeyToProto(pubkey) if err != nil { panic(err) } return abci.ValidatorUpdate{ PubKey: pubkeyABCI, Power: power, } } //---------------------------------------------------------------------------- // PB2TM is used for converting protobuf ABCI to Tendermint ABCI. // UNSTABLE var PB2TM = pb2tm{} type pb2tm struct{} func (pb2tm) ValidatorUpdates(vals []abci.ValidatorUpdate) ([]*Validator, error) { tmVals := make([]*Validator, len(vals)) for i, v := range vals { pub, err := cryptoenc.PubKeyFromProto(v.PubKey) if err != nil { return nil, err } tmVals[i] = NewValidator(pub, v.Power) } return tmVals, nil }