-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tool to validate the correctness of the Solidity code snippets (#68)
* Add std checker * Try stuff * Try again for real * Try stuff * Add more stuff
- Loading branch information
Showing
6 changed files
with
204 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Check code snippets | ||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
|
||
env: | ||
FOUNDRY_PROFILE: ci | ||
|
||
jobs: | ||
check-code-snippets: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Install Foundry | ||
uses: foundry-rs/foundry-toolchain@v1 | ||
with: | ||
version: nightly | ||
|
||
- name: Install deps | ||
run: forge install | ||
|
||
- name: Validate code snippets in README | ||
run: go run tools/stdchecker/main.go --root ./tools/stdchecker ./README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,5 @@ cache/ | |
out/ | ||
src-forge-test/ | ||
docs/ | ||
suave-std-gen/ | ||
suave-std-gen/ | ||
repo-src/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[profile.default] | ||
src = "repo-src" | ||
solc_version = "0.8.23" | ||
include_paths = ["../../"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"flag" | ||
"fmt" | ||
"io/fs" | ||
"log" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"regexp" | ||
) | ||
|
||
var ( | ||
inputFolder string | ||
rootFolder string | ||
) | ||
|
||
func main() { | ||
flag.StringVar(&rootFolder, "root", "./", "root folder of stdchecker") | ||
flag.Parse() | ||
args := flag.Args() | ||
|
||
if len(args) != 1 { | ||
log.Fatal("Usage: stdchecker <suave-std-folder>") | ||
} | ||
|
||
inputFolder = args[0] | ||
|
||
snippets := readTargets(inputFolder) | ||
writeSnippets(snippets) | ||
|
||
// use forge to build the snippets | ||
_, err := execForgeCommand([]string{ | ||
"build", | ||
"--root", rootFolder, | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func writeSnippets(snippets [][]byte) { | ||
// remove the destination folder first | ||
if err := os.RemoveAll(filepath.Join(rootFolder, "repo-src")); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
for indx, snippet := range snippets { | ||
dst := filepath.Join(rootFolder, fmt.Sprintf("repo-src/snippet_%d.sol", indx)) | ||
|
||
abs := filepath.Dir(dst) | ||
if err := os.MkdirAll(abs, 0755); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
if err := os.WriteFile(dst, []byte(snippet), 0755); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func readTargets(target string) [][]byte { | ||
// if the target is a file, read the content and extract the Solidity code blocks | ||
// if the target is a folder, read all the files in the folder and extract the Solidity code blocks | ||
info, err := os.Stat(target) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
markdownFiles := []string{} | ||
if info.IsDir() { | ||
filepath.WalkDir(target, func(path string, d fs.DirEntry, err error) error { | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if d.IsDir() { | ||
return nil | ||
} | ||
|
||
if filepath.Ext(path) != ".md" { | ||
return nil | ||
} | ||
markdownFiles = append(markdownFiles, path) | ||
return nil | ||
}) | ||
} else { | ||
markdownFiles = append(markdownFiles, target) | ||
} | ||
|
||
// Regular expression to match Solidity code blocks | ||
re := regexp.MustCompile("```solidity\\s+(?s)(.*?)```") | ||
|
||
snippets := [][]byte{} | ||
for _, file := range markdownFiles { | ||
content, err := os.ReadFile(file) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// Find all matches | ||
matches := re.FindAllSubmatch(content, -1) | ||
|
||
for _, match := range matches { | ||
snippet := match[1] | ||
if bytes.Contains(snippet, []byte("[skip-check]")) { | ||
// skip if the snippet contains the tag [skip-check] | ||
continue | ||
} | ||
snippets = append(snippets, snippet) | ||
} | ||
} | ||
|
||
if len(snippets) == 0 { | ||
log.Fatal("No Solidity code blocks found in the target") | ||
} | ||
log.Printf("Found %d Solidity code blocks", len(snippets)) | ||
return snippets | ||
} | ||
|
||
func execForgeCommand(args []string) (string, error) { | ||
_, err := exec.LookPath("forge") | ||
if err != nil { | ||
return "", fmt.Errorf("forge command not found in PATH: %v", err) | ||
} | ||
|
||
// Create a command to run the forge command | ||
cmd := exec.Command("forge", args...) | ||
|
||
// Set up output buffer | ||
var outBuf, errBuf bytes.Buffer | ||
cmd.Stdout = &outBuf | ||
cmd.Stderr = &errBuf | ||
|
||
// Run the command | ||
if err := cmd.Run(); err != nil { | ||
return "", fmt.Errorf("error running command: %v, %s", err, errBuf.String()) | ||
} | ||
|
||
return outBuf.String(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
suave-std/=../../src/ | ||
Solidity-RLP/=../../lib/Solidity-RLP/contracts/ | ||
ds-test/=../../lib/forge-std/lib/ds-test/src/ | ||
forge-std/=../../lib/forge-std/src/ | ||
solady/=../../lib/solady/ |