From 1fb82b20e4722121cf2fdab991fc6da46f98ff66 Mon Sep 17 00:00:00 2001 From: Keefe-Liu Date: Fri, 29 Oct 2021 19:06:45 +0800 Subject: [PATCH] accelarate get diff accounts with scope Signed-off-by: Keefe-Liu --- internal/ethapi/api.go | 79 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index da4cf8cad1..53e94d9af6 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1101,6 +1101,66 @@ func (s *PublicBlockChainAPI) GetDiffAccounts(ctx context.Context, blockNr rpc.B return s.b.Chain().GetDiffAccounts(header.Hash()) } +func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Block, accounts []common.Address) (bool, error) { + receipts, err := s.b.GetReceipts(ctx, block.Hash()) + if err != nil || len(receipts) != len(block.Transactions()) { + return false, fmt.Errorf("receipt incorrect for block number (%d): %v", block.NumberU64(), err) + } + + accountSet := make(map[common.Address]struct{}, len(accounts)) + for _, account := range accounts { + accountSet[account] = struct{}{} + } + spendValueMap := make(map[common.Address]int64, len(accounts)) + receiveValueMap := make(map[common.Address]int64, len(accounts)) + + signer := types.MakeSigner(s.b.ChainConfig(), block.Number()) + for index, tx := range block.Transactions() { + receipt := receipts[index] + from, err := types.Sender(signer, tx) + if err != nil { + return false, fmt.Errorf("get sender for tx failed: %v", err) + } + + if _, exists := accountSet[from]; exists { + spendValueMap[from] += int64(receipt.GasUsed) * tx.GasPrice().Int64() + if receipt.Status == types.ReceiptStatusSuccessful { + spendValueMap[from] += tx.Value().Int64() + } + } + + if tx.To() == nil { + continue + } + + if _, exists := accountSet[*tx.To()]; exists && receipt.Status == types.ReceiptStatusSuccessful { + receiveValueMap[*tx.To()] += tx.Value().Int64() + } + } + + parent, err := s.b.BlockByHash(ctx, block.ParentHash()) + if err != nil { + return false, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err) + } + parentState, err := s.b.Chain().StateAt(parent.Root()) + if err != nil { + return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64()-1, err) + } + currentState, err := s.b.Chain().StateAt(block.Root()) + if err != nil { + return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64(), err) + } + for _, account := range accounts { + parentBalance := parentState.GetBalance(account).Int64() + currentBalance := currentState.GetBalance(account).Int64() + if receiveValueMap[account]-spendValueMap[account] != currentBalance-parentBalance { + return true, nil + } + } + + 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 { @@ -1111,6 +1171,19 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc if err != nil { return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) } + + result := &types.DiffAccountsInBlock{ + Number: uint64(blockNr), + 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) @@ -1120,12 +1193,6 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc return nil, fmt.Errorf("state not found for block number (%d): %v", blockNr-1, err) } - result := &types.DiffAccountsInBlock{ - Number: uint64(blockNr), - BlockHash: block.Hash(), - Transactions: make([]types.DiffAccountsInTx, 0), - } - accountSet := make(map[common.Address]struct{}, len(accounts)) for _, account := range accounts { accountSet[account] = struct{}{}