Merge pull request #560 from harmony-one/rj_branch

Setup genesis shard state, and fix other issues
pull/563/head
Rongjian Lan 6 years ago committed by GitHub
commit 197e4c9552
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      core/blockchain.go
  2. 58
      core/gen_genesis.go
  3. 46
      core/genesis.go
  4. 32
      core/resharding.go
  5. 3
      node/node.go
  6. 7
      node/node_genesis.go
  7. 4
      node/node_handler.go
  8. 4
      node/node_newblock.go
  9. 1
      test/configs/beaconchain.txt

@ -1732,8 +1732,8 @@ func (bc *BlockChain) ValidateNewShardState(block *types.Block, stakeInfo *map[c
return nil return nil
} }
// InsertNewShardState insert new shard state into epoch block // StoreNewShardState insert new shard state into epoch block
func (bc *BlockChain) InsertNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) { func (bc *BlockChain) StoreNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) {
// write state into db. // write state into db.
shardState := bc.GetNewShardState(block, stakeInfo) shardState := bc.GetNewShardState(block, stakeInfo)
if shardState == nil { if shardState == nil {
@ -1742,8 +1742,8 @@ func (bc *BlockChain) InsertNewShardState(block *types.Block, stakeInfo *map[com
hash := block.Hash() hash := block.Hash()
number := block.NumberU64() number := block.NumberU64()
rawdb.WriteShardState(bc.db, hash, number, shardState) rawdb.WriteShardState(bc.db, hash, number, shardState)
utils.GetLogInstance().Debug("[resharding] save new shard state success", "shardStateHash", shardState.Hash()) utils.GetLogInstance().Debug("[Resharding] Saved new shard state success", "shardStateHash", shardState.Hash())
for _, c := range shardState { for _, c := range shardState {
utils.GetLogInstance().Debug("[resharding] new shard information", "shardID", c.ShardID, "NodeList", c.NodeList) utils.GetLogInstance().Debug("[Resharding] Shard Info", "shardID", c.ShardID, "NodeList", c.NodeList)
} }
} }

@ -18,19 +18,20 @@ var _ = (*genesisSpecMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (g Genesis) MarshalJSON() ([]byte, error) { func (g Genesis) MarshalJSON() ([]byte, error) {
type Genesis struct { type Genesis struct {
Config *params.ChainConfig `json:"config"` Config *params.ChainConfig `json:"config"`
Nonce math.HexOrDecimal64 `json:"nonce"` Nonce math.HexOrDecimal64 `json:"nonce"`
ShardID uint32 `json:"shardID"` ShardID uint32 `json:"shardID"`
Timestamp math.HexOrDecimal64 `json:"timestamp"` Timestamp math.HexOrDecimal64 `json:"timestamp"`
ExtraData hexutil.Bytes `json:"extraData"` ExtraData hexutil.Bytes `json:"extraData"`
GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
Mixhash common.Hash `json:"mixHash"` Mixhash common.Hash `json:"mixHash"`
Coinbase common.Address `json:"coinbase"` Coinbase common.Address `json:"coinbase"`
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"`
Number math.HexOrDecimal64 `json:"number"` ShardStateHash common.Hash `json:"shardStateHash"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"` Number math.HexOrDecimal64 `json:"number"`
ParentHash common.Hash `json:"parentHash"` GasUsed math.HexOrDecimal64 `json:"gasUsed"`
ParentHash common.Hash `json:"parentHash"`
} }
var enc Genesis var enc Genesis
enc.Config = g.Config enc.Config = g.Config
@ -48,6 +49,7 @@ func (g Genesis) MarshalJSON() ([]byte, error) {
enc.Alloc[common.UnprefixedAddress(k)] = v enc.Alloc[common.UnprefixedAddress(k)] = v
} }
} }
enc.ShardStateHash = g.ShardStateHash
enc.Number = math.HexOrDecimal64(g.Number) enc.Number = math.HexOrDecimal64(g.Number)
enc.GasUsed = math.HexOrDecimal64(g.GasUsed) enc.GasUsed = math.HexOrDecimal64(g.GasUsed)
enc.ParentHash = g.ParentHash enc.ParentHash = g.ParentHash
@ -57,19 +59,20 @@ func (g Genesis) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (g *Genesis) UnmarshalJSON(input []byte) error { func (g *Genesis) UnmarshalJSON(input []byte) error {
type Genesis struct { type Genesis struct {
Config *params.ChainConfig `json:"config"` Config *params.ChainConfig `json:"config"`
Nonce *math.HexOrDecimal64 `json:"nonce"` Nonce *math.HexOrDecimal64 `json:"nonce"`
ShardID *uint32 `json:"shardID"` ShardID *uint32 `json:"shardID"`
Timestamp *math.HexOrDecimal64 `json:"timestamp"` Timestamp *math.HexOrDecimal64 `json:"timestamp"`
ExtraData *hexutil.Bytes `json:"extraData"` ExtraData *hexutil.Bytes `json:"extraData"`
GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
Mixhash *common.Hash `json:"mixHash"` Mixhash *common.Hash `json:"mixHash"`
Coinbase *common.Address `json:"coinbase"` Coinbase *common.Address `json:"coinbase"`
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"`
Number *math.HexOrDecimal64 `json:"number"` ShardStateHash *common.Hash `json:"shardStateHash"`
GasUsed *math.HexOrDecimal64 `json:"gasUsed"` Number *math.HexOrDecimal64 `json:"number"`
ParentHash *common.Hash `json:"parentHash"` GasUsed *math.HexOrDecimal64 `json:"gasUsed"`
ParentHash *common.Hash `json:"parentHash"`
} }
var dec Genesis var dec Genesis
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -111,6 +114,9 @@ func (g *Genesis) UnmarshalJSON(input []byte) error {
for k, v := range dec.Alloc { for k, v := range dec.Alloc {
g.Alloc[common.Address(k)] = v g.Alloc[common.Address(k)] = v
} }
if dec.ShardStateHash != nil {
g.ShardStateHash = *dec.ShardStateHash
}
if dec.Number != nil { if dec.Number != nil {
g.Number = uint64(*dec.Number) g.Number = uint64(*dec.Number)
} }

@ -45,16 +45,17 @@ var errGenesisNoConfig = errors.New("genesis has no chain configuration")
// Genesis specifies the header fields, state of a genesis block. It also defines hard // Genesis specifies the header fields, state of a genesis block. It also defines hard
// fork switch-over blocks through the chain configuration. // fork switch-over blocks through the chain configuration.
type Genesis struct { type Genesis struct {
Config *params.ChainConfig `json:"config"` Config *params.ChainConfig `json:"config"`
Nonce uint64 `json:"nonce"` Nonce uint64 `json:"nonce"`
ShardID uint32 `json:"shardID"` ShardID uint32 `json:"shardID"`
Timestamp uint64 `json:"timestamp"` Timestamp uint64 `json:"timestamp"`
ExtraData []byte `json:"extraData"` ExtraData []byte `json:"extraData"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"` GasLimit uint64 `json:"gasLimit" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"` Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Mixhash common.Hash `json:"mixHash"` Mixhash common.Hash `json:"mixHash"`
Coinbase common.Address `json:"coinbase"` Coinbase common.Address `json:"coinbase"`
Alloc GenesisAlloc `json:"alloc" gencodec:"required"` Alloc GenesisAlloc `json:"alloc" gencodec:"required"`
ShardStateHash common.Hash `json:"shardStateHash"`
// These fields are used for consensus tests. Please don't use them // These fields are used for consensus tests. Please don't use them
// in actual genesis blocks. // in actual genesis blocks.
@ -237,18 +238,19 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
} }
root := statedb.IntermediateRoot(false) root := statedb.IntermediateRoot(false)
head := &types.Header{ head := &types.Header{
Number: new(big.Int).SetUint64(g.Number), Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce), Nonce: types.EncodeNonce(g.Nonce),
ShardID: types.EncodeShardID(g.ShardID), ShardID: types.EncodeShardID(g.ShardID),
Time: new(big.Int).SetUint64(g.Timestamp), Time: new(big.Int).SetUint64(g.Timestamp),
ParentHash: g.ParentHash, ParentHash: g.ParentHash,
Extra: g.ExtraData, Extra: g.ExtraData,
GasLimit: g.GasLimit, GasLimit: g.GasLimit,
GasUsed: g.GasUsed, GasUsed: g.GasUsed,
Difficulty: g.Difficulty, Difficulty: g.Difficulty,
MixDigest: g.Mixhash, MixDigest: g.Mixhash,
Coinbase: g.Coinbase, Coinbase: g.Coinbase,
Root: root, Root: root,
ShardStateHash: g.ShardStateHash,
} }
if g.GasLimit == 0 { if g.GasLimit == 0 {
head.GasLimit = 10000000000 // TODO(RJ): figure out better solution. // params.GenesisGasLimit head.GasLimit = 10000000000 // TODO(RJ): figure out better solution. // params.GenesisGasLimit

@ -19,9 +19,12 @@ import (
const ( const (
// InitialSeed is the initial random seed, a magic number to answer everything, remove later // InitialSeed is the initial random seed, a magic number to answer everything, remove later
InitialSeed uint32 = 42 InitialSeed uint32 = 42
// FirstEpoch is the number of the first epoch. // GenesisEpoch is the number of the first genesis epoch.
// TODO(minhdoan): we should design the first epoch as 0. Please figure out how to change other logic to make it 0 GenesisEpoch = 0
FirstEpoch = 1 // GenesisShardNum is the number of shard at genesis
GenesisShardNum = 3
// GenesisShardSize is the size of each shard at genesis
GenesisShardSize = 10
) )
// ShardingState is data structure hold the sharding state // ShardingState is data structure hold the sharding state
@ -83,8 +86,11 @@ func (ss *ShardingState) cuckooResharding(percent float64) {
// assignLeaders will first add new nodes into shards, then use cuckoo rule to reshard to get new shard state // assignLeaders will first add new nodes into shards, then use cuckoo rule to reshard to get new shard state
func (ss *ShardingState) assignLeaders() { func (ss *ShardingState) assignLeaders() {
for i := 0; i < ss.numShards; i++ { for i := 0; i < ss.numShards; i++ {
Shuffle(ss.shardState[i].NodeList) // At genesis epoch, the shards are empty.
ss.shardState[i].Leader = ss.shardState[i].NodeList[0] if len(ss.shardState[i].NodeList) > 0 {
Shuffle(ss.shardState[i].NodeList)
ss.shardState[i].Leader = ss.shardState[i].NodeList[0]
}
} }
} }
@ -134,12 +140,13 @@ func GetShardingStateFromBlockChain(bc *BlockChain, epoch uint64) *ShardingState
// CalculateNewShardState get sharding state from previous epoch and calculate sharding state for new epoch // CalculateNewShardState get sharding state from previous epoch and calculate sharding state for new epoch
// TODO: currently, we just mock everything // TODO: currently, we just mock everything
func CalculateNewShardState(bc *BlockChain, epoch uint64, stakeInfo *map[common.Address]*structs.StakeInfo) types.ShardState { func CalculateNewShardState(bc *BlockChain, epoch uint64, stakeInfo *map[common.Address]*structs.StakeInfo) types.ShardState {
if epoch == FirstEpoch { if epoch == GenesisEpoch {
return getInitShardState(3, 10) return GetInitShardState()
} }
ss := GetShardingStateFromBlockChain(bc, epoch-1) ss := GetShardingStateFromBlockChain(bc, epoch-1)
newNodeList := ss.UpdateShardingState(stakeInfo) newNodeList := ss.UpdateShardingState(stakeInfo)
percent := ss.calculateKickoutRate(newNodeList) percent := ss.calculateKickoutRate(newNodeList)
utils.GetLogInstance().Info("Kickout Percentage", "percentage", percent)
ss.Reshard(newNodeList, percent) ss.Reshard(newNodeList, percent)
return ss.shardState return ss.shardState
} }
@ -190,15 +197,16 @@ func (ss *ShardingState) calculateKickoutRate(newNodeList []types.NodeID) float6
return math.Max(0.1, math.Min(rate, 1.0)) return math.Max(0.1, math.Min(rate, 1.0))
} }
// getInitShardState returns the initial shard state at genesis. // GetInitShardState returns the initial shard state at genesis.
func getInitShardState(numberOfShards, numNodesPerShard int) types.ShardState { // TODO: make the deploy.sh config file in sync with genesis constants.
func GetInitShardState() types.ShardState {
shardState := types.ShardState{} shardState := types.ShardState{}
for i := 0; i < numberOfShards; i++ { for i := 0; i < GenesisShardNum; i++ {
com := types.Committee{ShardID: uint32(i)} com := types.Committee{ShardID: uint32(i)}
if i == 0 { if i == 0 {
for j := 0; j < numNodesPerShard; j++ { for j := 0; j < GenesisShardSize; j++ {
priKey := bls.SecretKey{} priKey := bls.SecretKey{}
priKey.SetHexString(contract.InitialBeaconChainAccounts[i].Private) priKey.SetHexString(contract.InitialBeaconChainAccounts[j].Private)
addrBytes := priKey.GetPublicKey().GetAddress() addrBytes := priKey.GetPublicKey().GetAddress()
address := hex.EncodeToString(addrBytes[:]) address := hex.EncodeToString(addrBytes[:])
com.NodeList = append(com.NodeList, types.NodeID(address)) com.NodeList = append(com.NodeList, types.NodeID(address))

@ -240,6 +240,9 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database) *N
os.Exit(1) os.Exit(1)
} }
node.blockchain = chain node.blockchain = chain
// Store the genesis shard state into db.
node.blockchain.StoreNewShardState(node.blockchain.CurrentBlock(), nil)
node.BlockChannel = make(chan *types.Block) node.BlockChannel = make(chan *types.Block)
node.ConfirmedBlockChannel = make(chan *types.Block) node.ConfirmedBlockChannel = make(chan *types.Block)
node.BeaconBlockChannel = make(chan *types.Block) node.BeaconBlockChannel = make(chan *types.Block)

@ -43,9 +43,10 @@ func (node *Node) GenesisBlockSetup(db ethdb.Database) (*core.BlockChain, error)
chainConfig := params.TestChainConfig chainConfig := params.TestChainConfig
chainConfig.ChainID = big.NewInt(int64(node.Consensus.ShardID)) // Use ChainID as piggybacked ShardID chainConfig.ChainID = big.NewInt(int64(node.Consensus.ShardID)) // Use ChainID as piggybacked ShardID
gspec := core.Genesis{ gspec := core.Genesis{
Config: chainConfig, Config: chainConfig,
Alloc: genesisAlloc, Alloc: genesisAlloc,
ShardID: uint32(node.Consensus.ShardID), ShardID: uint32(node.Consensus.ShardID),
ShardStateHash: core.GetInitShardState().Hash(),
} }
// Store genesis block into db. // Store genesis block into db.

@ -153,7 +153,7 @@ func (node *Node) messageHandler(content []byte, sender string) {
utils.GetLogInstance().Info("NET: received message: Node/Control") utils.GetLogInstance().Info("NET: received message: Node/Control")
controlType := msgPayload[0] controlType := msgPayload[0]
if proto_node.ControlMessageType(controlType) == proto_node.STOP { if proto_node.ControlMessageType(controlType) == proto_node.STOP {
utils.GetLogInstance().Debug("Stopping Node", "node", node, "numBlocks", node.blockchain.CurrentBlock().NumberU64(), "numTxsProcessed", node.countNumTransactionsInBlockchain()) utils.GetLogInstance().Debug("Stopping Node", "numBlocks", node.blockchain.CurrentBlock().NumberU64(), "numTxsProcessed", node.countNumTransactionsInBlockchain())
var avgBlockSizeInBytes common.StorageSize var avgBlockSizeInBytes common.StorageSize
txCount := 0 txCount := 0
@ -297,7 +297,7 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
func (node *Node) AddNewBlock(newBlock *types.Block) { func (node *Node) AddNewBlock(newBlock *types.Block) {
blockNum, err := node.blockchain.InsertChain([]*types.Block{newBlock}) blockNum, err := node.blockchain.InsertChain([]*types.Block{newBlock})
node.blockchain.InsertNewShardState(newBlock, &node.CurrentStakes) node.blockchain.StoreNewShardState(newBlock, &node.CurrentStakes)
if err != nil { if err != nil {
utils.GetLogInstance().Debug("Error adding new block to blockchain", "blockNum", blockNum, "Error", err) utils.GetLogInstance().Debug("Error adding new block to blockchain", "blockNum", blockNum, "Error", err)
} else { } else {

@ -60,7 +60,7 @@ func (node *Node) WaitForConsensusReady(readySignal chan struct{}, stopChan chan
} else { } else {
// add new shard state if it's epoch block // add new shard state if it's epoch block
// TODO(minhdoan): only happens for beaconchain // TODO(minhdoan): only happens for beaconchain
node.addNewShardState(block) node.addNewShardStateHash(block)
newBlock = block newBlock = block
break break
} }
@ -78,7 +78,7 @@ func (node *Node) WaitForConsensusReady(readySignal chan struct{}, stopChan chan
}() }()
} }
func (node *Node) addNewShardState(block *types.Block) { func (node *Node) addNewShardStateHash(block *types.Block) {
shardState := node.blockchain.GetNewShardState(block, &node.CurrentStakes) shardState := node.blockchain.GetNewShardState(block, &node.CurrentStakes)
if shardState != nil { if shardState != nil {
shardHash := shardState.Hash() shardHash := shardState.Hash()

@ -8,3 +8,4 @@
127.0.0.1 9007 validator 0 127.0.0.1 9007 validator 0
127.0.0.1 9008 validator 0 127.0.0.1 9008 validator 0
127.0.0.1 9009 validator 0 127.0.0.1 9009 validator 0
127.0.0.1 19999 client 0

Loading…
Cancel
Save