From 288eb52e9f31cbbe7d08c7c15d7b17cd8aedaed2 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Tue, 16 Nov 2021 11:39:50 +0800 Subject: [PATCH 1/2] get diff accounts by replaying block when diff layer not found (#536) Signed-off-by: Keefe-Liu --- core/blockchain.go | 2 +- core/error.go | 3 ++ core/state/statedb.go | 8 +++++ internal/ethapi/api.go | 71 ++++++++++++++++++++++++++++-------------- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 4562061337..4a7cdf9a54 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1011,7 +1011,7 @@ func (bc *BlockChain) GetDiffAccounts(blockHash common.Hash) ([]common.Address, if diffLayer == nil { if header.TxHash != types.EmptyRootHash { - return nil, fmt.Errorf("no diff layer found") + return nil, ErrDiffLayerNotFound } return nil, nil diff --git a/core/error.go b/core/error.go index 197dd81567..1fbd0d599b 100644 --- a/core/error.go +++ b/core/error.go @@ -31,6 +31,9 @@ var ( // ErrNoGenesis is returned when there is no Genesis Block. ErrNoGenesis = errors.New("genesis not found in chain") + + // ErrDiffLayerNotFound is returned when diff layer not found. + ErrDiffLayerNotFound = errors.New("diff layer not found") ) // List of evm-call-message pre-checking errors. All state transition messages will diff --git a/core/state/statedb.go b/core/state/statedb.go index c7a9d92ef7..6f150915ca 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1493,3 +1493,11 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre } return s.accessList.Contains(addr, slot) } + +func (s *StateDB) GetDirtyAccounts() []common.Address { + accounts := make([]common.Address, 0, len(s.stateObjectsDirty)) + for account := range s.stateObjectsDirty { + accounts = append(accounts, account) + } + return accounts +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 53e94d9af6..091e9e7e82 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1098,7 +1098,21 @@ func (s *PublicBlockChainAPI) GetDiffAccounts(ctx context.Context, blockNr rpc.B return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) } - return s.b.Chain().GetDiffAccounts(header.Hash()) + accounts, err := s.b.Chain().GetDiffAccounts(header.Hash()) + if err == nil || !errors.Is(err, core.ErrDiffLayerNotFound) { + return accounts, err + } + + // Replay the block when diff layer not found, it is very slow. + block, err := s.b.BlockByNumber(ctx, blockNr) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) + } + _, statedb, err := s.replay(ctx, block, nil) + if err != nil { + return nil, err + } + return statedb.GetDirtyAccounts(), nil } func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Block, accounts []common.Address) (bool, error) { @@ -1161,36 +1175,20 @@ func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Blo return false, nil } -// GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. -func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) { - if s.b.Chain() == nil { - return nil, fmt.Errorf("blockchain not support get diff accounts") - } - - block, err := s.b.BlockByNumber(ctx, blockNr) - if err != nil { - return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) - } - +func (s *PublicBlockChainAPI) replay(ctx context.Context, block *types.Block, accounts []common.Address) (*types.DiffAccountsInBlock, *state.StateDB, error) { result := &types.DiffAccountsInBlock{ - Number: uint64(blockNr), + Number: block.NumberU64(), BlockHash: block.Hash(), Transactions: make([]types.DiffAccountsInTx, 0), } - if needReplay, err := s.needToReplay(ctx, block, accounts); err != nil { - return nil, err - } else if !needReplay { - return result, nil - } - parent, err := s.b.BlockByHash(ctx, block.ParentHash()) if err != nil { - return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr-1, err) + return nil, nil, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err) } statedb, err := s.b.Chain().StateAt(parent.Root()) if err != nil { - return nil, fmt.Errorf("state not found for block number (%d): %v", blockNr-1, err) + return nil, nil, fmt.Errorf("state not found for block number (%d): %v", block.NumberU64()-1, err) } accountSet := make(map[common.Address]struct{}, len(accounts)) @@ -1240,7 +1238,7 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { - return nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + return nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) @@ -1259,7 +1257,34 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc } } - return result, nil + return result, statedb, nil +} + +// GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. +func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) { + if s.b.Chain() == nil { + return nil, fmt.Errorf("blockchain not support get diff accounts") + } + + block, err := s.b.BlockByNumber(ctx, blockNr) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) + } + + needReplay, err := s.needToReplay(ctx, block, accounts) + if err != nil { + return nil, err + } + if !needReplay { + return &types.DiffAccountsInBlock{ + Number: uint64(blockNr), + BlockHash: block.Hash(), + Transactions: make([]types.DiffAccountsInTx, 0), + }, nil + } + + result, _, err := s.replay(ctx, block, accounts) + return result, err } // ExecutionResult groups all structured logs emitted by the EVM From 6fb789de676173b70ad34bb3efeebc50682f74e0 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Tue, 16 Nov 2021 13:51:44 +0800 Subject: [PATCH 2/2] prepare for release v.1.1.5 (#549) --- CHANGELOG.md | 9 +++++++++ params/config.go | 2 +- params/version.go | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78bb469607..5b0b345db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ # Changelog +## v1.1.5 +BUGFIX +* [\#509](https://github.com/binance-chain/bsc/pull/509) fix graceful shutdown bug + +IMPROVEMENT +* [\#536](https://github.com/binance-chain/bsc/pull/536) get diff accounts by replaying block when diff layer not found +* [\#527](https://github.com/binance-chain/bsc/pull/527) improve diffsync protocol in many aspects +* [\#493](https://github.com/binance-chain/bsc/pull/493) implement fast getDiffAccountsWithScope API + ## v1.1.4 Improvement * [\#472](https://github.com/binance-chain/bsc/pull/472) add metrics for contract code bitmap cache diff --git a/params/config.go b/params/config.go index 8afc20f882..c09a576495 100644 --- a/params/config.go +++ b/params/config.go @@ -250,7 +250,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(5184000), - BrunoBlock: nil, + BrunoBlock: big.NewInt(13082000), Parlia: &ParliaConfig{ Period: 3, Epoch: 200, diff --git a/params/version.go b/params/version.go index 0786d099b5..d15c2d94c5 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release + VersionPatch = 5 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string )