traceChain configures a new tracer according to the provided configuration, and executes all the transactions contained within. The return value will be one item per transaction, dependent on the requestd tracer.
(ctx context.Context, start, end *types.Block, config *TraceConfig)
| 132 | // executes all the transactions contained within. The return value will be one item |
| 133 | // per transaction, dependent on the requestd tracer. |
| 134 | func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) { |
| 135 | // Tracing a chain is a **long** operation, only do with subscriptions |
| 136 | notifier, supported := rpc.NotifierFromContext(ctx) |
| 137 | if !supported { |
| 138 | return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported |
| 139 | } |
| 140 | sub := notifier.CreateSubscription() |
| 141 | |
| 142 | // Ensure we have a valid starting state before doing any work |
| 143 | origin := start.NumberU64() |
| 144 | database := state.NewDatabase(api.cpc.ChainDb()) |
| 145 | |
| 146 | if number := start.NumberU64(); number > 0 { |
| 147 | start = api.cpc.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1) |
| 148 | if start == nil { |
| 149 | return nil, fmt.Errorf("parent block #%d not found", number-1) |
| 150 | } |
| 151 | } |
| 152 | pubStateDB, err := state.New(start.StateRoot(), database) |
| 153 | if err != nil { |
| 154 | // If the starting state is missing, allow some number of blocks to be reexecuted |
| 155 | reexec := defaultTraceReexec |
| 156 | if config != nil && config.Reexec != nil { |
| 157 | reexec = *config.Reexec |
| 158 | } |
| 159 | // Find the most recent block that has the state available |
| 160 | for i := uint64(0); i < reexec; i++ { |
| 161 | start = api.cpc.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1) |
| 162 | if start == nil { |
| 163 | break |
| 164 | } |
| 165 | if pubStateDB, err = state.New(start.StateRoot(), database); err == nil { |
| 166 | break |
| 167 | } |
| 168 | } |
| 169 | // If we still don't have the state available, bail out |
| 170 | if err != nil { |
| 171 | switch err.(type) { |
| 172 | case *trie.MissingNodeError: |
| 173 | return nil, errors.New("required historical state unavailable") |
| 174 | default: |
| 175 | return nil, err |
| 176 | } |
| 177 | } |
| 178 | } |
| 179 | // Execute all the transaction contained within the chain concurrently for each block |
| 180 | blocks := int(end.NumberU64() - origin) |
| 181 | |
| 182 | threads := runtime.NumCPU() |
| 183 | if threads > blocks { |
| 184 | threads = blocks |
| 185 | } |
| 186 | var ( |
| 187 | pend = new(sync.WaitGroup) |
| 188 | tasks = make(chan *blockTraceTask, threads) |
| 189 | results = make(chan *blockTraceTask, threads) |
| 190 | ) |
| 191 | for th := 0; th < threads; th++ { |
no test coverage detected