Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Feature/add validator #2

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions pkg/app/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/bluele/hypermint/pkg/contract"
"github.com/bluele/hypermint/pkg/handler"
"github.com/bluele/hypermint/pkg/transaction"
"github.com/bluele/hypermint/pkg/validator"
)

const (
Expand All @@ -50,6 +51,7 @@ type Chain struct {
// keys to access the substores
capKeyMainStore *sdk.KVStoreKey
contractStore *sdk.KVStoreKey
validatorStore *sdk.KVStoreKey
}

func NewChain(logger log.Logger, db db.DB, traceStore io.Writer) *Chain {
Expand All @@ -65,7 +67,9 @@ func NewChain(logger log.Logger, db db.DB, traceStore io.Writer) *Chain {
cmn := contract.NewContractManager(cm)
envm := contract.NewEnvManager(c.contractStore, cm)

c.SetHandler(handler.NewHandler(am, cmn, envm))
valm := validator.NewValidatorMapper(c.validatorStore)

c.SetHandler(handler.NewHandler(am, cmn, envm, valm))
c.SetAnteHandler(handler.NewAnteHandler(am))
c.SetInitChainer(GetInitChainer(am))

Expand All @@ -79,7 +83,7 @@ func NewChain(logger log.Logger, db db.DB, traceStore io.Writer) *Chain {

func (c *Chain) mountStores() error {
keys := []*sdk.KVStoreKey{
c.capKeyMainStore, c.contractStore,
c.capKeyMainStore, c.contractStore, c.validatorStore,
}

c.MountStoresIAVL(keys...)
Expand Down
23 changes: 22 additions & 1 deletion pkg/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"github.com/bluele/hypermint/pkg/account"
"github.com/bluele/hypermint/pkg/contract"
"github.com/bluele/hypermint/pkg/transaction"
"github.com/bluele/hypermint/pkg/validator"
"github.com/ethereum/go-ethereum/common"
)

func NewHandler(am account.AccountMapper, cm *contract.ContractManager, envm *contract.EnvManager) types.Handler {
func NewHandler(am account.AccountMapper, cm *contract.ContractManager, envm *contract.EnvManager, valm validator.ValidatorMapper) types.Handler {
return func(ctx types.Context, tx types.Tx) types.Result {
switch tx := tx.(type) {
case *transaction.TransferTx:
Expand All @@ -18,6 +20,10 @@ func NewHandler(am account.AccountMapper, cm *contract.ContractManager, envm *co
return handleContractDeployTx(ctx, cm, envm, tx)
case *transaction.ContractCallTx:
return handleContractCallTx(ctx, cm, envm, tx)
case *transaction.ValidatorAddTx:
return handleValidatorAddTx(ctx, tx, valm)
case *transaction.ValidatorRemoveTx:
return handleValidatorRemoveTx(ctx, tx, valm)
default:
errMsg := "Unrecognized Tx type: " + reflect.TypeOf(tx).Name()
return types.ErrUnknownRequest(errMsg).Result()
Expand Down Expand Up @@ -57,3 +63,18 @@ func handleContractCallTx(ctx types.Context, cm *contract.ContractManager, envm
Data: res,
}
}

// TODO subtract bonded amount from the balance
func handleValidatorAddTx(ctx types.Context, tx *transaction.ValidatorAddTx, valm validator.ValidatorMapper) types.Result {
val := validator.MakeValidatorFromTx(tx)
if err := valm.Set(ctx, val); err != nil {
return transaction.ErrInvalidValidatorAdd(transaction.DefaultCodespace, err.Error()).Result()
}
return types.Result{}
}

// TODO return bonded amount to the balance
func handleValidatorRemoveTx(ctx types.Context, tx *transaction.ValidatorRemoveTx, valm validator.ValidatorMapper) types.Result {
valm.Remove(ctx, common.BytesToAddress(tx.PubKey.Bytes()))
return types.Result{}
}
2 changes: 2 additions & 0 deletions pkg/transaction/contract_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const (
ContractInitFunc = "init"
)

var _ Transaction = &ContractCallTx{}

type ContractCallTx struct {
Address common.Address
Func string // function name
Expand Down
2 changes: 2 additions & 0 deletions pkg/transaction/contract_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)

var _ Transaction = &ContractDeployTx{}

type ContractDeployTx struct {
Code []byte
CommonTx
Expand Down
25 changes: 20 additions & 5 deletions pkg/transaction/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import (
const (
DefaultCodespace types.CodespaceType = "2"

CodeInvalidTx types.CodeType = 101
CodeInvalidTransfer types.CodeType = 102
CodeFailTransfer types.CodeType = 103
CodeInvalidDeploy types.CodeType = 104
CodeInvalidCall types.CodeType = 105
CodeInvalidTx types.CodeType = 101
CodeInvalidTransfer types.CodeType = 102
CodeFailTransfer types.CodeType = 103
CodeInvalidDeploy types.CodeType = 104
CodeInvalidCall types.CodeType = 105
CodeInvalidValidatorAdd types.CodeType = 106
CodeInvalidValidatorRemove types.CodeType = 107
CodeInvalidDelegation types.CodeType = 108
)

// NOTE: Don't stringer this, we'll put better messages in later.
Expand Down Expand Up @@ -48,6 +51,18 @@ func ErrInvalidCall(codespace types.CodespaceType, msg string) types.Error {
return newError(codespace, CodeInvalidCall, msg)
}

func ErrInvalidValidatorAdd(codespace types.CodespaceType, msg string) types.Error {
return newError(codespace, CodeInvalidValidatorAdd, msg)
}

func ErrInvalidValidatorRemove(codespace types.CodespaceType, msg string) types.Error {
return newError(codespace, CodeInvalidValidatorRemove, msg)
}

func ErrInvalidDelegation(codespace types.CodespaceType, msg string) types.Error {
return newError(codespace, CodeInvalidDelegation, msg)
}

//----------------------------------------

func msgOrDefaultMsg(msg string, code types.CodeType) string {
Expand Down
4 changes: 4 additions & 0 deletions pkg/transaction/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ const (
TRANSFER uint8 = 1 + iota
CONTRACT_DEPLOY
CONTRACT_CALL
VALIDATOR_ADD
VALIDATOR_REMOVE
VALIDATOR_DELEGATE
)

type Transaction interface {
types.Tx
GetSignBytes() []byte
SetSignature([]byte)
Decode(b []byte) error
Bytes() []byte
}

Expand Down
6 changes: 1 addition & 5 deletions pkg/transaction/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)

var emptyAddr common.Address
var _ Transaction = &TransferTx{}

type TransferTx struct {
To common.Address
Expand Down Expand Up @@ -49,7 +49,3 @@ func (tx *TransferTx) Bytes() []byte {
}
return append([]byte{TRANSFER}, b...)
}

func isEmptyAddr(addr common.Address) bool {
return addr == emptyAddr
}
6 changes: 6 additions & 0 deletions pkg/transaction/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import (
"github.com/ethereum/go-ethereum/common"
)

var emptyAddr common.Address

func GetNonceByAddress(addr common.Address) (uint64, error) {
return uint64(time.Now().UnixNano()), nil
}

func isEmptyAddr(addr common.Address) bool {
return addr == emptyAddr
}
85 changes: 85 additions & 0 deletions pkg/transaction/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package transaction

import (
"github.com/bluele/hypermint/pkg/abci/types"
"github.com/bluele/hypermint/pkg/util"
"github.com/ethereum/go-ethereum/rlp"
"github.com/tendermint/tendermint/crypto"
)

var _ Transaction = &ValidatorAddTx{}

type ValidatorAddTx struct {
PubKey crypto.PubKey
Amount uint64
Commitment []byte
CommonTx
}

func (tx *ValidatorAddTx) Decode(b []byte) error {
return rlp.DecodeBytes(b, tx)
}

func (tx *ValidatorAddTx) ValidateBasic() types.Error {
if err := tx.CommonTx.ValidateBasic(); err != nil {
return err
}
if tx.Amount == 0 {
return ErrInvalidTransfer(DefaultCodespace, "tx.Amount == 0")
}
return tx.VerifySignature(tx.GetSignBytes())
}

func (tx *ValidatorAddTx) GetSignBytes() []byte {
ntx := *tx
ntx.Signature = nil
b, err := rlp.EncodeToBytes(ntx)
if err != nil {
panic(err)
}
return util.TxHash(b)
}

func (tx *ValidatorAddTx) Bytes() []byte {
b, err := rlp.EncodeToBytes(tx)
if err != nil {
panic(err)
}
return append([]byte{VALIDATOR_ADD}, b...)
}

var _ Transaction = &ValidatorRemoveTx{}

type ValidatorRemoveTx struct {
PubKey crypto.PubKey
CommonTx
}

func (tx *ValidatorRemoveTx) Decode(b []byte) error {
return rlp.DecodeBytes(b, tx)
}

func (tx *ValidatorRemoveTx) ValidateBasic() types.Error {
if err := tx.CommonTx.ValidateBasic(); err != nil {
return err
}
return tx.VerifySignature(tx.GetSignBytes())
}

func (tx *ValidatorRemoveTx) GetSignBytes() []byte {
ntx := *tx
ntx.Signature = nil
b, err := rlp.EncodeToBytes(ntx)
if err != nil {
panic(err)
}
return util.TxHash(b)
}

func (tx *ValidatorRemoveTx) Bytes() []byte {
b, err := rlp.EncodeToBytes(tx)
if err != nil {
panic(err)
}
return append([]byte{VALIDATOR_REMOVE}, b...)
}
17 changes: 17 additions & 0 deletions pkg/validator/amino.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package validator

import (
"github.com/tendermint/go-amino"
)

var cdc = amino.NewCodec()

func init() {
RegisterAmino(cdc)
}

// RegisterAmino registers all go-crypto related types in the given (amino) codec.
func RegisterAmino(cdc *amino.Codec) {
cdc.RegisterConcrete(Validator{},
"hypermint/Validator", nil)
}
34 changes: 34 additions & 0 deletions pkg/validator/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package validator

import (
"crypto/ecdsa"

gcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/secp256k1"
pvm "github.com/tendermint/tendermint/privval"
)

func GenFilePV(path string, prv crypto.PrivKey) *pvm.FilePV {
privValidator := pvm.GenFilePV(path)
privValidator.PrivKey = prv
privValidator.PubKey = prv.PubKey()
privValidator.Address = prv.PubKey().Address()
privValidator.Save()
return privValidator
}

func GenFilePVWithECDSA(path string, prv *ecdsa.PrivateKey) *pvm.FilePV {
pb := gcrypto.FromECDSA(prv)
var p secp256k1.PrivKeySecp256k1
copy(p[:], pb)
return GenFilePV(path, p)
}

func bytesToECDSAPrvKey(b []byte) *ecdsa.PrivateKey {
pv, err := gcrypto.ToECDSA(b)
if err != nil {
panic(err)
}
return pv
}
63 changes: 63 additions & 0 deletions pkg/validator/mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package validator

import (
"errors"

"github.com/bluele/hypermint/pkg/abci/types"
"github.com/ethereum/go-ethereum/common"
)

var (
ErrKeyNotFound = errors.New("key not found")
ErrKeyAlreadyExist = errors.New("key already exist")
)

type ValidatorMapper interface {
Set(types.Context, *Validator) error
Get(types.Context, common.Address) (*Validator, error)
Remove(types.Context, common.Address)
}

type validatorMapper struct {
storeKey types.StoreKey
}

func NewValidatorMapper(storeKey types.StoreKey) ValidatorMapper {
return &validatorMapper{storeKey: storeKey}
}

func (vm *validatorMapper) Set(ctx types.Context, val *Validator) error {
_, err := vm.Get(ctx, val.Address)
if err == nil {
return ErrKeyAlreadyExist
} else if err != ErrKeyNotFound {
return err
}

store := vm.getStore(ctx)
b, err := cdc.MarshalBinaryBare(*val)
if err != nil {
return err
}
store.Set(val.Address.Bytes(), b)
return nil
}

func (vm *validatorMapper) Get(ctx types.Context, addr common.Address) (*Validator, error) {
store := vm.getStore(ctx)
b := store.Get(addr.Bytes())
if b == nil {
return nil, ErrKeyNotFound
}
val := new(Validator)
return val, cdc.UnmarshalBinaryBare(b, val)
}

func (vm *validatorMapper) Remove(ctx types.Context, addr common.Address) {
store := vm.getStore(ctx)
store.Delete(addr.Bytes())
}

func (vm *validatorMapper) getStore(ctx types.Context) types.KVStore {
return ctx.KVStore(vm.storeKey)
}
Loading