mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
* added support for dependencies (executor_tests) * added a function to get dependency map * getting all dependencies in the GetDep function * updated GetDep function * changed the type of AllDeps * added a function to get dependency map * updated GetDep function * generate and get dependencies from block producer * optimized getDep function * bug fix regarding txn index and dep structure * fixed gas bug * optimized getDep function * tests updated/added * few updates regarding dependencies * added channel to calculate the dependencies in a separate go routine * minor changes in the executor which uses latest changes of dependecies + removed metadata flag/argument * Use channel when metadata is available * small bug fix * getting reads and writes only when the transaction succeeds * fixed bug in adding dependencies * updated logic for delay/not delay * bug fix (shouldDelayFeeCal) in parallel state processor * lint fix * using EnableMVHashMap flag * fixed worker and stateProcessor and removed SetMVHashMapNil fumction from stateDB * addredded few comments and fixed bug in executor tests * commented executor tests with metadata (panic: test timed out after 5m0s) * added a check to check len(mvReadMapList) > 0 in miner * addressed comments, minor refactoring in dag.go * moved blockContext out of Execute and adding it in execution task * removed Author() from Settle() and added in execution task * not calling block.Header() again and again, using instead * removed EnableMVHashMap flag, and updated applyTransaction function * addressed comments * added unit test to check dependencies in the block header Co-authored-by: Jerry <jerrycgh@gmail.com>
201 lines
4 KiB
Go
201 lines
4 KiB
Go
package blockstm
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/heimdalr/dag"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
)
|
|
|
|
type DAG struct {
|
|
*dag.DAG
|
|
}
|
|
|
|
type TxDep struct {
|
|
Index int
|
|
ReadList []ReadDescriptor
|
|
FullWriteList [][]WriteDescriptor
|
|
}
|
|
|
|
func HasReadDep(txFrom TxnOutput, txTo TxnInput) bool {
|
|
reads := make(map[Key]bool)
|
|
|
|
for _, v := range txTo {
|
|
reads[v.Path] = true
|
|
}
|
|
|
|
for _, rd := range txFrom {
|
|
if _, ok := reads[rd.Path]; ok {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func BuildDAG(deps TxnInputOutput) (d DAG) {
|
|
d = DAG{dag.NewDAG()}
|
|
ids := make(map[int]string)
|
|
|
|
for i := len(deps.inputs) - 1; i > 0; i-- {
|
|
txTo := deps.inputs[i]
|
|
|
|
var txToId string
|
|
|
|
if _, ok := ids[i]; ok {
|
|
txToId = ids[i]
|
|
} else {
|
|
txToId, _ = d.AddVertex(i)
|
|
ids[i] = txToId
|
|
}
|
|
|
|
for j := i - 1; j >= 0; j-- {
|
|
txFrom := deps.allOutputs[j]
|
|
|
|
if HasReadDep(txFrom, txTo) {
|
|
var txFromId string
|
|
if _, ok := ids[j]; ok {
|
|
txFromId = ids[j]
|
|
} else {
|
|
txFromId, _ = d.AddVertex(j)
|
|
ids[j] = txFromId
|
|
}
|
|
|
|
err := d.AddEdge(txFromId, txToId)
|
|
if err != nil {
|
|
log.Warn("Failed to add edge", "from", txFromId, "to", txToId, "err", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func depsHelper(dependencies map[int]map[int]bool, txFrom TxnOutput, txTo TxnInput, i int, j int) map[int]map[int]bool {
|
|
if HasReadDep(txFrom, txTo) {
|
|
dependencies[i][j] = true
|
|
|
|
for k := range dependencies[i] {
|
|
_, foundDep := dependencies[j][k]
|
|
|
|
if foundDep {
|
|
delete(dependencies[i], k)
|
|
}
|
|
}
|
|
}
|
|
|
|
return dependencies
|
|
}
|
|
|
|
func UpdateDeps(deps map[int]map[int]bool, t TxDep) map[int]map[int]bool {
|
|
txTo := t.ReadList
|
|
|
|
deps[t.Index] = map[int]bool{}
|
|
|
|
for j := 0; j <= t.Index-1; j++ {
|
|
txFrom := t.FullWriteList[j]
|
|
|
|
deps = depsHelper(deps, txFrom, txTo, t.Index, j)
|
|
}
|
|
|
|
return deps
|
|
}
|
|
|
|
func GetDep(deps TxnInputOutput) map[int]map[int]bool {
|
|
newDependencies := map[int]map[int]bool{}
|
|
|
|
for i := 1; i < len(deps.inputs); i++ {
|
|
txTo := deps.inputs[i]
|
|
|
|
newDependencies[i] = map[int]bool{}
|
|
|
|
for j := 0; j <= i-1; j++ {
|
|
txFrom := deps.allOutputs[j]
|
|
|
|
newDependencies = depsHelper(newDependencies, txFrom, txTo, i, j)
|
|
}
|
|
}
|
|
|
|
return newDependencies
|
|
}
|
|
|
|
// Find the longest execution path in the DAG
|
|
func (d DAG) LongestPath(stats map[int]ExecutionStat) ([]int, uint64) {
|
|
prev := make(map[int]int, len(d.GetVertices()))
|
|
|
|
for i := 0; i < len(d.GetVertices()); i++ {
|
|
prev[i] = -1
|
|
}
|
|
|
|
pathWeights := make(map[int]uint64, len(d.GetVertices()))
|
|
|
|
maxPath := 0
|
|
maxPathWeight := uint64(0)
|
|
|
|
idxToId := make(map[int]string, len(d.GetVertices()))
|
|
|
|
for k, i := range d.GetVertices() {
|
|
idxToId[i.(int)] = k
|
|
}
|
|
|
|
for i := 0; i < len(idxToId); i++ {
|
|
parents, _ := d.GetParents(idxToId[i])
|
|
|
|
if len(parents) > 0 {
|
|
for _, p := range parents {
|
|
weight := pathWeights[p.(int)] + stats[i].End - stats[i].Start
|
|
if weight > pathWeights[i] {
|
|
pathWeights[i] = weight
|
|
prev[i] = p.(int)
|
|
}
|
|
}
|
|
} else {
|
|
pathWeights[i] = stats[i].End - stats[i].Start
|
|
}
|
|
|
|
if pathWeights[i] > maxPathWeight {
|
|
maxPath = i
|
|
maxPathWeight = pathWeights[i]
|
|
}
|
|
}
|
|
|
|
path := make([]int, 0)
|
|
for i := maxPath; i != -1; i = prev[i] {
|
|
path = append(path, i)
|
|
}
|
|
|
|
// Reverse the path so the transactions are in the ascending order
|
|
for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
|
|
path[i], path[j] = path[j], path[i]
|
|
}
|
|
|
|
return path, maxPathWeight
|
|
}
|
|
|
|
func (d DAG) Report(stats map[int]ExecutionStat, out func(string)) {
|
|
longestPath, weight := d.LongestPath(stats)
|
|
|
|
serialWeight := uint64(0)
|
|
|
|
for i := 0; i < len(d.GetVertices()); i++ {
|
|
serialWeight += stats[i].End - stats[i].Start
|
|
}
|
|
|
|
makeStrs := func(ints []int) (ret []string) {
|
|
for _, v := range ints {
|
|
ret = append(ret, fmt.Sprint(v))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
out("Longest execution path:")
|
|
out(fmt.Sprintf("(%v) %v", len(longestPath), strings.Join(makeStrs(longestPath), "->")))
|
|
|
|
out(fmt.Sprintf("Longest path ideal execution time: %v of %v (serial total), %v%%", time.Duration(weight),
|
|
time.Duration(serialWeight), fmt.Sprintf("%.1f", float64(weight)*100.0/float64(serialWeight))))
|
|
}
|