diff --git a/core/blockchain.go b/core/blockchain.go index 9f7ecf739..a8811fe2f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1719,27 +1719,6 @@ func (bc *BlockChain) GetNewShardState(block *types.Block, stakeInfo *map[common return shardState } -// ValidateNewShardState validate whether the new shard state root matches -func (bc *BlockChain) ValidateNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) error { - proposed := block.Header().ShardState - if proposed == nil { - // For now, beacon validators simply wait until the beacon leader - // proposes a new sharding state. - // TODO ek – invoke view change if leader continues epoch for too long - return nil - } - if block.ShardID() == 0 { // Beacon chain - nextEpoch := GetEpochFromBlockNumber(block.NumberU64()) + 1 - expected := CalculateNewShardState(bc, nextEpoch, stakeInfo) - if types.CompareShardState(expected, proposed) != 0 { - // TODO ek – log state proposal differences - return errors.New("shard state proposal is different from expected") - } - } else { // regular chain - } - return nil -} - // StoreNewShardState insert new shard state into epoch block func (bc *BlockChain) StoreNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) types.ShardState { // write state into db. diff --git a/node/node_handler.go b/node/node_handler.go index 62f9b0df4..664e75bbe 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -5,6 +5,7 @@ import ( "context" "encoding/gob" "encoding/hex" + "errors" "fmt" "io/ioutil" "math" @@ -25,6 +26,7 @@ import ( "github.com/harmony-one/harmony/api/proto/message" proto_node "github.com/harmony-one/harmony/api/proto/node" "github.com/harmony-one/harmony/api/service" + "github.com/harmony-one/harmony/contracts/structs" "github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/crypto/pki" @@ -259,13 +261,40 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) error { // TODO: verify the vrf randomness _ = newBlock.Header().RandPreimage - err = node.blockchain.ValidateNewShardState(newBlock, &node.CurrentStakes) + err = node.ValidateNewShardState(newBlock, &node.CurrentStakes) if err != nil { return ctxerror.New("failed to verify sharding state").WithCause(err) } return nil } +// ValidateNewShardState validate whether the new shard state root matches +func (node *Node) ValidateNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) error { + proposed := block.Header().ShardState + if proposed == nil { + // For now, beacon validators simply wait until the beacon leader + // proposes a new sharding state. + // TODO ek – invoke view change if leader continues epoch for too long + return nil + } + if block.ShardID() == 0 { + // Beacon validators independently recalculate the master state and + // compare it against the proposed copy. + nextEpoch := core.GetEpochFromBlockNumber(block.NumberU64()) + 1 + expected := core.CalculateNewShardState(node.blockchain, nextEpoch, stakeInfo) + if types.CompareShardState(expected, proposed) != 0 { + // TODO ek – log state proposal differences + return errors.New("shard state proposal is different from expected") + } + } else { + // Regular validators fetch the local-shard copy on the beacon chain + // and compare it against the proposed copy. + // TODO ek – we aren't in the right place to have access to beacon + // chain. Move this method one level up. + } + return nil +} + // PostConsensusProcessing is called by consensus participants, after consensus is done, to: // 1. add the new block to blockchain // 2. [leader] send new block to the client