Commit bf6a9ceb authored by clabby's avatar clabby

`srcmap` patch

parent 063e52ac
...@@ -12,13 +12,14 @@ version: ...@@ -12,13 +12,14 @@ version:
compile: compile:
cd $(contracts-dir) && \ cd $(contracts-dir) && \
pnpm build pnpm build --build-info
bindings: compile bindings-build bindings: compile bindings-build
bindings-build: bindings-build:
go run ./gen/main.go \ go run ./gen/main.go \
-forge-artifacts $(contracts-dir)/forge-artifacts \ -forge-artifacts $(contracts-dir)/forge-artifacts \
-forge-build-info $(contracts-dir)/artifacts/build-info \
-out ./bindings \ -out ./bindings \
-contracts ./artifacts.json \ -contracts ./artifacts.json \
-source-maps MIPS,PreimageOracle \ -source-maps MIPS,PreimageOracle \
......
This diff is collapsed.
...@@ -12,13 +12,16 @@ import ( ...@@ -12,13 +12,16 @@ import (
"regexp" "regexp"
"strings" "strings"
"text/template" "text/template"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/ast" "github.com/ethereum-optimism/optimism/op-bindings/ast"
"github.com/ethereum-optimism/optimism/op-bindings/foundry" "github.com/ethereum-optimism/optimism/op-bindings/foundry"
"github.com/ethereum-optimism/optimism/op-bindings/hardhat"
) )
type flags struct { type flags struct {
ForgeArtifacts string ForgeArtifacts string
ForgeBuildInfo string
Contracts string Contracts string
SourceMaps string SourceMaps string
OutDir string OutDir string
...@@ -27,6 +30,7 @@ type flags struct { ...@@ -27,6 +30,7 @@ type flags struct {
} }
type data struct { type data struct {
SourceId uint
Name string Name string
StorageLayout string StorageLayout string
DeployedBin string DeployedBin string
...@@ -34,9 +38,17 @@ type data struct { ...@@ -34,9 +38,17 @@ type data struct {
DeployedSourceMap string DeployedSourceMap string
} }
type sourceIdData struct {
Package string
Sources []string
SourceToId map[string]uint
IdToSource map[uint]string
}
func main() { func main() {
var f flags var f flags
flag.StringVar(&f.ForgeArtifacts, "forge-artifacts", "", "Forge artifacts directory, to load sourcemaps from, if available") flag.StringVar(&f.ForgeArtifacts, "forge-artifacts", "", "Forge artifacts directory, to load sourcemaps from, if available")
flag.StringVar(&f.ForgeBuildInfo, "forge-build-info", "", "Forge build info directory, to load source IDs from, if available")
flag.StringVar(&f.OutDir, "out", "", "Output directory to put code in") flag.StringVar(&f.OutDir, "out", "", "Output directory to put code in")
flag.StringVar(&f.Contracts, "contracts", "artifacts.json", "Path to file containing list of contracts to generate bindings for") flag.StringVar(&f.Contracts, "contracts", "artifacts.json", "Path to file containing list of contracts to generate bindings for")
flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for") flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for")
...@@ -197,6 +209,80 @@ func main() { ...@@ -197,6 +209,80 @@ func main() {
outfile.Close() outfile.Close()
log.Printf("wrote file %s\n", outfile.Name()) log.Printf("wrote file %s\n", outfile.Name())
} }
mostRecentBuildInfo, err := getMostRecentlyModifiedFile(f.ForgeBuildInfo)
if err != nil {
log.Fatalf("Error getting most recently modified build info file: %v", err)
}
buildInfoRaw, err := os.ReadFile(mostRecentBuildInfo)
if err != nil {
log.Fatalf("Error reading build info file: %v", err)
}
var buildInfo hardhat.BuildInfo
if err := json.Unmarshal(buildInfoRaw, &buildInfo); err != nil {
log.Fatalf("Error parsing build info file: %v", err)
}
sourceToId := make(map[string]uint)
idToSource := make(map[uint]string)
monorepoBase, err := filepath.Abs(f.MonorepoBase)
if err != nil {
log.Fatalf("Error getting absolute path of monorepo base: %v", err)
}
for k, v := range buildInfo.Output.Sources {
// Replace absolute monorepo base with relative path to monorepo root
k = strings.Replace(k, monorepoBase+"/", "../../", 1)
sourceToId[k] = v.Id
idToSource[v.Id] = k
}
fname := filepath.Join(f.OutDir, "source_ids.go")
outfile, err := os.OpenFile(
fname,
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
0o600,
)
if err != nil {
log.Fatalf("error opening %s: %v\n", fname, err)
}
t = template.Must(template.New("source_ids").Parse(sourceIdTmpl))
d := sourceIdData{
Package: f.Package,
SourceToId: sourceToId,
IdToSource: idToSource,
}
if err := t.Execute(outfile, d); err != nil {
log.Fatalf("error writing template %s: %v", outfile.Name(), err)
}
outfile.Close()
log.Printf("wrote file %s\n", outfile.Name())
}
// getMostRecentlyModifiedFile returns the path of the most recently modified file in the given directory.
func getMostRecentlyModifiedFile(dirPath string) (string, error) {
var mostRecentFile string
var mostRecentModTime time.Time
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Check if the current path is a regular file and not a directory
if !info.IsDir() {
modTime := info.ModTime()
if modTime.After(mostRecentModTime) {
mostRecentModTime = modTime
mostRecentFile = path
}
}
return nil
})
return mostRecentFile, err
} }
var tmpl = `// Code generated - DO NOT EDIT. var tmpl = `// Code generated - DO NOT EDIT.
...@@ -227,3 +313,21 @@ func init() { ...@@ -227,3 +313,21 @@ func init() {
deployedBytecodes["{{.Name}}"] = {{.Name}}DeployedBin deployedBytecodes["{{.Name}}"] = {{.Name}}DeployedBin
} }
` `
var sourceIdTmpl = `// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package {{.Package}}
var Sources = []string{
{{range $key, $value := .SourceToId}} "{{$key}}",
{{end}}}
var SourceToId = map[string]uint{
{{range $key, $value := .SourceToId}} "{{$key}}": {{$value}},
{{end}}}
var IdToSource = map[uint]string{
{{range $key, $value := .IdToSource}} {{$key}}: "{{$value}}",
{{end}}}
`
...@@ -84,10 +84,6 @@ func (s *SourceMap) Info(pc uint64) (source string, line uint32, col uint32) { ...@@ -84,10 +84,6 @@ func (s *SourceMap) Info(pc uint64) (source string, line uint32, col uint32) {
if instr.F < 0 { if instr.F < 0 {
return "generated", 0, 0 return "generated", 0, 0
} }
if instr.F >= int32(len(s.Sources)) {
source = "unknown"
return
}
source = s.Sources[instr.F] source = s.Sources[instr.F]
if instr.S < 0 { if instr.S < 0 {
return return
......
package srcmap package srcmap
import ( import (
"path"
"strings" "strings"
"testing" "testing"
...@@ -11,17 +12,27 @@ import ( ...@@ -11,17 +12,27 @@ import (
) )
func TestSourcemap(t *testing.T) { func TestSourcemap(t *testing.T) {
sourcePath := "../../packages/contracts-bedrock/src/cannon/MIPS.sol" contractsDir := "../../packages/contracts-bedrock"
sources := []string{path.Join(contractsDir, "contracts/cannon/MIPS.sol")}
sources = append(sources, bindings.Sources...)
for i, source := range sources {
// Add relative path to contracts directory if the source is not
// already relativized.
if !strings.HasPrefix(source, "..") {
sources[i] = path.Join(contractsDir, source)
}
}
deployedByteCode := hexutil.MustDecode(bindings.MIPSDeployedBin) deployedByteCode := hexutil.MustDecode(bindings.MIPSDeployedBin)
srcMap, err := ParseSourceMap( srcMap, err := ParseSourceMap(
[]string{sourcePath}, sources,
deployedByteCode, deployedByteCode,
bindings.MIPSDeployedSourceMap) bindings.MIPSDeployedSourceMap)
require.NoError(t, err) require.NoError(t, err)
for i := 0; i < len(deployedByteCode); i++ { for i := 0; i < len(deployedByteCode); i++ {
info := srcMap.FormattedInfo(uint64(i)) info := srcMap.FormattedInfo(uint64(i))
if !strings.HasPrefix(info, "generated:") && !strings.HasPrefix(info, sourcePath) { if strings.HasPrefix(info, "unexpected") {
t.Fatalf("unexpected info: %q", info) t.Fatalf("unexpected info: %q", info)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment