Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Improve the way to hash genesis config (#691)
  • Loading branch information
zjshen14 committed Mar 7, 2019
1 parent 124d71a commit 82d0be5
Show file tree
Hide file tree
Showing 5 changed files with 631 additions and 16 deletions.
6 changes: 4 additions & 2 deletions api/api_test.go
Expand Up @@ -1017,8 +1017,9 @@ func TestServer_GetProductivity(t *testing.T) {
bc, _, err := setupChain(cfg)
require.NoError(err)
require.NoError(bc.Start(context.Background()))
genesisDigest := cfg.Genesis.Hash()
require.NoError(addTestingDummyBlocks(bc, test.blockProducers, test.blockProducerKeys, test.numSubEpochs,
test.failedBlockProducer))
test.failedBlockProducer, genesisDigest))
svr.bc = bc

res, err := svr.GetProductivity(context.Background(), &iotexapi.GetProductivityRequest{EpochNumber: test.epochNumber})
Expand Down Expand Up @@ -1189,9 +1190,10 @@ func addTestingDummyBlocks(
blockProducerKeys []keypair.PrivateKey,
numSubEpochs uint64,
failedBlockProducer genesis.Delegate,
genesisDigest hash.Hash256,
) error {
failedIndex := rand.Intn(int(numSubEpochs))
prevBlkHash := hash.ZeroHash256
prevBlkHash := genesisDigest
var prevBlkHeight uint64
for i := 0; i < int(numSubEpochs); i++ {
for j, bp := range blockProducers {
Expand Down
4 changes: 2 additions & 2 deletions blockchain/blockchain.go
Expand Up @@ -719,7 +719,7 @@ func (bc *blockchain) MintNewBlock(
// The first block's previous block hash is pointing to the digest of genesis config. This is to guarantee all nodes
// could verify that they start from the same genesis
if newblockHeight == 1 {
prevBlkHash = bc.config.Genesis.Digest
prevBlkHash = bc.config.Genesis.Hash()
}
blk, err := block.NewBuilder(ra).
SetPrevBlockHash(prevBlkHash).
Expand Down Expand Up @@ -1009,7 +1009,7 @@ func (bc *blockchain) validateBlock(blk *block.Block) error {
validateTimer := bc.timerFactory.NewTimer("validate")
prevBlkHash := bc.tipHash
if blk.Height() == 1 {
prevBlkHash = bc.config.Genesis.Digest
prevBlkHash = bc.config.Genesis.Hash()
}
err := bc.validator.Validate(blk, bc.tipHeight, prevBlkHash)
validateTimer.End()
Expand Down
83 changes: 71 additions & 12 deletions blockchain/genesis/genesis.go
Expand Up @@ -8,20 +8,20 @@ package genesis

import (
"flag"
"io/ioutil"
"math/big"
"sort"
"time"

"github.com/iotexproject/iotex-core/pkg/hash"

"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
"go.uber.org/config"
"go.uber.org/zap"

"github.com/iotexproject/iotex-core/address"
"github.com/iotexproject/iotex-core/pkg/hash"
"github.com/iotexproject/iotex-core/pkg/log"
"github.com/iotexproject/iotex-core/pkg/unit"
"github.com/iotexproject/iotex-core/protogen/iotextypes"
"github.com/iotexproject/iotex-core/test/identityset"
)

Expand Down Expand Up @@ -84,8 +84,6 @@ type (
Account `ymal:"account"`
Poll `yaml:"poll"`
Rewarding `yaml:"rewarding"`
// Digest is the digest of genesis config file
Digest hash.Hash256
}
// Blockchain contains blockchain level configs
Blockchain struct {
Expand Down Expand Up @@ -159,14 +157,8 @@ type (
func New() (Genesis, error) {
opts := make([]config.YAMLOption, 0)
opts = append(opts, config.Static(Default))
genesisDigest := hash.ZeroHash256
if genesisPath != "" {
opts = append(opts, config.File(genesisPath))
genesisCfgBytes, err := ioutil.ReadFile(genesisPath)
if err != nil {
return Genesis{}, err
}
genesisDigest = hash.Hash256b(genesisCfgBytes)
}
yaml, err := config.NewYAML(opts...)
if err != nil {
Expand All @@ -177,10 +169,77 @@ func New() (Genesis, error) {
if err := yaml.Get(config.Root).Populate(&genesis); err != nil {
return Genesis{}, errors.Wrap(err, "failed to unmarshal yaml genesis to struct")
}
genesis.Digest = genesisDigest
return genesis, nil
}

// Hash is the hash of genesis config
func (g *Genesis) Hash() hash.Hash256 {
gbProto := iotextypes.GenesisBlockchain{
Timestamp: g.Timestamp,
BlockGasLimit: g.BlockGasLimit,
ActionGasLimit: g.ActionGasLimit,
BlockInterval: g.BlockInterval.Nanoseconds(),
NumSubEpochs: g.NumSubEpochs,
NumDelegates: g.NumDelegates,
NumCandidateDelegates: g.NumCandidateDelegates,
TimeBasedRotation: g.TimeBasedRotation,
}

initBalanceAddrs := make([]string, 0)
for initBalanceAddr := range g.InitBalanceMap {
initBalanceAddrs = append(initBalanceAddrs, initBalanceAddr)
}
sort.Strings(initBalanceAddrs)
initBalances := make([]string, 0)
for _, initBalanceAddr := range initBalanceAddrs {
initBalances = append(initBalances, g.InitBalanceMap[initBalanceAddr])
}
aProto := iotextypes.GenesisAccount{
InitBalanceAddrs: initBalanceAddrs,
InitBalances: initBalances,
}

dProtos := make([]*iotextypes.GenesisDelegate, 0)
for _, d := range g.Delegates {
dProto := iotextypes.GenesisDelegate{
OperatorAddr: d.OperatorAddrStr,
RewardAddr: d.RewardAddrStr,
Votes: d.VotesStr,
}
dProtos = append(dProtos, &dProto)
}
pProto := iotextypes.GenesisPoll{
EnableGravityChainVoting: g.EnableGravityChainVoting,
GravityChainStartHeight: g.GravityChainStartHeight,
RegisterContractAddress: g.RegisterContractAddress,
StakingContractAddress: g.StakingContractAddress,
VoteThreshold: g.VoteThreshold,
ScoreThreshold: g.ScoreThreshold,
SelfStakingThreshold: g.SelfStakingThreshold,
Delegates: dProtos,
}

rProto := iotextypes.GenesisRewarding{
InitAdminAddr: g.InitAdminAddrStr,
InitBalance: g.InitBalanceStr,
BlockReward: g.BlockRewardStr,
EpochReward: g.EpochRewardStr,
NumDelegatesForEpochReward: g.NumDelegatesForEpochReward,
}

gProto := iotextypes.Genesis{
Blockchain: &gbProto,
Account: &aProto,
Poll: &pProto,
Rewarding: &rProto,
}
b, err := proto.Marshal(&gProto)
if err != nil {
log.L().Panic("Error when marshaling genesis proto", zap.Error(err))
}
return hash.Hash256b(b)
}

// InitBalances returns the address that have initial balances and the corresponding amounts. The i-th amount is the
// i-th address' balance.
func (a *Account) InitBalances() ([]address.Address, []*big.Int) {
Expand Down
59 changes: 59 additions & 0 deletions proto/types/genesis.proto
@@ -0,0 +1,59 @@
// Copyright (c) 2019 IoTeX
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

// To compile the proto, run:
// protoc --go_out=plugins=grpc:$GOPATH/src *.proto
syntax = "proto3";
package iotextypes;
option go_package = "github.com/iotexproject/iotex-core/protogen/iotextypes";

message Genesis {
GenesisBlockchain blockchain = 1;
GenesisAccount account = 2;
GenesisPoll poll = 3;
GenesisRewarding rewarding = 4;
}

message GenesisBlockchain {
int64 timestamp = 1;
uint64 blockGasLimit = 2;
uint64 actionGasLimit = 3;
int64 blockInterval = 4;
uint64 numSubEpochs = 5;
uint64 numDelegates = 6;
uint64 numCandidateDelegates = 7;
bool timeBasedRotation = 8;
}

message GenesisAccount {
repeated string initBalanceAddrs = 1;
repeated string initBalances = 2;
}

message GenesisPoll {
bool enableGravityChainVoting = 1;
uint64 gravityChainStartHeight = 2;
string registerContractAddress = 3;
string stakingContractAddress = 4;
string voteThreshold = 5;
string scoreThreshold = 6;
string selfStakingThreshold = 7;
repeated GenesisDelegate delegates = 8;
}

message GenesisDelegate {
string operatorAddr = 1;
string rewardAddr = 2;
string votes = 3;
}

message GenesisRewarding {
string initAdminAddr = 1;
string initBalance = 2;
string blockReward = 3;
string epochReward = 4;
uint64 numDelegatesForEpochReward = 5;
}

0 comments on commit 82d0be5

Please sign in to comment.