Merge branch 'master' of github.com:harmony-one/harmony into staking_devnet_fixes

pull/1936/head
Rongjian Lan 5 years ago
commit 1645d7a302
  1. 12
      consensus/quorum/one-node-staked-vote.go
  2. 102
      consensus/quorum/one-node-staked-vote_test.go
  3. 147
      consensus/reward/schedule.go
  4. 35
      consensus/votepower/roster.go
  5. 6
      consensus/votepower/roster_test.go
  6. 6
      core/block_validator.go
  7. 33
      core/blockchain.go
  8. 10
      core/evm.go
  9. 7
      core/state_transition.go
  10. 11
      core/types/block.go
  11. 24
      core/types/derive_sha.go
  12. 23
      internal/chain/reward.go
  13. 9
      staking/types/transaction.go

@ -185,7 +185,10 @@ func (v *stakedVoteWeight) SetVoters(
s, _ := v.ShardIDProvider()() s, _ := v.ShardIDProvider()()
v.Reset([]Phase{Prepare, Commit, ViewChange}) v.Reset([]Phase{Prepare, Commit, ViewChange})
roster := votepower.Compute(staked) roster, err := votepower.Compute(staked)
if err != nil {
return nil, err
}
utils.Logger().Info(). utils.Logger().Info().
Str("our-percentage", roster.OurVotingPowerTotalPercentage.String()). Str("our-percentage", roster.OurVotingPowerTotalPercentage.String()).
Str("their-percentage", roster.TheirVotingPowerTotalPercentage.String()). Str("their-percentage", roster.TheirVotingPowerTotalPercentage.String()).
@ -193,13 +196,6 @@ func (v *stakedVoteWeight) SetVoters(
Str("Raw-Staked", roster.RawStakedTotal.String()). Str("Raw-Staked", roster.RawStakedTotal.String()).
Msg("Total staked") Msg("Total staked")
//switch {
//case roster.totalStakedPercent.Equal(totalShare) == false:
// return nil, errSumOfVotingPowerNotOne
//case roster.ourPercentage.Add(theirPercentage).Equal(totalShare) == false:
// return nil, errSumOfOursAndTheirsNotOne
//}
// Hold onto this calculation // Hold onto this calculation
v.roster = *roster v.roster = *roster
return &TallyResult{ return &TallyResult{

@ -0,0 +1,102 @@
package quorum
import (
"math/big"
"math/rand"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/consensus/votepower"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
)
var (
secretKeyMap map[shard.BlsPublicKey]bls.SecretKey
slotList shard.SlotList
roster *votepower.Roster
stakedVote Decider
result *TallyResult
harmonyNodes = 33
stakedNodes = 33
maxAccountGen = int64(98765654323123134)
accountGen = rand.New(rand.NewSource(1337))
maxKeyGen = int64(98765654323123134)
keyGen = rand.New(rand.NewSource(42))
maxStakeGen = int64(200)
stakeGen = rand.New(rand.NewSource(541))
)
func init() {
slotList = shard.SlotList{}
secretKeyMap = make(map[shard.BlsPublicKey]bls.SecretKey)
for i := 0; i < harmonyNodes; i++ {
newSlot, sKey := generateRandomSlot()
newSlot.TotalStake = nil
slotList = append(slotList, newSlot)
secretKeyMap[newSlot.BlsPublicKey] = sKey
}
for j := 0; j < stakedNodes; j++ {
newSlot, sKey := generateRandomSlot()
slotList = append(slotList, newSlot)
secretKeyMap[newSlot.BlsPublicKey] = sKey
}
stakedVote = NewDecider(SuperMajorityStake)
stakedVote.SetShardIDProvider(func() (uint32, error) { return 0, nil })
r, err := stakedVote.SetVoters(slotList)
if err != nil {
panic("Unable to SetVoters")
}
result = r
}
func generateRandomSlot() (shard.Slot, bls.SecretKey) {
addr := common.Address{}
addr.SetBytes(big.NewInt(int64(accountGen.Int63n(maxAccountGen))).Bytes())
secretKey := bls.SecretKey{}
secretKey.Deserialize(big.NewInt(int64(keyGen.Int63n(maxKeyGen))).Bytes())
key := shard.BlsPublicKey{}
key.FromLibBLSPublicKey(secretKey.GetPublicKey())
stake := numeric.NewDecFromBigInt(big.NewInt(int64(stakeGen.Int63n(maxStakeGen))))
return shard.Slot{addr, key, &stake}, secretKey
}
func Test33(t *testing.T) {
sum := result.ourPercent.Add(result.theirPercent)
if !sum.Equal(numeric.OneDec()) {
t.Errorf("Total voting power does not equal 1. Harmony voting power: %s, Staked voting power: %s, Sum: %s",
result.ourPercent, result.theirPercent, sum)
}
}
func TestPolicy(t *testing.T) {
expectedPolicy := SuperMajorityStake
policy := stakedVote.Policy()
if expectedPolicy != policy {
t.Errorf("Expected: %s, Got: %s", expectedPolicy.String(), policy.String())
}
}
func TestIsQuorumAchieved(t *testing.T) {
//
}
func TestQuorumThreshold(t *testing.T) {
expectedThreshold := numeric.NewDec(2).Quo(numeric.NewDec(3))
quorumThreshold := stakedVote.QuorumThreshold()
if !expectedThreshold.Equal(quorumThreshold) {
t.Errorf("Expected: %s, Got: %s", expectedThreshold.String(), quorumThreshold.String())
}
}
func TestIsRewardThresholdAchieved(t *testing.T) {
//
}
// ????
func TestShouldSlash(t *testing.T) {
//
}

@ -0,0 +1,147 @@
package reward
import (
"sort"
"time"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric"
)
type pair struct {
ts int64
share numeric.Dec
}
var (
// schedule is the Token Release Schedule of Harmony
releasePlan = map[int64]numeric.Dec{
//2019
mustParse("2019-May-31"): numeric.MustNewDecFromStr("0.2429"),
mustParse("2019-Jun-30"): numeric.MustNewDecFromStr("0.2488"),
mustParse("2019-Jul-31"): numeric.MustNewDecFromStr("0.2547"),
mustParse("2019-Aug-31"): numeric.MustNewDecFromStr("0.2607"),
mustParse("2019-Sep-30"): numeric.MustNewDecFromStr("0.2666"),
mustParse("2019-Oct-31"): numeric.MustNewDecFromStr("0.2726"),
mustParse("2019-Nov-30"): numeric.MustNewDecFromStr("0.3785"),
mustParse("2019-Dec-31"): numeric.MustNewDecFromStr("0.3844"),
// 2020
mustParse("2020-Jan-31"): numeric.MustNewDecFromStr("0.3951"),
mustParse("2020-Feb-29"): numeric.MustNewDecFromStr("0.4047"),
mustParse("2020-Mar-31"): numeric.MustNewDecFromStr("0.4143"),
mustParse("2020-Apr-30"): numeric.MustNewDecFromStr("0.4239"),
mustParse("2020-May-31"): numeric.MustNewDecFromStr("0.5335"),
mustParse("2020-Jun-30"): numeric.MustNewDecFromStr("0.5431"),
mustParse("2020-Jul-31"): numeric.MustNewDecFromStr("0.5527"),
mustParse("2020-Aug-31"): numeric.MustNewDecFromStr("0.5623"),
mustParse("2020-Sep-30"): numeric.MustNewDecFromStr("0.5719"),
mustParse("2020-Oct-31"): numeric.MustNewDecFromStr("0.5815"),
mustParse("2020-Nov-30"): numeric.MustNewDecFromStr("0.6882"),
mustParse("2020-Dec-31"): numeric.MustNewDecFromStr("0.6948"),
// 2021
mustParse("2021-Jan-31"): numeric.MustNewDecFromStr("0.7015"),
mustParse("2021-Feb-28"): numeric.MustNewDecFromStr("0.7082"),
mustParse("2021-Mar-31"): numeric.MustNewDecFromStr("0.7148"),
mustParse("2021-Apr-30"): numeric.MustNewDecFromStr("0.7215"),
mustParse("2021-May-31"): numeric.MustNewDecFromStr("0.7721"),
mustParse("2021-Jun-30"): numeric.MustNewDecFromStr("0.7788"),
mustParse("2021-Jul-31"): numeric.MustNewDecFromStr("0.7855"),
mustParse("2021-Aug-31"): numeric.MustNewDecFromStr("0.7922"),
mustParse("2021-Sep-30"): numeric.MustNewDecFromStr("0.7988"),
mustParse("2021-Oct-31"): numeric.MustNewDecFromStr("0.8055"),
mustParse("2021-Nov-30"): numeric.MustNewDecFromStr("0.8561"),
mustParse("2021-Dec-31"): numeric.MustNewDecFromStr("0.8628"),
// 2022
mustParse("2022-Jan-31"): numeric.MustNewDecFromStr("0.8695"),
mustParse("2022-Feb-28"): numeric.MustNewDecFromStr("0.8761"),
mustParse("2022-Mar-31"): numeric.MustNewDecFromStr("0.8828"),
mustParse("2022-Apr-30"): numeric.MustNewDecFromStr("0.8895"),
mustParse("2022-May-31"): numeric.MustNewDecFromStr("0.8962"),
mustParse("2022-Jun-30"): numeric.MustNewDecFromStr("0.9028"),
mustParse("2022-Jul-31"): numeric.MustNewDecFromStr("0.9095"),
mustParse("2022-Aug-31"): numeric.MustNewDecFromStr("0.9162"),
mustParse("2022-Sep-30"): numeric.MustNewDecFromStr("0.9228"),
mustParse("2022-Oct-31"): numeric.MustNewDecFromStr("0.9295"),
mustParse("2022-Nov-30"): numeric.MustNewDecFromStr("0.9362"),
mustParse("2022-Dec-31"): numeric.MustNewDecFromStr("0.9429"),
// 2023
mustParse("2023-Jan-31"): numeric.MustNewDecFromStr("0.9448"),
mustParse("2023-Feb-28"): numeric.MustNewDecFromStr("0.9468"),
mustParse("2023-Mar-31"): numeric.MustNewDecFromStr("0.9488"),
mustParse("2023-Apr-30"): numeric.MustNewDecFromStr("0.9507"),
mustParse("2023-May-31"): numeric.MustNewDecFromStr("0.9527"),
mustParse("2023-Jun-30"): numeric.MustNewDecFromStr("0.9547"),
mustParse("2023-Jul-31"): numeric.MustNewDecFromStr("0.9567"),
mustParse("2023-Aug-31"): numeric.MustNewDecFromStr("0.9586"),
mustParse("2023-Sep-30"): numeric.MustNewDecFromStr("0.9606"),
mustParse("2023-Oct-31"): numeric.MustNewDecFromStr("0.9626"),
mustParse("2023-Nov-30"): numeric.MustNewDecFromStr("0.9645"),
mustParse("2023-Dec-31"): numeric.MustNewDecFromStr("0.9665"),
// 2024
mustParse("2024-Jan-31"): numeric.MustNewDecFromStr("0.9685"),
mustParse("2024-Feb-29"): numeric.MustNewDecFromStr("0.9704"),
mustParse("2024-Mar-31"): numeric.MustNewDecFromStr("0.9724"),
mustParse("2024-Apr-30"): numeric.MustNewDecFromStr("0.9744"),
mustParse("2024-May-31"): numeric.MustNewDecFromStr("0.9764"),
mustParse("2024-Jun-30"): numeric.MustNewDecFromStr("0.9783"),
mustParse("2024-Jul-31"): numeric.MustNewDecFromStr("0.9803"),
mustParse("2024-Aug-31"): numeric.MustNewDecFromStr("0.9823"),
mustParse("2024-Sep-30"): numeric.MustNewDecFromStr("0.9842"),
mustParse("2024-Oct-31"): numeric.MustNewDecFromStr("0.9862"),
mustParse("2024-Nov-30"): numeric.MustNewDecFromStr("0.9882"),
mustParse("2024-Dec-31"): numeric.MustNewDecFromStr("0.9901"),
// 2025
mustParse("2025-Jan-31"): numeric.MustNewDecFromStr("0.9921"),
mustParse("2025-Feb-28"): numeric.MustNewDecFromStr("0.9941"),
mustParse("2025-Mar-31"): numeric.MustNewDecFromStr("0.9961"),
mustParse("2025-Apr-30"): numeric.MustNewDecFromStr("0.9980"),
mustParse("2025-May-30"): numeric.MustNewDecFromStr("1.0000"),
}
sorted = func() []pair {
s := []pair{}
for k, v := range releasePlan {
s = append(s, pair{k, v})
}
sort.SliceStable(
s,
func(i, j int) bool { return s[i].ts < s[j].ts },
)
return s
}()
)
func mustParse(ts string) int64 {
const shortForm = "2006-Jan-02"
t, err := time.Parse(shortForm, ts)
if err != nil {
panic("could not parse timestamp")
}
return t.Unix()
}
// PercentageForTimeStamp ..
func PercentageForTimeStamp(ts int64) numeric.Dec {
bucket := pair{}
i, j := 0, 1
for range sorted {
if i == len(sorted) {
bucket = sorted[i-1]
break
}
if ts >= sorted[i].ts && ts < sorted[j].ts {
bucket = sorted[i]
break
}
i++
j++
}
utils.Logger().Info().
Str("percent of total-supply used", bucket.share.Mul(numeric.NewDec(100)).String()).
Str("for-time", time.Unix(ts, 0).String()).
Msg("Picked Percentage for timestamp")
return bucket.share
}

@ -2,8 +2,10 @@ package votepower
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
"github.com/pkg/errors"
) )
var ( var (
@ -11,11 +13,14 @@ var (
HarmonysShare = numeric.MustNewDecFromStr("0.68") HarmonysShare = numeric.MustNewDecFromStr("0.68")
// StakersShare .. // StakersShare ..
StakersShare = numeric.MustNewDecFromStr("0.32") StakersShare = numeric.MustNewDecFromStr("0.32")
// ErrVotingPowerNotEqualOne ..
ErrVotingPowerNotEqualOne = errors.New("voting power not equal to one")
) )
type stakedVoter struct { type stakedVoter struct {
IsActive, IsHarmonyNode bool IsActive, IsHarmonyNode bool
EarningAccount common.Address EarningAccount common.Address
Identity shard.BlsPublicKey
EffectivePercent numeric.Dec EffectivePercent numeric.Dec
RawStake numeric.Dec RawStake numeric.Dec
} }
@ -29,8 +34,8 @@ type Roster struct {
HmySlotCount int64 HmySlotCount int64
} }
// Compute .. // Compute creates a new roster based off the shard.SlotList
func Compute(staked shard.SlotList) *Roster { func Compute(staked shard.SlotList) (*Roster, error) {
roster := NewRoster() roster := NewRoster()
for i := range staked { for i := range staked {
if staked[i].TotalStake == nil { if staked[i].TotalStake == nil {
@ -45,12 +50,14 @@ func Compute(staked shard.SlotList) *Roster {
ourCount := numeric.NewDec(roster.HmySlotCount) ourCount := numeric.NewDec(roster.HmySlotCount)
ourPercentage := numeric.ZeroDec() ourPercentage := numeric.ZeroDec()
theirPercentage := numeric.ZeroDec() theirPercentage := numeric.ZeroDec()
var lastStakedVoter *stakedVoter = nil
for i := range staked { for i := range staked {
member := stakedVoter{ member := stakedVoter{
IsActive: true, IsActive: true,
IsHarmonyNode: true, IsHarmonyNode: true,
EarningAccount: staked[i].EcdsaAddress, EarningAccount: staked[i].EcdsaAddress,
Identity: staked[i].BlsPublicKey,
EffectivePercent: numeric.ZeroDec(), EffectivePercent: numeric.ZeroDec(),
RawStake: numeric.ZeroDec(), RawStake: numeric.ZeroDec(),
} }
@ -63,6 +70,7 @@ func Compute(staked shard.SlotList) *Roster {
Quo(roster.RawStakedTotal). Quo(roster.RawStakedTotal).
Mul(StakersShare) Mul(StakersShare)
theirPercentage = theirPercentage.Add(member.EffectivePercent) theirPercentage = theirPercentage.Add(member.EffectivePercent)
lastStakedVoter = &member
} else { // Our node } else { // Our node
// TODO See the todo on where this called in one-node-staked-vote, // TODO See the todo on where this called in one-node-staked-vote,
// need to have these two values of our // need to have these two values of our
@ -74,10 +82,31 @@ func Compute(staked shard.SlotList) *Roster {
roster.Voters[staked[i].BlsPublicKey] = member roster.Voters[staked[i].BlsPublicKey] = member
} }
// NOTE Enforce voting power sums to one, give diff (expect tiny amt) to last staked voter
if diff := numeric.OneDec().Sub(
ourPercentage.Add(theirPercentage),
); lastStakedVoter != nil {
lastStakedVoter.EffectivePercent = lastStakedVoter.EffectivePercent.Add(diff)
theirPercentage = theirPercentage.Add(diff)
utils.Logger().Info().
Str("diff", diff.String()).
Str("bls-public-key-of-receipent", lastStakedVoter.Identity.Hex()).
Msg("sum of voting power of hmy & staked slots not equal to 1, gave diff to staked slot")
}
if lastStakedVoter != nil &&
!ourPercentage.Add(theirPercentage).Equal(numeric.OneDec()) {
utils.Logger().Error().
Str("theirs", theirPercentage.String()).
Str("ours", ourPercentage.String()).
Msg("Total voting power not equal 100 percent")
return nil, ErrVotingPowerNotEqualOne
}
roster.OurVotingPowerTotalPercentage = ourPercentage roster.OurVotingPowerTotalPercentage = ourPercentage
roster.TheirVotingPowerTotalPercentage = theirPercentage roster.TheirVotingPowerTotalPercentage = theirPercentage
return roster return roster, nil
} }

@ -81,7 +81,11 @@ func TestCompute(t *testing.T) {
expectedRoster.Voters[slot.BlsPublicKey] = newMember expectedRoster.Voters[slot.BlsPublicKey] = newMember
} }
computedRoster := Compute(slotList) computedRoster, err := Compute(slotList)
if err != nil {
t.Error("Computed Roster failed on vote summation to one")
}
if !compareRosters(expectedRoster, computedRoster, t) { if !compareRosters(expectedRoster, computedRoster, t) {
t.Errorf("Compute Roster mismatch with expected Roster") t.Errorf("Compute Roster mismatch with expected Roster")
} }

@ -70,8 +70,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
//if err := v.engine.VerifyUncles(v.bc, block); err != nil { //if err := v.engine.VerifyUncles(v.bc, block); err != nil {
// return err // return err
//} //}
// TODO: Add staking transactions into txns root if hash := types.DeriveSha(
if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash() { block.Transactions(),
block.StakingTransactions(),
); hash != header.TxHash() {
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash()) return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash())
} }
return nil return nil

@ -2917,3 +2917,36 @@ func (bc *BlockChain) ValidatorCandidates() []common.Address {
func (bc *BlockChain) DelegatorsInformation(addr common.Address) []*staking.Delegation { func (bc *BlockChain) DelegatorsInformation(addr common.Address) []*staking.Delegation {
return make([]*staking.Delegation, 0) return make([]*staking.Delegation, 0)
} }
// GetECDSAFromCoinbase retrieve corresponding ecdsa address from Coinbase Address
func (bc *BlockChain) GetECDSAFromCoinbase(header *block.Header) (common.Address, error) {
// backward compatibility: before isStaking epoch, coinbase address is the ecdsa address
isStaking := bc.Config().IsStaking(header.Epoch())
if !isStaking {
return header.Coinbase(), nil
}
shardState, err := bc.ReadShardState(header.Epoch())
if err != nil {
return common.Address{}, ctxerror.New("cannot read shard state",
"epoch", header.Epoch(),
"coinbaseAddr", header.Coinbase(),
).WithCause(err)
}
committee := shardState.FindCommitteeByID(header.ShardID())
if committee == nil {
return common.Address{}, ctxerror.New("cannot find shard in the shard state",
"blockNum", header.Number(),
"shardID", header.ShardID(),
"coinbaseAddr", header.Coinbase(),
)
}
for _, member := range committee.Slots {
// After staking the coinbase address will be the address of bls public key
if utils.GetAddressFromBlsPubKeyBytes(member.BlsPublicKey[:]) == header.Coinbase() {
return member.EcdsaAddress, nil
}
}
return common.Address{}, ctxerror.New("cannot find corresponding ECDSA Address", "coinbaseAddr", header.Coinbase())
}

@ -27,6 +27,7 @@ import (
consensus_engine "github.com/harmony-one/harmony/consensus/engine" consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/utils"
) )
// ChainContext supports retrieving headers and consensus parameters from the // ChainContext supports retrieving headers and consensus parameters from the
@ -43,14 +44,21 @@ type ChainContext interface {
// ReadValidatorSnapshot returns the snapshot of validator at the beginning of current epoch. // ReadValidatorSnapshot returns the snapshot of validator at the beginning of current epoch.
ReadValidatorSnapshot(common.Address) (*types2.ValidatorWrapper, error) ReadValidatorSnapshot(common.Address) (*types2.ValidatorWrapper, error)
// GetECDSAFromCoinbase retrieves corresponding ECDSA address from the coinbase (BLS Address)
GetECDSAFromCoinbase(*block.Header) (common.Address, error)
} }
// NewEVMContext creates a new context for use in the EVM. // NewEVMContext creates a new context for use in the EVM.
func NewEVMContext(msg Message, header *block.Header, chain ChainContext, author *common.Address) vm.Context { func NewEVMContext(msg Message, header *block.Header, chain ChainContext, author *common.Address) vm.Context {
// If we don't have an explicit author (i.e. not mining), extract from the header // If we don't have an explicit author (i.e. not mining), extract from the header
var beneficiary common.Address var beneficiary common.Address
var err error
if author == nil { if author == nil {
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation beneficiary, err = chain.GetECDSAFromCoinbase(header) // Ignore error, we're past header validation
if err != nil {
utils.Logger().Warn().Msg("oops! We cannot find any beneficiary from header")
}
} else { } else {
beneficiary = *author beneficiary = *author
} }

@ -245,8 +245,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
} }
} }
st.refundGas() st.refundGas()
// TODO: need to move the gas fee to the general block rewards txFee := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) st.state.AddBalance(st.evm.Coinbase, txFee)
return ret, st.gasUsed(), vmerr != nil, err return ret, st.gasUsed(), vmerr != nil, err
} }
@ -360,6 +360,9 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) {
} }
st.refundGas() st.refundGas()
txFee := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)
st.state.AddBalance(st.evm.Coinbase, txFee)
return st.gasUsed(), err return st.gasUsed(), err
} }

@ -278,7 +278,10 @@ func init() {
// The values of TxHash, UncleHash, ReceiptHash and Bloom in header // The values of TxHash, UncleHash, ReceiptHash and Bloom in header
// are ignored and set to values derived from the given txs, // are ignored and set to values derived from the given txs,
// and receipts. // and receipts.
func NewBlock(header *block.Header, txs []*Transaction, receipts []*Receipt, outcxs []*CXReceipt, incxs []*CXReceiptsProof, stks []*staking.StakingTransaction) *Block { func NewBlock(
header *block.Header, txs []*Transaction,
receipts []*Receipt, outcxs []*CXReceipt, incxs []*CXReceiptsProof,
stks []*staking.StakingTransaction) *Block {
b := &Block{header: CopyHeader(header)} b := &Block{header: CopyHeader(header)}
if len(receipts) != len(txs)+len(stks) { if len(receipts) != len(txs)+len(stks) {
@ -294,8 +297,10 @@ func NewBlock(header *block.Header, txs []*Transaction, receipts []*Receipt, out
b.stakingTransactions = make(staking.StakingTransactions, len(stks)) b.stakingTransactions = make(staking.StakingTransactions, len(stks))
copy(b.stakingTransactions, stks) copy(b.stakingTransactions, stks)
// TODO: Add staking transactions into txns root b.header.SetTxHash(DeriveSha(
b.header.SetTxHash(DeriveSha(Transactions(txs))) Transactions(txs),
staking.StakingTransactions(stks),
))
} }
if len(receipts) == 0 { if len(receipts) == 0 {

@ -26,22 +26,32 @@ import (
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
// DerivableList is the interface of DerivableList. // DerivableBase ..
type DerivableList interface { type DerivableBase interface {
Len() int Len() int
GetRlp(i int) []byte GetRlp(i int) []byte
}
// DerivableList is the interface of DerivableList.
type DerivableList interface {
DerivableBase
ToShardID(i int) uint32 ToShardID(i int) uint32
MaxToShardID() uint32 // return the maximum non-empty destination shardID MaxToShardID() uint32 // return the maximum non-empty destination shardID
} }
// DeriveSha calculates the hash of the trie generated by DerivableList. // DeriveSha calculates the hash of the trie generated by DerivableList.
func DeriveSha(list DerivableList) common.Hash { func DeriveSha(list ...DerivableBase) common.Hash {
keybuf := new(bytes.Buffer) keybuf := new(bytes.Buffer)
trie := new(trie.Trie) trie := new(trie.Trie)
for i := 0; i < list.Len(); i++ { var num uint = 0
keybuf.Reset()
rlp.Encode(keybuf, uint(i)) for j := range list {
trie.Update(keybuf.Bytes(), list.GetRlp(i)) for i := 0; i < list[j].Len(); i++ {
keybuf.Reset()
rlp.Encode(keybuf, num)
trie.Update(keybuf.Bytes(), list[j].GetRlp(i))
num++
}
} }
return trie.Hash() return trie.Hash()
} }

@ -131,6 +131,7 @@ func ballotResultBeaconchain(
func whatPercentStakedNow( func whatPercentStakedNow(
beaconchain engine.ChainReader, beaconchain engine.ChainReader,
timestamp int64,
) (*numeric.Dec, error) { ) (*numeric.Dec, error) {
stakedNow := numeric.ZeroDec() stakedNow := numeric.ZeroDec()
// Only active validators' stake is counted in stake ratio because only their stake is under slashing risk // Only active validators' stake is counted in stake ratio because only their stake is under slashing risk
@ -154,23 +155,23 @@ func whatPercentStakedNow(
numeric.NewDecFromBigInt(wrapper.TotalDelegation()), numeric.NewDecFromBigInt(wrapper.TotalDelegation()),
) )
} }
percentage := stakedNow.Quo(totalTokens.Mul(
percentage := stakedNow.Quo(totalTokens.Add( reward.PercentageForTimeStamp(timestamp),
).Add(
numeric.NewDecFromBigInt(soFarDoledOut)), numeric.NewDecFromBigInt(soFarDoledOut)),
) )
return &percentage, nil return &percentage, nil
} }
// AccumulateRewards credits the coinbase of the given block with the mining // AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for // reward. The total reward consists of the static block reward
// included uncles. The coinbase of each uncle block is also rewarded.
func AccumulateRewards( func AccumulateRewards(
bc engine.ChainReader, state *state.DB, header *block.Header, bc engine.ChainReader, state *state.DB, header *block.Header,
rewarder reward.Distributor, slasher slash.Slasher, rewarder reward.Distributor, slasher slash.Slasher,
beaconChain engine.ChainReader, beaconChain engine.ChainReader,
) error { ) error {
blockNum := header.Number().Uint64() blockNum := header.Number().Uint64()
if blockNum == 0 { if blockNum == 0 {
// genesis block has no parent to reward. // genesis block has no parent to reward.
return nil return nil
@ -188,7 +189,7 @@ func AccumulateRewards(
defaultReward := BaseStakedReward defaultReward := BaseStakedReward
// TODO Use cached result in off-chain db instead of full computation // TODO Use cached result in off-chain db instead of full computation
percentageStaked, err := whatPercentStakedNow(beaconChain) percentageStaked, err := whatPercentStakedNow(beaconChain, header.Time().Int64())
if err != nil { if err != nil {
return err return err
} }
@ -217,7 +218,10 @@ func AccumulateRewards(
return err return err
} }
votingPower := votepower.Compute(members) votingPower, err := votepower.Compute(members)
if err != nil {
return err
}
for beaconMember := range payable { for beaconMember := range payable {
// TODO Give out whatever leftover to the last voter/handle // TODO Give out whatever leftover to the last voter/handle
@ -269,7 +273,10 @@ func AccumulateRewards(
return err return err
} }
votingPower := votepower.Compute(payableSigners) votingPower, err := votepower.Compute(payableSigners)
if err != nil {
return err
}
for j := range payableSigners { for j := range payableSigners {
voter := votingPower.Voters[payableSigners[j].BlsPublicKey] voter := votingPower.Voters[payableSigners[j].BlsPublicKey]
if !voter.IsHarmonyNode && !voter.EffectivePercent.IsZero() { if !voter.IsHarmonyNode && !voter.EffectivePercent.IsZero() {

@ -103,6 +103,15 @@ var (
// StakingTransactions is a stake slice type for basic sorting. // StakingTransactions is a stake slice type for basic sorting.
type StakingTransactions []*StakingTransaction type StakingTransactions []*StakingTransaction
// Len ..
func (s StakingTransactions) Len() int { return len(s) }
// GetRlp implements Rlpable and returns the i'th element of s in rlp.
func (s StakingTransactions) GetRlp(i int) []byte {
enc, _ := rlp.EncodeToBytes(s[i])
return enc
}
// Hash hashes the RLP encoding of tx. // Hash hashes the RLP encoding of tx.
// It uniquely identifies the transaction. // It uniquely identifies the transaction.
func (tx *StakingTransaction) Hash() common.Hash { func (tx *StakingTransaction) Hash() common.Hash {

Loading…
Cancel
Save