Skip to content

Commit

Permalink
Further progress on staking (#1709)
Browse files Browse the repository at this point in the history
* [staking] Factor some project errors into values core/pkg. Thread stking Txs through Finalize

* [staking] Incorporate Chao code from PR 1700

* [staking] Remove dead staking code, create const values, factor out dec from staking

* [staking] Remove voting power for now till discussion, factor out more error values
  • Loading branch information
fxfactorial authored Oct 8, 2019
1 parent 3b52046 commit 97efce2
Show file tree
Hide file tree
Showing 33 changed files with 281 additions and 405 deletions.
2 changes: 0 additions & 2 deletions cmd/client/txgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ func setUpTXGen() *node.Node {
shardID := *shardIDFlag
selfPeer := p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: peerPubKey}

gsif, err := consensus.NewGenesisStakeInfoFinder()
// Nodes containing blockchain data to mirror the shards' data in the network

myhost, err := p2pimpl.NewHost(&selfPeer, nodePriKey)
Expand All @@ -103,7 +102,6 @@ func setUpTXGen() *node.Node {
chainDBFactory := &shardchain.MemDBFactory{}
txGen := node.New(myhost, consensusObj, chainDBFactory, false) //Changed it : no longer archival node.
txGen.Client = client.NewClient(txGen.GetHost(), uint32(shardID))
consensusObj.SetStakeInfoFinder(gsif)
consensusObj.ChainReader = txGen.Blockchain()
consensusObj.PublicKeys = nil
genesisShardingConfig := core.ShardingSchedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch))
Expand Down
44 changes: 22 additions & 22 deletions cmd/staking/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,29 +57,29 @@ func (s *staker) run(cmd *cobra.Command, args []string) error {
p.DeserializeHexStr(testBLSPubKey)
pub := shard.BlsPublicKey{}
pub.FromLibBLSPublicKey(p)
return staking.DirectiveNewValidator, staking.NewValidator{
Description: staking.Description{
Name: "something",
Identity: "something else",
Website: "some site, harmony.one",
SecurityContact: "mr.smith",
Details: "blah blah details",
},
CommissionRates: staking.CommissionRates{
Rate: staking.NewDec(100),
MaxRate: staking.NewDec(150),
MaxChangeRate: staking.NewDec(5),
},
MinSelfDelegation: big.NewInt(10),
StakingAddress: common.Address(dAddr),
PubKey: pub,
Amount: big.NewInt(100),
}
// return message.DirectiveDelegate, message.Delegate{
// common.Address(dAddr),
// common.Address(dAddr),
// big.NewInt(10),
// return staking.DirectiveNewValidator, staking.NewValidator{
// Description: staking.Description{
// Name: "something",
// Identity: "something else",
// Website: "some site, harmony.one",
// SecurityContact: "mr.smith",
// Details: "blah blah details",
// },
// CommissionRates: staking.CommissionRates{
// Rate: staking.NewDec(100),
// MaxRate: staking.NewDec(150),
// MaxChangeRate: staking.NewDec(5),
// },
// MinSelfDelegation: big.NewInt(10),
// StakingAddress: common.Address(dAddr),
// PubKey: pub,
// Amount: big.NewInt(100),
// }
return staking.DirectiveDelegate, staking.Delegate{
common.Address(dAddr),
common.Address(dAddr),
big.NewInt(10),
}
}

stakingTx, err := staking.NewStakingTransaction(2, 100, gasPrice, stakePayloadMaker)
Expand Down
35 changes: 11 additions & 24 deletions consensus/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
Consensus package includes the Harmony BFT consensus protocol code, which uses BLS-based multi-signature to cosign the new block. The details are in Harmony's new [consensus protocol design](https://talk.harmony.one/t/bls-based-practical-bft-consensus/131).
Consensus package includes the Harmony BFT consensus protocol code, which uses BLS-based
multi-signature to cosign the new block. The details are
in Harmony's new [consensus protocol design](https://talk.harmony.one/t/bls-based-practical-bft-consensus/131).

## Introduction to Harmony BFT with BLS signatures

Harmony BFT consensus protocol consist of normal mode and view changing mode which is same as the PBFT(practical byzantine fault tolerance) protocol. The difference is we use the BLS aggregated signature to reduce O(N^2) communications to O(N), which is more efficient and scalable to traditional PBFT. For brevity, we will still call the whole process as PBFT.
Harmony BFT consensus protocol consist of normal mode and view changing mode which is same
as the PBFT(practical byzantine fault tolerance) protocol. The difference is we use the
BLS aggregated signature to reduce O(N^2) communications to O(N), which is more efficient
and scalable to traditional PBFT. For brevity, we will still call the whole process as PBFT.

### Normal mode

To reach the consensus of the next block, there are 3 phases: announce(i.e. pre-prepare in PBFT), prepare and commit.
To reach the consensus of the next block, there are 3 phases: announce(i.e. pre-prepare in PBFT), prepare and commit.

* Announce(leader): The leader broadcasts ANNOUNCE message along with candidate of the next block.
* Prepare(validator): The validator will validate the block sent by leader and send PREPARE message; if the block is invalid, the validator will propose view change. If the prepare timeout, the validator will also propose view change.
Expand Down Expand Up @@ -42,8 +47,8 @@ type PbftLog struct {
messages []*PbftMessage
}
// entry point and main loop;
// in each loop, the node will receive PBFT message from peers with timeout,
// entry point and main loop;
// in each loop, the node will receive PBFT message from peers with timeout,
// then update its state accordingly. handleMessageUpdate function handles various kinds of messages and update its state
// it will also send new PBFT message (if not null) to its peers.
// in the same loop, the node will also check whether it should send view changing message to new leader
Expand Down Expand Up @@ -75,27 +80,9 @@ func (consensus *Consensus) Start(stopChan chan struct{}, stoppedChan chan struc
case <-stopChan:
return
}
}
}
}
```


















113 changes: 0 additions & 113 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,13 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/bls/ffi/go/bls"

"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/genesis"
"github.com/harmony-one/harmony/internal/memprofiling"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard"
)

const (
Expand Down Expand Up @@ -150,9 +144,6 @@ type Consensus struct {
// MessageSender takes are of sending consensus message and the corresponding retry logic.
msgSender *MessageSender

// Staking information finder
stakeInfoFinder StakeInfoFinder

// Used to convey to the consensus main loop that block syncing has finished.
syncReadyChan chan struct{}
// Used to convey to the consensus main loop that node is out of sync
Expand All @@ -171,18 +162,6 @@ func (consensus *Consensus) SetCommitDelay(delay time.Duration) {
consensus.delayCommit = delay
}

// StakeInfoFinder returns the stake information finder instance this
// consensus uses, e.g. for block reward distribution.
func (consensus *Consensus) StakeInfoFinder() StakeInfoFinder {
return consensus.stakeInfoFinder
}

// SetStakeInfoFinder sets the stake information finder instance this
// consensus uses, e.g. for block reward distribution.
func (consensus *Consensus) SetStakeInfoFinder(stakeInfoFinder StakeInfoFinder) {
consensus.stakeInfoFinder = stakeInfoFinder
}

// DisableViewChangeForTestingOnly makes the receiver not propose view
// changes when it should, e.g. leader timeout.
//
Expand Down Expand Up @@ -235,39 +214,22 @@ func (consensus *Consensus) GetBlockReward() *big.Int {
return consensus.lastBlockReward
}

// StakeInfoFinder finds the staking account for the given consensus key.
type StakeInfoFinder interface {
// FindStakeInfoByNodeKey returns a list of staking information matching
// the given node key. Caller may modify the returned slice of StakeInfo
// struct pointers, but must not modify the StakeInfo structs themselves.
FindStakeInfoByNodeKey(key *bls.PublicKey) []*structs.StakeInfo

// FindStakeInfoByAccount returns a list of staking information matching
// the given account. Caller may modify the returned slice of StakeInfo
// struct pointers, but must not modify the StakeInfo structs themselves.
FindStakeInfoByAccount(addr common.Address) []*structs.StakeInfo
}

// New creates a new Consensus object
// TODO: put shardId into chain reader's chain config
func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKey) (*Consensus, error) {
consensus := Consensus{}
consensus.host = host
consensus.msgSender = NewMessageSender(host)
consensus.blockNumLowChan = make(chan struct{})

// pbft related
consensus.PbftLog = NewPbftLog()
consensus.phase = Announce
consensus.mode = PbftMode{mode: Normal}
// pbft timeout
consensus.consensusTimeout = createTimeout()

consensus.prepareSigs = map[string]*bls.Sign{}
consensus.commitSigs = map[string]*bls.Sign{}

consensus.CommitteePublicKeys = make(map[string]bool)

consensus.validators.Store(leader.ConsensusPubKey.SerializeToHexStr(), leader)

if blsPriKey != nil {
Expand All @@ -283,90 +245,15 @@ func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKe
// as it was displayed on explorer as Height right now
consensus.viewID = 0
consensus.ShardID = ShardID

consensus.MsgChan = make(chan []byte)
consensus.syncReadyChan = make(chan struct{})
consensus.syncNotReadyChan = make(chan struct{})
consensus.commitFinishChan = make(chan uint64)

consensus.ReadySignal = make(chan struct{})
consensus.lastBlockReward = big.NewInt(0)

// channel for receiving newly generated VDF
consensus.RndChannel = make(chan [vdfAndSeedSize]byte)

consensus.uniqueIDInstance = utils.GetUniqueValidatorIDInstance()

memprofiling.GetMemProfiling().Add("consensus.pbftLog", consensus.PbftLog)
return &consensus, nil
}

// GenesisStakeInfoFinder is a stake info finder implementation using only
// genesis accounts.
// When used for block reward, it rewards only foundational nodes.
type GenesisStakeInfoFinder struct {
byNodeKey map[shard.BlsPublicKey][]*structs.StakeInfo
byAccount map[common.Address][]*structs.StakeInfo
}

// FindStakeInfoByNodeKey returns the genesis account matching the given node
// key, as a single-item StakeInfo list.
// It returns nil if the key is not a genesis node key.
func (f *GenesisStakeInfoFinder) FindStakeInfoByNodeKey(
key *bls.PublicKey,
) []*structs.StakeInfo {
var pk shard.BlsPublicKey
if err := pk.FromLibBLSPublicKey(key); err != nil {
utils.Logger().Warn().Err(err).Msg("cannot convert BLS public key")
return nil
}
l, _ := f.byNodeKey[pk]
return l
}

// FindStakeInfoByAccount returns the genesis account matching the given
// address, as a single-item StakeInfo list.
// It returns nil if the address is not a genesis account.
func (f *GenesisStakeInfoFinder) FindStakeInfoByAccount(
addr common.Address,
) []*structs.StakeInfo {
l, _ := f.byAccount[addr]
return l
}

// NewGenesisStakeInfoFinder returns a stake info finder that can look up
// genesis nodes.
func NewGenesisStakeInfoFinder() (*GenesisStakeInfoFinder, error) {
f := &GenesisStakeInfoFinder{
byNodeKey: make(map[shard.BlsPublicKey][]*structs.StakeInfo),
byAccount: make(map[common.Address][]*structs.StakeInfo),
}
for idx, account := range genesis.HarmonyAccounts {
pub := &bls.PublicKey{}
pub.DeserializeHexStr(account.BlsPublicKey)
var blsPublicKey shard.BlsPublicKey
if err := blsPublicKey.FromLibBLSPublicKey(pub); err != nil {
return nil, ctxerror.New("cannot convert BLS public key",
"accountIndex", idx,
).WithCause(err)
}
addressBytes, err := hexutil.Decode(account.Address)
if err != nil {
return nil, ctxerror.New("cannot decode account address",
"accountIndex", idx,
).WithCause(err)
}
var address common.Address
address.SetBytes(addressBytes)
stakeInfo := &structs.StakeInfo{
Account: address,
BlsPublicKey: blsPublicKey,
BlockNum: common.Big0,
LockPeriodCount: big.NewInt(0x7fffffffffffffff),
Amount: common.Big0,
}
f.byNodeKey[blsPublicKey] = append(f.byNodeKey[blsPublicKey], stakeInfo)
f.byAccount[address] = append(f.byAccount[address], stakeInfo)
}
return f, nil
}
12 changes: 8 additions & 4 deletions consensus/engine/consensus_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/params"

"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)

// ChainReader defines a small collection of methods needed to access the local
Expand Down Expand Up @@ -77,8 +77,12 @@ type Engine interface {
// and assembles the final block.
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
Finalize(chain ChainReader, header *block.Header, state *state.DB, txs []*types.Transaction,
receipts []*types.Receipt, outcxs []*types.CXReceipt, incxs []*types.CXReceiptsProof) (*types.Block, error)
Finalize(
chain ChainReader, header *block.Header, state *state.DB,
txs []*types.Transaction,
stkgTxs []*staking.StakingTransaction,
receipts []*types.Receipt, outcxs []*types.CXReceipt,
incxs []*types.CXReceiptsProof) (*types.Block, error)

// Seal generates a new sealing request for the given input block and pushes
// the result into the given channel.
Expand Down
35 changes: 0 additions & 35 deletions contracts/structs/structs.go

This file was deleted.

6 changes: 3 additions & 3 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/internal/ctxerror"

consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/values"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params"
)

Expand Down Expand Up @@ -58,7 +58,7 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Check whether the block's known, and if not, that it's linkable
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return ErrKnownBlock
return values.ErrKnownBlock
}
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
Expand Down
Loading

0 comments on commit 97efce2

Please sign in to comment.