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) } } } }