diff --git a/consensus/engine/consensus_engine.go b/consensus/engine/consensus_engine.go index 980b160c6..4ed63128e 100644 --- a/consensus/engine/consensus_engine.go +++ b/consensus/engine/consensus_engine.go @@ -10,6 +10,7 @@ import ( "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/shard" + "github.com/harmony-one/harmony/staking/slash" staking "github.com/harmony-one/harmony/staking/types" ) @@ -83,6 +84,12 @@ type Engine interface { // SetRewarder assigns the Distributor used in block reward SetRewarder(reward.Distributor) + // Slasher handles slashing accounts due to inavailibility or double-signing + Slasher() slash.Slasher + + // SetSlasher assigns the slasher used + SetSlasher(slash.Slasher) + // Finalize runs any post-transaction state modifications (e.g. block rewards) // and assembles the final block. // Note: The block header and state database might be updated to reflect any diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index 61d91cfc6..03a86acd0 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -223,27 +223,43 @@ func (s *cIdentities) ReadAllSignatures(p Phase) []*bls.Sign { return sigs } -func newMapBackedSignatureReader() SignatureReader { - return &cIdentities{ +func newMapBackedSignatureReader() cIdentities { + return cIdentities{ []*bls.PublicKey{}, map[string]*bls.Sign{}, map[string]*bls.Sign{}, map[string]*bls.Sign{}, } } +func (c *composite) ShouldSlash(shard.BlsPublicKey) bool { + s, _ := c.shardIDProvider() + switch s { + case shard.BeaconChainShardID: + return true + default: + return false + } +} + +type composite struct { + cIdentities + depInject +} + // NewDecider .. func NewDecider(p Policy) Decider { signatureStore := newMapBackedSignatureReader() - dependencies := &depInject{} + dependencies := depInject{} + c := &composite{signatureStore, dependencies} switch p { case SuperMajorityVote: - return &uniformVoteWeight{signatureStore, dependencies} + return &uniformVoteWeight{&c.cIdentities, &c.depInject} case SuperMajorityStake: return &stakedVoteWeight{ - signatureStore, - dependencies, + &c.cIdentities, &c.depInject, map[[shard.PublicKeySizeInBytes]byte]stakedVoter{}, big.NewInt(0), } + default: // Should not be possible return nil diff --git a/internal/chain/engine.go b/internal/chain/engine.go index ee6bc7289..0a1df170e 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -16,6 +16,7 @@ import ( "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard/committee" + "github.com/harmony-one/harmony/staking/slash" staking "github.com/harmony-one/harmony/staking/types" "github.com/pkg/errors" "golang.org/x/crypto/sha3" @@ -23,10 +24,11 @@ import ( type engineImpl struct { d reward.Distributor + s slash.Slasher } // Engine is an algorithm-agnostic consensus engine. -var Engine = &engineImpl{nil} +var Engine = &engineImpl{nil, nil} // Rewarder handles the distribution of block rewards func (e *engineImpl) Rewarder() reward.Distributor { @@ -38,6 +40,16 @@ func (e *engineImpl) SetRewarder(d reward.Distributor) { e.d = d } +// Slasher handles slashing accounts due to inavailibility or double-signing +func (e *engineImpl) Slasher() slash.Slasher { + return e.s +} + +// SetSlasher assigns the slasher used +func (e *engineImpl) SetSlasher(s slash.Slasher) { + e.s = s +} + // SealHash returns the hash of a block prior to it being sealed. func (e *engineImpl) SealHash(header *block.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() @@ -170,8 +182,7 @@ func (e *engineImpl) Finalize( incxs []*types.CXReceiptsProof, stks []*staking.StakingTransaction) (*types.Block, error) { // Accumulate any block and uncle rewards and commit the final state root // Header seems complete, assemble into a block and return - // TODO: Block rewards should be done only in beacon chain based on cross-links - if err := AccumulateRewards(chain, state, header, e.Rewarder()); err != nil { + if err := AccumulateRewards(chain, state, header, e.Rewarder(), e.Slasher()); err != nil { return nil, ctxerror.New("cannot pay block reward").WithCause(err) } diff --git a/internal/chain/reward.go b/internal/chain/reward.go index c4f585161..37523a723 100644 --- a/internal/chain/reward.go +++ b/internal/chain/reward.go @@ -14,6 +14,7 @@ import ( common2 "github.com/harmony-one/harmony/internal/common" "github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/utils" + "github.com/harmony-one/harmony/staking/slash" "github.com/pkg/errors" ) @@ -27,7 +28,9 @@ var ( // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. func AccumulateRewards( - bc engine.ChainReader, state *state.DB, header *block.Header, rewarder reward.Distributor, + bc engine.ChainReader, state *state.DB, + header *block.Header, rewarder reward.Distributor, + slasher slash.Slasher, ) error { blockNum := header.Number().Uint64() if blockNum == 0 { diff --git a/node/node.go b/node/node.go index f65962b5b..a76ff6993 100644 --- a/node/node.go +++ b/node/node.go @@ -33,6 +33,7 @@ import ( p2p_host "github.com/harmony-one/harmony/p2p/host" "github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard/committee" + "github.com/harmony-one/harmony/staking/slash" staking "github.com/harmony-one/harmony/staking/types" ) @@ -441,6 +442,8 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction) node.Consensus.VerifiedNewBlock = make(chan *types.Block) chain.Engine.SetRewarder(node.Consensus.Decider.(reward.Distributor)) + chain.Engine.SetSlasher(node.Consensus.Decider.(slash.Slasher)) + // the sequence number is the next block number to be added in consensus protocol, which is always one more than current chain header block node.Consensus.SetBlockNum(blockchain.CurrentBlock().NumberU64() + 1) diff --git a/staking/slash/slasher.go b/staking/slash/slasher.go new file mode 100644 index 000000000..2d6da48e2 --- /dev/null +++ b/staking/slash/slasher.go @@ -0,0 +1,8 @@ +package slash + +import "github.com/harmony-one/harmony/shard" + +// Slasher .. +type Slasher interface { + ShouldSlash(shard.BlsPublicKey) bool +}