eth-statediff-compliance/pkg/diff_dump.go

107 lines
2.4 KiB
Go

package compliance
import (
"bytes"
"fmt"
"os"
"path/filepath"
"sort"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/cerc-io/eth-statediff-compliance/internal/statediff"
)
// arg 0 is filename
func WriteDiffs(outputDir string,
chain *core.BlockChain,
blocks []*types.Block,
) {
sdb := chain.StateCache()
builder := statediff.MakeBuilder(sdb)
// For each block, run the builder and output to a file
for i, block := range blocks {
args := statediff.Args{
NewStateRoot: block.Root(),
BlockNumber: block.Number(),
BlockHash: block.Hash(),
}
if i != 0 {
args.OldStateRoot = blocks[i-1].Root()
}
diff, err := builder.BuildStateDiffObject(args, statediff.Params{})
if err != nil {
panic(err)
}
writeDiff(outputDir, i, &diff)
}
}
// Sorts contained state nodes, storage nodes, and IPLDs
// Outputs them to respective files in given dir
func writeDiff(outputDir string, number int, diff *statediff.StateObject) {
sort.Slice(diff.IPLDs, func(i, j int) bool {
return diff.IPLDs[i].CID < diff.IPLDs[j].CID
})
sort.Slice(diff.Nodes, func(i, j int) bool {
return bytes.Compare(
diff.Nodes[i].AccountWrapper.LeafKey,
diff.Nodes[j].AccountWrapper.LeafKey,
) < 0
})
for _, node := range diff.Nodes {
sort.Slice(node.StorageDiff, func(i, j int) bool {
return bytes.Compare(
node.StorageDiff[i].LeafKey,
node.StorageDiff[j].LeafKey,
) < 0
})
}
// open file and dump sorted node CIDs
ipldsPath := filepath.Join(outputDir, fmt.Sprintf("%d_diff.txt", number))
f, err := os.Create(ipldsPath)
if err != nil {
panic(err)
}
defer f.Close()
for _, item := range diff.IPLDs {
s := fmt.Sprintf("ipld,%s,%x\n",
item.CID,
item.Content,
)
if _, err = f.WriteString(s); err != nil {
panic(err)
}
}
for _, item := range diff.Nodes {
s := fmt.Sprintf("state,%s,%x,%t,%v,%v,%s,%x\n",
item.AccountWrapper.CID,
item.AccountWrapper.LeafKey,
item.Removed,
item.AccountWrapper.Account.Nonce,
item.AccountWrapper.Account.Balance,
item.AccountWrapper.Account.Root,
item.AccountWrapper.Account.CodeHash,
)
if _, err = f.WriteString(s); err != nil {
panic(err)
}
for _, storage := range item.StorageDiff {
s := fmt.Sprintf("storage,%s,%x,%t,%x\n",
storage.CID,
storage.LeafKey,
storage.Removed,
storage.Value,
)
if _, err = f.WriteString(s); err != nil {
panic(err)
}
}
}
}