Skip to content

Commit

Permalink
EVM-843 Fix block post processing (#1928)
Browse files Browse the repository at this point in the history
  • Loading branch information
igorcrevar authored Sep 25, 2023
1 parent f30facf commit 9c9af49
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 42 deletions.
4 changes: 2 additions & 2 deletions consensus/polybft/consensus_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (c *consensusRuntime) initStakeManager(logger hcf.Logger) error {
return err
}

c.stakeManager = newStakeManager(
c.stakeManager, err = newStakeManager(
logger.Named("stake-manager"),
c.state,
rootRelayer,
Expand All @@ -238,7 +238,7 @@ func (c *consensusRuntime) initStakeManager(logger hcf.Logger) error {
int(c.config.PolyBFTConfig.MaxValidatorSetSize),
)

return nil
return err
}

// getGuardedData returns last build block, proposer snapshot and current epochMetadata in a thread-safe manner.
Expand Down
5 changes: 5 additions & 0 deletions consensus/polybft/consensus_runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,11 @@ func Test_NewConsensusRuntime(t *testing.T) {
blockchain: blockchainMock,
bridgeTopic: &mockTopic{},
}

require.NoError(t, config.State.StakeStore.insertFullValidatorSet(validatorSetState{
BlockNumber: 1,
}))

runtime, err := newConsensusRuntime(hclog.NewNullLogger(), config)
require.NoError(t, err)

Expand Down
97 changes: 82 additions & 15 deletions consensus/polybft/stake_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func newStakeManager(
validatorSetAddr, supernetManagerAddr types.Address,
blockchain blockchainBackend,
maxValidatorSetSize int,
) *stakeManager {
) (*stakeManager, error) {
eventsGetter := &eventsGetter[*contractsapi.TransferEvent]{
blockchain: blockchain,
isValidLogFn: func(l *types.Log) bool {
Expand All @@ -81,7 +81,7 @@ func newStakeManager(
},
}

return &stakeManager{
sm := &stakeManager{
logger: logger,
state: state,
rootChainRelayer: rootchainRelayer,
Expand All @@ -90,6 +90,12 @@ func newStakeManager(
maxValidatorSetSize: maxValidatorSetSize,
eventsGetter: eventsGetter,
}

if err := sm.init(blockchain); err != nil {
return nil, err
}

return sm, nil
}

// PostEpoch saves the initial validator set to db
Expand All @@ -115,30 +121,82 @@ func (s *stakeManager) PostBlock(req *PostBlockRequest) error {
return err
}

s.logger.Debug("Stake manager on post block", "block", req.FullBlock.Block.Number(),
"last saved", fullValidatorSet.BlockNumber, "last updated", fullValidatorSet.UpdatedAtBlockNumber)
blockNumber := req.FullBlock.Block.Number()

s.logger.Debug("Stake manager on post block",
"block", blockNumber,
"last saved", fullValidatorSet.BlockNumber,
"last updated", fullValidatorSet.UpdatedAtBlockNumber)

err = s.updateWithReceipts(&fullValidatorSet, req.FullBlock)
// get transfer currentBlockEvents from current block
transferEvents, err := s.eventsGetter.getFromBlocks(fullValidatorSet.BlockNumber, req.FullBlock)
if err != nil {
return fmt.Errorf("could not get transfer events from current block. Error: %w", err)
}

if err = s.updateWithReceipts(&fullValidatorSet, transferEvents, blockNumber); err != nil {
return err
}

// we should save new state even if number of events is zero
// because otherwise next time we will process more blocks
fullValidatorSet.EpochID = req.Epoch
fullValidatorSet.BlockNumber = req.FullBlock.Block.Number()
fullValidatorSet.BlockNumber = blockNumber

return s.state.StakeStore.insertFullValidatorSet(fullValidatorSet)
}

func (s *stakeManager) updateWithReceipts(
fullValidatorSet *validatorSetState, fullBlock *types.FullBlock) error {
var transferEvents []*contractsapi.TransferEvent
func (s *stakeManager) init(blockchain blockchainBackend) error {
currentHeader := blockchain.CurrentHeader()
currentBlockNumber := currentHeader.Number

// get transfer currentBlockEvents from current block
transferEvents, err := s.eventsGetter.getFromBlocks(fullValidatorSet.BlockNumber, fullBlock)
// early exit if this is genesis block
if currentBlockNumber == 0 {
return nil
}

validatorSet, err := s.state.StakeStore.getFullValidatorSet()
if err != nil {
return fmt.Errorf("could not get transfer events from current block. Error: %w", err)
return err
}

// early return if current block is already processed
if validatorSet.BlockNumber == currentBlockNumber {
return nil
}

// retrieve epoch needed for state
epochID, err := getEpochID(blockchain, currentHeader)
if err != nil {
return err
}

s.logger.Debug("Stake manager on post block",
"block", currentBlockNumber,
"last saved", validatorSet.BlockNumber,
"last updated", validatorSet.UpdatedAtBlockNumber)

transferEvents, err := s.eventsGetter.getEventsFromAllBlocks(validatorSet.BlockNumber+1, currentBlockNumber)
if err != nil {
return err
}

if err := s.updateWithReceipts(&validatorSet, transferEvents, currentBlockNumber); err != nil {
return err
}

// we should save new state even if number of events is zero
// because otherwise next time we will process more blocks
validatorSet.EpochID = epochID
validatorSet.BlockNumber = currentBlockNumber

return s.state.StakeStore.insertFullValidatorSet(validatorSet)
}

func (s *stakeManager) updateWithReceipts(
fullValidatorSet *validatorSetState,
transferEvents []*contractsapi.TransferEvent,
blockNumber uint64) error {
if len(transferEvents) == 0 {
return nil
}
Expand All @@ -165,7 +223,7 @@ func (s *stakeManager) updateWithReceipts(
blsKey, err := s.getBlsKey(data.Address)
if err != nil {
s.logger.Warn("Could not get info for new validator",
"block", fullBlock.Block.Number(), "address", addr)
"block", blockNumber, "address", addr)
}

data.BlsKey = blsKey
Expand All @@ -175,9 +233,9 @@ func (s *stakeManager) updateWithReceipts(
}

// mark on which block validator set has been updated
fullValidatorSet.UpdatedAtBlockNumber = fullValidatorSet.BlockNumber
fullValidatorSet.UpdatedAtBlockNumber = blockNumber

s.logger.Debug("Full validator set after", "block", fullBlock.Block, "data", fullValidatorSet.Validators)
s.logger.Debug("Full validator set after", "block", blockNumber, "data", fullValidatorSet.Validators)

return nil
}
Expand Down Expand Up @@ -399,3 +457,12 @@ func (sc validatorStakeMap) String() string {

return sb.String()
}

func getEpochID(blockchain blockchainBackend, header *types.Header) (uint64, error) {
provider, err := blockchain.GetStateProviderForBlock(header)
if err != nil {
return 0, err
}

return blockchain.GetSystemState(provider).GetEpoch()
}
18 changes: 11 additions & 7 deletions consensus/polybft/stake_manager_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,12 @@ func FuzzTestStakeManagerPostBlock(f *testing.F) {

bcMock := new(blockchainMock)
for i := 0; i < int(data.BlockID); i++ {
bcMock.On("CurrentHeader").Return(&types.Header{Number: 0})
bcMock.On("GetHeaderByNumber", mock.Anything).Return(&types.Header{Hash: types.Hash{6, 4}}, true).Once()
bcMock.On("GetReceiptsByHash", mock.Anything).Return([]*types.Receipt{{}}, error(nil)).Once()
}

stakeManager := newStakeManager(
stakeManager, err := newStakeManager(
hclog.NewNullLogger(),
state,
nil,
Expand All @@ -172,6 +173,7 @@ func FuzzTestStakeManagerPostBlock(f *testing.F) {
bcMock,
5,
)
require.NoError(t, err)

// insert initial full validator set
require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{
Expand All @@ -190,14 +192,12 @@ func FuzzTestStakeManagerPostBlock(f *testing.F) {
},
}

req := &PostBlockRequest{
require.NoError(t, stakeManager.PostBlock(&PostBlockRequest{
FullBlock: &types.FullBlock{Block: &types.Block{Header: &types.Header{Number: data.BlockID}},
Receipts: []*types.Receipt{receipt},
},
Epoch: data.EpochID,
}
err := stakeManager.PostBlock(req)
require.NoError(t, err)
}))
})
}

Expand All @@ -210,15 +210,19 @@ func FuzzTestStakeManagerUpdateValidatorSet(f *testing.F) {
validators := validator.NewTestValidatorsWithAliases(f, aliases, stakes)
state := newTestState(f)

stakeManager := newStakeManager(
bcMock := new(blockchainMock)
bcMock.On("CurrentHeader").Return(&types.Header{Number: 0})

stakeManager, err := newStakeManager(
hclog.NewNullLogger(),
state,
nil,
wallet.NewEcdsaSigner(validators.GetValidator("A").Key()),
types.StringToAddress("0x0001"), types.StringToAddress("0x0002"),
nil,
bcMock,
10,
)
require.NoError(f, err)

seeds := []updateValidatorSetF{
{
Expand Down
Loading

0 comments on commit 9c9af49

Please sign in to comment.