forked from ethereum-optimism/cannon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchallenge_fault.sh
executable file
·138 lines (106 loc) · 4.8 KB
/
challenge_fault.sh
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
137
138
#!/usr/bin/env bash
# --- DOC ----------------------------------------------------------------------
# Unlike the simple scenario (cf. challenge_simple.sh), in this
# challenge-response scenario we use the correct block data (preimages) and
# instead use the `OUTPUTFAULT` environment variable to request a fault in the
# challenger's execution, making his challenge invalid.
#
# The "fault" in question is a behaviour hardcoded in `mipsevm` (Unicorn mode
# only) which triggers when the `OUTPUTFAULT` env var is set: when writing to
# MIPS address 0x30000804 (address where the output hash is written at the end
# of execution), it will write a wrong value instead.
#
# Alternatively, if `REGFAULT` is set, it should contain a MIPS execution step
# number and causes the MIPS register V0 to be set to a bogus value at the given
# execution step. (Just like before, this behaviour is hardcoded in `mipsevm` in
# Unicorn mode and triggers when `REGFAULT` is set.)
#
# This is much slower than the previous scenario because:
#
# - Since we write to the output hash at the end of execution, we will execute ~
# `log(n) * 3/4 * n` MIPS steps (where `n` = number of steps in full
# execution) vs `log(n) * 1/4 * n`in the previous example. (This is the
# difference of having the fault occur in the first vs (one of) the last
# steps.)
#
# - The challenged block contains almost 4x as many transactions as the original
# (8.5M vs 30M gas).
# --- SCRIPT SETUP -------------------------------------------------------------
shout() {
echo ""
echo "----------------------------------------"
echo "$1"
echo "----------------------------------------"
echo ""
}
# Exit if any command fails.
set -e
exit_trap() {
# Print an error if the last command failed
# (in which case the script is exiting because of set -e).
[[ $? == 0 ]] && return
echo "----------------------------------------"
echo "EARLY EXIT: SCRIPT FAILED"
echo "----------------------------------------"
# Kill (send SIGTERM) to the whole process group, also killing
# any background processes.
# I think the trap command resets SIGTERM before resending it to the whole
# group. (cf. https://stackoverflow.com/a/2173421)
trap - SIGTERM && kill -- -$$
}
trap "exit_trap" SIGINT SIGTERM EXIT
# --- BOOT MAINNET FORK --------------------------------------------------------
NODE_LOG="challenge_fault_node.log"
shout "BOOTING MAINNET FORK NODE IN BACKGROUND (LOG: $NODE_LOG)"
# get directory containing this file
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
# run a hardhat mainnet fork node
"$SCRIPT_DIR/forked_node.sh" > "$NODE_LOG" 2>&1 &
# give the node some time to boot up
sleep 10
# --- CHALLENGE SETUP ----------------------------------------------------------
# block whose transition will be challenged
# this variable is read by challenge.js, respond.js and assert.js
export BLOCK=13284491
# challenge ID, read by respond.js and assert.js
export ID=0
# clear data from previous runs
mkdir -p /tmp/cannon /tmp/cannon_fault && rm -rf /tmp/cannon/* /tmp/cannon_fault/*
# stored in /tmp/cannon/golden.json
shout "GENERATING INITIAL MEMORY STATE CHECKPOINT"
mipsevm/mipsevm
shout "DEPLOYING CONTRACTS"
npx hardhat run scripts/deploy.js --network hosthat
# challenger will use same initial memory checkpoint and deployed contracts
cp /tmp/cannon/{golden,deployed}.json /tmp/cannon_fault/
shout "FETCHING PREIMAGES FOR REAL BLOCK"
minigeth/go-ethereum $BLOCK
shout "COMPUTING REAL MIPS FINAL MEMORY CHECKPOINT"
mipsevm/mipsevm $BLOCK
# these are the preimages for the real block (but go into a different basedir)
shout "FETCHING PREIMAGES FOR FAULTY BLOCK"
BASEDIR=/tmp/cannon_fault minigeth/go-ethereum $BLOCK
# since the computation includes a fault, the output file will be different than
# for the real block
shout "COMPUTE FAKE MIPS CHECKPOINT"
OUTPUTFAULT=1 BASEDIR=/tmp/cannon_fault mipsevm/mipsevm $BLOCK
# alternatively, to inject a fault in registers instead of memory
# REGFAULT=13240000 BASEDIR=/tmp/cannon_fault mipsevm/mipsevm $BLOCK
# --- BINARY SEARCH ------------------------------------------------------------
shout "STARTING CHALLENGE"
BASEDIR=/tmp/cannon_fault npx hardhat run scripts/challenge.js --network hosthat
shout "BINARY SEARCH"
for i in {1..25}; do
echo ""
echo "--- STEP $i / 25 --"
echo ""
OUTPUTFAULT=1 BASEDIR=/tmp/cannon_fault CHALLENGER=1 npx hardhat run scripts/respond.js --network hosthat
npx hardhat run scripts/respond.js --network hosthat
done
# --- SINGLE STEP EXECUTION ----------------------------------------------------
shout "ASSERTING AS CHALLENGER (should fail)"
set +e # this should fail!
BASEDIR=/tmp/cannon_fault CHALLENGER=1 npx hardhat run scripts/assert.js --network hosthat
set -e
shout "ASSERTING AS DEFENDER (should pass)"
npx hardhat run scripts/assert.js --network hosthat