1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const fs = require("fs")
const rlp = require('rlp')
const child_process = require("child_process")
async function deploy() {
const MIPS = await ethers.getContractFactory("MIPS")
const m = await MIPS.deploy()
const mm = await ethers.getContractAt("MIPSMemory", await m.m())
let startTrie = JSON.parse(fs.readFileSync("/tmp/cannon/golden.json"))
let goldenRoot = startTrie["root"]
console.log("goldenRoot is", goldenRoot)
const Challenge = await ethers.getContractFactory("Challenge")
const c = await Challenge.deploy(m.address, goldenRoot)
return [c,m,mm]
}
function getBlockRlp(block) {
let dat = [
block['parentHash'],
block['sha3Uncles'],
block['miner'],
block['stateRoot'],
block['transactionsRoot'],
block['receiptsRoot'],
block['logsBloom'],
block['difficulty'],
block['number'],
block['gasLimit'],
block['gasUsed'],
block['timestamp'],
block['extraData'],
block['mixHash'],
block['nonce'],
];
// post london
if (block['baseFeePerGas'] !== undefined) {
dat.push(block['baseFeePerGas'])
}
dat = dat.map(x => (x == "0x0") ? "0x" : x)
//console.log(dat)
let rdat = rlp.encode(dat)
if (ethers.utils.keccak256(rdat) != block['hash']) {
throw "block hash doesn't match"
}
return rdat
}
async function deployed() {
let addresses = JSON.parse(fs.readFileSync("/tmp/cannon/deployed.json"))
const c = await ethers.getContractAt("Challenge", addresses["Challenge"])
const m = await ethers.getContractAt("MIPS", addresses["MIPS"])
const mm = await ethers.getContractAt("MIPSMemory", addresses["MIPSMemory"])
return [c,m,mm]
}
class MissingHashError extends Error {
constructor(hash, offset) {
super("hash is missing")
this.hash = hash
this.offset = offset
}
}
async function getTrieNodesForCall(c, caddress, cdat, preimages) {
let nodes = []
while (1) {
try {
// TODO: make this eth call?
// needs something like InitiateChallengeWithTrieNodesj
let calldata = c.interface.encodeFunctionData("CallWithTrieNodes", [caddress, cdat, nodes])
ret = await ethers.provider.call({
to:c.address,
data:calldata
});
break
} catch(e) {
let missing = e.toString().split("'")[1]
if (missing == undefined) {
// other kind of error from HTTPProvider
missing = e.error.message.toString().split("execution reverted: ")[1]
}
if (missing !== undefined && missing.length == 64) {
console.log("requested node", missing)
let node = preimages["0x"+missing]
if (node === undefined) {
throw("node not found")
}
const bin = Uint8Array.from(Buffer.from(node, 'base64').toString('binary'), c => c.charCodeAt(0))
nodes.push(bin)
continue
} else if (missing !== undefined && missing.length == 128) {
let hash = missing.slice(0, 64)
let offset = parseInt(missing.slice(64, 128), 16)
console.log("requested hash oracle", hash, offset)
throw new MissingHashError(hash, offset)
} else {
console.log(e)
break
}
}
}
return nodes
}
function getTrieAtStep(blockNumberN, step) {
const fn = "/tmp/cannon/0_"+blockNumberN.toString()+"/checkpoint_"+step.toString()+".json"
if (!fs.existsSync(fn)) {
console.log("running mipsevm")
child_process.execSync("mipsevm/mipsevm "+blockNumberN.toString()+" "+step.toString(), {stdio: 'inherit'})
}
return JSON.parse(fs.readFileSync(fn))
}
async function writeMemory(mm, root, addr, data, bytes32=false) {
if (bytes32) {
ret = await mm.WriteBytes32WithReceipt(root, addr, data)
} else {
ret = await mm.WriteMemoryWithReceipt(root, addr, data)
}
const receipt = await ret.wait()
for (l of receipt.logs) {
if (l.topics[0] == "0x86b89b5c9818dbbf520dd979a5f250d357508fe11b9511d4a43fd9bc6aa1be70") {
root = l.data
}
}
console.log("new hash", root)
return root
}
module.exports = { deploy, deployed, getTrieNodesForCall, getBlockRlp, getTrieAtStep, writeMemory, MissingHashError }