Skip to content

Commit d2dd2ed

Browse files
committed
clean up
1 parent b1e0b9e commit d2dd2ed

16 files changed

+207
-105
lines changed

.gitignore

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ yarn-error.log*
77
pnpm-debug.log*
88
lerna-debug.log*
99

10-
abi/*
11-
pvm/*
12-
evm/*
10+
codegen/abi/*
11+
codegen/pvm/*
12+
codegen/evm/*
13+
*.sha256.txt
1314

1415
node_modules
1516
dist

.prettierrc.json

Lines changed: 0 additions & 6 deletions
This file was deleted.
File renamed without changes.
File renamed without changes.
File renamed without changes.

deno.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
}
1010
},
1111
"tasks": {
12-
"build": "deno run -P src/build-contracts.ts && deno fmt",
12+
"build": "deno run -P src/build-contracts.ts",
1313
"test:evm": "deno task build && USE_REVIVE=evm START_REVIVE_DEV_NODE=true START_ETH_RPC=true deno test -P",
1414
"test:pvm": "deno task build && USE_REVIVE=pvm START_REVIVE_DEV_NODE=true START_ETH_RPC=true deno test -P",
1515
"test:geth": "START_GETH=true deno test -P",
@@ -19,14 +19,16 @@
1919
"include": ["src/all-tests.ts"]
2020
},
2121
"imports": {
22+
"@std/cli": "jsr:@std/cli@^1.0.23",
2223
"viem": "npm:viem@^2.38.3",
2324
"viem/": "npm:/viem@^2.38.3/",
2425
"solc": "npm:solc@^0.8.30",
2526
"@parity/resolc": "npm:@parity/resolc@^0.4.1",
2627
"@std/assert": "jsr:@std/assert@^1.0.15",
2728
"@std/expect": "jsr:@std/expect@^1.0.17",
2829
"@std/testing": "jsr:@std/testing@^1.0.16",
29-
"@std/path": "jsr:@std/path@^1.1.2"
30+
"@std/path": "jsr:@std/path@^1.1.2",
31+
"@std/log": "jsr:@std/log@^0.224"
3032
},
3133
"compilerOptions": {
3234
"strict": true

deno.lock

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/build-contracts.ts

Lines changed: 128 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,82 @@
11
/// <reference path="./solc.d.ts" />
22

3-
import {
4-
compile,
5-
type SolcOutput,
6-
tryResolveImport,
7-
version,
8-
} from '@parity/resolc'
3+
import * as resolc from '@parity/resolc'
94
import solc from 'solc'
105
import { basename, join } from '@std/path'
6+
import * as log from '@std/log'
7+
import { parseArgs } from '@std/cli'
8+
9+
type CompileInput = Parameters<typeof resolc.compile>[0]
10+
const LOG_LEVEL = (Deno.env.get('LOG_LEVEL')?.toUpperCase() ??
11+
'INFO') as log.LevelName
12+
log.setup({
13+
handlers: {
14+
console: new log.ConsoleHandler(LOG_LEVEL),
15+
},
16+
loggers: {
17+
default: {
18+
level: LOG_LEVEL,
19+
handlers: ['console'],
20+
},
21+
},
22+
})
23+
24+
const logger = log.getLogger()
25+
const { filter, solcOnly, force } = parseArgs(Deno.args, {
26+
string: ['filter'],
27+
boolean: ['solcOnly', 'force'],
28+
})
29+
30+
async function computeSha256(content: string): Promise<string> {
31+
const encoder = new TextEncoder()
32+
const data = encoder.encode(content)
33+
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
34+
const hashArray = Array.from(new Uint8Array(hashBuffer))
35+
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
36+
}
1137

12-
type CompileInput = Parameters<typeof compile>[0]
38+
function readCachedHash(hashFile: string): string | null {
39+
try {
40+
return Deno.readTextFileSync(hashFile).trim()
41+
} catch {
42+
return null
43+
}
44+
}
1345

14-
const args = Deno.args
15-
const filter = args.includes('-f') || args.includes('--filter')
16-
? args[args.indexOf('-f') + 1] || args[args.indexOf('--filter') + 1]
17-
: undefined
18-
const solcOnly = args.includes('-s') || args.includes('--solcOnly')
46+
function writeCachedHash(hashFile: string, hash: string): void {
47+
Deno.writeTextFileSync(hashFile, hash)
48+
}
1949

20-
function evmCompile(sources: CompileInput) {
50+
let resolcVersion = ''
51+
async function pvmCompile(file: Deno.DirEntry, sources: CompileInput) {
52+
if (resolcVersion === '') {
53+
if (Deno.env.get('REVIVE_BIN') === undefined) {
54+
resolcVersion = ` @parity/resolc: ${resolc.version().trim()}`
55+
} else {
56+
resolcVersion = new TextDecoder()
57+
.decode(
58+
(
59+
await new Deno.Command('resolc', {
60+
args: ['--version'],
61+
stdout: 'piped',
62+
}).output()
63+
).stdout,
64+
)
65+
.trim()
66+
}
67+
}
68+
logger.info(`Compiling ${file.name} with revive ${resolcVersion}`)
69+
return await resolc.compile(sources, {
70+
bin: Deno.env.get('REVIVE_BIN'),
71+
})
72+
}
73+
74+
let solcVersion = ''
75+
function evmCompile(file: Deno.DirEntry, sources: CompileInput) {
76+
if (solcVersion === '') {
77+
solcVersion = solc.version()
78+
}
79+
logger.info(`Compile ${file.name} with solc ${solcVersion}`)
2180
const input = {
2281
language: 'Solidity',
2382
sources,
@@ -32,84 +91,87 @@ function evmCompile(sources: CompileInput) {
3291

3392
return solc.compile(JSON.stringify(input), {
3493
import: (relativePath: string) => {
35-
const source = Deno.readTextFileSync(tryResolveImport(relativePath))
94+
const source = Deno.readTextFileSync(
95+
resolc.tryResolveImport(relativePath),
96+
)
3697
return { contents: source }
3798
},
3899
})
39100
}
40101

41-
console.log('Compiling contracts...')
102+
logger.debug('Compiling contracts...')
42103

43104
const currentDir = new URL('.', import.meta.url).pathname
44105
const rootDir = join(currentDir, '..')
45106
const contractsDir = join(rootDir, 'contracts')
46-
const abiDir = join(rootDir, 'abi')
47-
const pvmDir = join(rootDir, 'pvm')
48-
const evmDir = join(rootDir, 'evm')
107+
const codegenDir = join(rootDir, 'codegen')
108+
const abiDir = join(codegenDir, 'abi')
109+
const pvmDir = join(codegenDir, 'pvm')
110+
const evmDir = join(codegenDir, 'evm')
49111

50112
const input = Array.from(Deno.readDirSync(contractsDir))
51113
.filter((f) => f.isFile && f.name.endsWith('.sol'))
52114
.filter((f) => !filter || f.name.includes(filter))
53115

54116
for (const file of input) {
55-
console.log(`🔨 Compiling ${file.name}...`)
56117
const name = basename(file.name)
118+
const sourceFilePath = join(contractsDir, file.name)
119+
const sourceContent = Deno.readTextFileSync(sourceFilePath)
120+
const sourceHash = await computeSha256(sourceContent)
57121
const inputSources = {
58122
[name]: {
59-
content: Deno.readTextFileSync(join(contractsDir, file.name)),
123+
content: sourceContent,
60124
},
61125
}
62126

63-
if (!solcOnly) {
64-
if (Deno.env.get('REVIVE_BIN') === undefined) {
65-
console.log(`Compiling with revive @parity/resolc: ${version()}...`)
66-
} else {
67-
// add the result of resolc --version
68-
69-
const output = new TextDecoder().decode(
70-
(
71-
await new Deno.Command('resolc', {
72-
args: ['--version'],
73-
stdout: 'piped',
74-
}).output()
75-
).stdout,
76-
)
77-
console.log(
78-
`Compiling with revive (using ${
79-
Deno.env.get(
80-
'REVIVE_BIN',
81-
)
82-
} - ${output})...`,
83-
)
84-
}
85-
const reviveOut = await compile(inputSources, {
86-
bin: Deno.env.get('REVIVE_BIN'),
87-
})
127+
// Create marker files to track if this source has been compiled
128+
const pvmSourceMarkerFile = join(pvmDir, `.${name}.sha256.txt`)
129+
const pvmSourceMarkerHash = readCachedHash(pvmSourceMarkerFile)
130+
const needsPvmCompilation = !solcOnly &&
131+
(force || pvmSourceMarkerHash !== sourceHash)
132+
133+
const evmSourceMarkerFile = join(evmDir, `.${name}.sha256.txt`)
134+
const evmSourceMarkerHash = readCachedHash(evmSourceMarkerFile)
135+
const needsEvmCompilation = force || evmSourceMarkerHash !== sourceHash
136+
137+
if (needsPvmCompilation) {
138+
const reviveOut = await pvmCompile(file, inputSources)
88139

89140
for (const contracts of Object.values(reviveOut.contracts)) {
90141
for (const [name, contract] of Object.entries(contracts)) {
91142
if (contract?.evm?.bytecode?.object) {
92-
console.log(`📜 Add PVM contract ${name}`)
143+
const pvmFile = join(pvmDir, `${name}.polkavm`)
144+
logger.info(`📜 Add PVM contract ${name}`)
93145
const bytecode = new Uint8Array(
94146
contract.evm.bytecode.object
95147
.match(/.{1,2}/g)!
96148
.map((byte) => parseInt(byte, 16)),
97149
)
98-
Deno.writeFileSync(
99-
join(pvmDir, `${name}.polkavm`),
100-
bytecode,
101-
)
150+
Deno.writeFileSync(pvmFile, bytecode)
102151
}
103152
}
104153
}
154+
writeCachedHash(pvmSourceMarkerFile, sourceHash)
155+
} else if (!solcOnly) {
156+
logger.debug(
157+
`⏭️ Skipping PVM compilation for ${file.name} (unchanged)`,
158+
)
159+
}
160+
161+
if (!needsEvmCompilation) {
162+
logger.debug(
163+
`⏭️ Skipping EVM compilation for ${file.name} (unchanged)`,
164+
)
165+
continue
105166
}
106167

107-
console.log(`Compile with solc ${file.name}`)
108-
const evmOut = JSON.parse(evmCompile(inputSources)) as SolcOutput
168+
const evmOut = JSON.parse(
169+
evmCompile(file, inputSources),
170+
) as resolc.SolcOutput
109171

110172
if (evmOut.errors) {
111173
for (const error of evmOut.errors) {
112-
console.error(error.formattedMessage)
174+
logger.error(error.formattedMessage)
113175
}
114176

115177
if (evmOut.errors.some((err) => err.severity !== 'warning')) {
@@ -119,21 +181,24 @@ for (const file of input) {
119181

120182
for (const contracts of Object.values(evmOut.contracts)) {
121183
for (const [name, contract] of Object.entries(contracts)) {
122-
console.log(`📜 Add EVM contract ${name}`)
184+
const evmFile = join(evmDir, `${name}.bin`)
185+
const abiFile = join(abiDir, `${name}.ts`)
123186

124187
// Only write bytecode if it exists and is not empty
125188
if (contract.evm?.bytecode?.object) {
126189
const bytecodeHex = contract.evm.bytecode.object
127190
if (bytecodeHex.length > 0) {
191+
logger.info(`📜 Add EVM contract ${name}`)
128192
const bytecode = new Uint8Array(
129193
bytecodeHex
130194
.match(/.{1,2}/g)!
131195
.map((byte) => parseInt(byte, 16)),
132196
)
133-
Deno.writeFileSync(join(evmDir, `${name}.bin`), bytecode)
197+
Deno.writeFileSync(evmFile, bytecode)
134198
}
135199
}
136200

201+
logger.info(`📜 Add ABI ${name}`)
137202
const abi = contract.abi
138203
const abiName = `${name}Abi`
139204
const tsContent = `export const ${abiName} = ${
@@ -143,7 +208,14 @@ for (const file of input) {
143208
2,
144209
)
145210
} as const\n`
146-
Deno.writeTextFileSync(join(abiDir, `${name}.ts`), tsContent)
211+
Deno.writeTextFileSync(abiFile, tsContent)
147212
}
148213
}
214+
215+
// Mark that we've compiled this source file for EVM
216+
writeCachedHash(evmSourceMarkerFile, sourceHash)
217+
218+
if (needsEvmCompilation || needsPvmCompilation) {
219+
logger.info(`✅ Compiled ${file.name} successfully`)
220+
}
149221
}

0 commit comments

Comments
 (0)