Skip to content

Commit 4c67886

Browse files
authored
Merge pull request #13 from EspressoSystems/batch-validation
Add justification to batches, progress on validation pipeline
2 parents c3c566d + 46fe352 commit 4c67886

File tree

28 files changed

+192
-17
lines changed

28 files changed

+192
-17
lines changed

arbitrator/jit/src/machine.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ pub fn create(opts: &Opts, env: WasmEnv) -> (Instance, FunctionEnv<WasmEnv>, Sto
107107
"github.com/offchainlabs/nitro/wavmio.getGlobalStateU64" => func!(wavmio::get_global_state_u64),
108108
"github.com/offchainlabs/nitro/wavmio.setGlobalStateU64" => func!(wavmio::set_global_state_u64),
109109
"github.com/offchainlabs/nitro/wavmio.readInboxMessage" => func!(wavmio::read_inbox_message),
110+
"github.com/offchainlabs/nitro/wavmio.readHotShotCommitment" => func!(wavmio::read_hotshot_commitment),
110111
"github.com/offchainlabs/nitro/wavmio.readDelayedInboxMessage" => func!(wavmio::read_delayed_inbox_message),
111112
"github.com/offchainlabs/nitro/wavmio.resolvePreImage" => {
112113
#[allow(deprecated)] // we're just keeping this around until we no longer need to validate old replay binaries
@@ -184,6 +185,7 @@ impl From<RuntimeError> for Escape {
184185

185186
pub type WasmEnvMut<'a> = FunctionEnvMut<'a, WasmEnv>;
186187
pub type Inbox = BTreeMap<u64, Vec<u8>>;
188+
pub type HotShotCommitmentMap = BTreeMap<u64, [u8; 32]>;
187189
pub type Preimages = BTreeMap<PreimageType, BTreeMap<[u8; 32], Vec<u8>>>;
188190

189191
#[derive(Default)]
@@ -202,6 +204,8 @@ pub struct WasmEnv {
202204
pub preimages: Preimages,
203205
/// The sequencer inbox's messages
204206
pub sequencer_messages: Inbox,
207+
/// Mapping from batch positions to hotshot commitments
208+
pub hotshot_comm_map: HotShotCommitmentMap,
205209
/// The delayed inbox's messages
206210
pub delayed_messages: Inbox,
207211
/// The purpose and connections of this process

arbitrator/jit/src/wavmio.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use crate::{
55
gostack::GoStack,
6-
machine::{Escape, Inbox, MaybeEscape, WasmEnv, WasmEnvMut},
6+
machine::{Escape, HotShotCommitmentMap, Inbox, MaybeEscape, WasmEnv, WasmEnvMut},
77
socket,
88
};
99

@@ -85,6 +85,14 @@ pub fn set_global_state_u64(mut env: WasmEnvMut, sp: u32) -> MaybeEscape {
8585
Ok(())
8686
}
8787

88+
pub fn read_hotshot_commitment(mut env: WasmEnvMut, sp: u32) -> MaybeEscape {
89+
let (sp, env) = GoStack::new(sp, &mut env);
90+
ready_hostio(env)?;
91+
let hotshot_comms = &env.hotshot_comm_map;
92+
93+
read_hotshot_commitment_impl(&sp, hotshot_comms, "wavmio.readHotShotCommitment")
94+
}
95+
8896
pub fn read_inbox_message(mut env: WasmEnvMut, sp: u32) -> MaybeEscape {
8997
let (sp, env) = GoStack::new(sp, &mut env);
9098
ready_hostio(env)?;
@@ -101,6 +109,32 @@ pub fn read_delayed_inbox_message(mut env: WasmEnvMut, sp: u32) -> MaybeEscape {
101109
inbox_message_impl(&sp, inbox, "wavmio.readDelayedInboxMessage")
102110
}
103111

112+
// Reads a hotshot commitment
113+
fn read_hotshot_commitment_impl(
114+
sp: &GoStack,
115+
comm_map: &HotShotCommitmentMap,
116+
name: &str,
117+
) -> MaybeEscape {
118+
let msg_num = sp.read_u64(0);
119+
let out_ptr = sp.read_u64(1);
120+
let out_len = sp.read_u64(2);
121+
if out_len != 32 {
122+
eprintln!("Go trying to read header bytes with out len {out_len} in {name}");
123+
sp.write_u64(5, 0);
124+
return Ok(());
125+
}
126+
127+
let message = comm_map.get(&msg_num).unwrap_or(&[0; 32]);
128+
129+
if out_ptr + 32 > sp.memory_size() {
130+
let text = format!("memory bounds exceeded in {}", name);
131+
return Escape::hostio(&text);
132+
}
133+
sp.write_slice(out_ptr, message);
134+
sp.write_u64(5, 32);
135+
Ok(())
136+
}
137+
104138
/// Reads an inbox message
105139
/// note: the order of the checks is very important.
106140
fn inbox_message_impl(sp: &GoStack, inbox: &Inbox, name: &str) -> MaybeEscape {
@@ -273,7 +307,9 @@ fn ready_hostio(env: &mut WasmEnv) -> MaybeEscape {
273307
while socket::read_u8(stream)? == socket::ANOTHER {
274308
let position = socket::read_u64(stream)?;
275309
let message = socket::read_bytes(stream)?;
310+
let hotshot_comm = socket::read_bytes32(stream)?;
276311
env.sequencer_messages.insert(position, message);
312+
env.hotshot_comm_map.insert(position, hotshot_comm);
277313
}
278314
while socket::read_u8(stream)? == socket::ANOTHER {
279315
let position = socket::read_u64(stream)?;

arbitrator/prover/src/host.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub enum Hostio {
5252
WavmReadKeccakPreimage,
5353
WavmReadSha256Preimage,
5454
WavmReadInboxMessage,
55+
WavmReadHotShotCommitment,
5556
WavmReadDelayedInboxMessage,
5657
WavmHaltAndSetFinished,
5758
}
@@ -76,6 +77,7 @@ impl FromStr for Hostio {
7677
("env", "wavm_read_sha2_256_preimage") => WavmReadSha256Preimage,
7778
("env", "wavm_read_inbox_message") => WavmReadInboxMessage,
7879
("env", "wavm_read_delayed_inbox_message") => WavmReadDelayedInboxMessage,
80+
("env", "wavm_read_hotshot_header") => WavmReadHotShotCommitment,
7981
("env", "wavm_halt_and_set_finished") => WavmHaltAndSetFinished,
8082
_ => bail!("no such hostio {} in {}", name.red(), module.red()),
8183
})
@@ -109,6 +111,7 @@ impl Hostio {
109111
WavmSetGlobalStateBytes32 => func!([I32, I32]),
110112
WavmGetGlobalStateU64 => func!([I32], [I64]),
111113
WavmSetGlobalStateU64 => func!([I32, I64]),
114+
WavmReadHotShotCommitment => func!([I32, I32]),
112115
WavmReadKeccakPreimage => func!([I32, I32], [I32]),
113116
WavmReadSha256Preimage => func!([I32, I32], [I32]),
114117
WavmReadInboxMessage => func!([I64, I32, I32], [I32]),
@@ -180,6 +183,11 @@ impl Hostio {
180183
opcode!(LocalGet, 1);
181184
opcode!(ReadPreImage, PreimageType::Sha2_256);
182185
}
186+
WavmReadHotShotCommitment => {
187+
// TODO implement for fault proofs
188+
// https://github.com/EspressoSystems/espresso-sequencer/issues/670
189+
unimplemented!()
190+
}
183191
WavmReadInboxMessage => {
184192
opcode!(LocalGet, 0);
185193
opcode!(LocalGet, 1);

arbitrator/wasm-libraries/host-io/src/lib.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ pub unsafe extern "C" fn go__github_com_offchainlabs_nitro_wavmio_setGlobalState
7171
wavm_set_globalstate_u64(idx, sp.read_u64(1));
7272
}
7373

74+
#[no_mangle]
75+
pub unsafe extern "C" fn go__github_com_offchainlabs_nitro_wavmio_readHotShotCommitment(
76+
sp: GoStack,
77+
) {
78+
// TODO implement for fault proofs
79+
// https://github.com/EspressoSystems/espresso-sequencer/issues/671
80+
return unimplemented!();
81+
}
82+
7483
#[no_mangle]
7584
pub unsafe extern "C" fn go__github_com_offchainlabs_nitro_wavmio_readInboxMessage(sp: GoStack) {
7685
let msg_num = sp.read_u64(0);
@@ -120,7 +129,9 @@ pub unsafe extern "C" fn go__github_com_offchainlabs_nitro_wavmio_readDelayedInb
120129
}
121130

122131
#[no_mangle]
123-
pub unsafe extern "C" fn go__github_com_offchainlabs_nitro_wavmio_resolveTypedPreimage(sp: GoStack) {
132+
pub unsafe extern "C" fn go__github_com_offchainlabs_nitro_wavmio_resolveTypedPreimage(
133+
sp: GoStack,
134+
) {
124135
let preimage_type = sp.read_u8(0);
125136
let hash_ptr = sp.read_u64(1);
126137
let hash_len = sp.read_u64(2);

arbos/arbostypes/incomingmessage.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/ethereum/go-ethereum/crypto"
1616
"github.com/ethereum/go-ethereum/params"
1717

18+
"github.com/offchainlabs/nitro/arbos/espresso"
1819
"github.com/offchainlabs/nitro/arbos/util"
1920
"github.com/offchainlabs/nitro/util/arbmath"
2021
)
@@ -34,13 +35,19 @@ const (
3435

3536
const MaxL2MessageSize = 256 * 1024
3637

38+
type EspressoBlockJustification struct {
39+
Header espresso.Header
40+
Proof espresso.NmtProof
41+
}
42+
3743
type L1IncomingMessageHeader struct {
38-
Kind uint8 `json:"kind"`
39-
Poster common.Address `json:"sender"`
40-
BlockNumber uint64 `json:"blockNumber"`
41-
Timestamp uint64 `json:"timestamp"`
42-
RequestId *common.Hash `json:"requestId" rlp:"nilList"`
43-
L1BaseFee *big.Int `json:"baseFeeL1"`
44+
Kind uint8 `json:"kind"`
45+
Poster common.Address `json:"sender"`
46+
BlockNumber uint64 `json:"blockNumber"`
47+
Timestamp uint64 `json:"timestamp"`
48+
RequestId *common.Hash `json:"requestId" rlp:"nilList"`
49+
L1BaseFee *big.Int `json:"baseFeeL1"`
50+
BlockJustification *EspressoBlockJustification `json:"justification,omitempty" rlp:"optional"`
4451
}
4552

4653
func (h L1IncomingMessageHeader) SeqNum() (uint64, error) {
@@ -228,6 +235,7 @@ func ParseIncomingL1Message(rd io.Reader, batchFetcher FallibleBatchFetcher) (*L
228235
timestamp,
229236
&requestId,
230237
baseFeeL1.Big(),
238+
nil,
231239
},
232240
data,
233241
nil,

arbos/block_processor.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/offchainlabs/nitro/arbos/arbosState"
1414
"github.com/offchainlabs/nitro/arbos/arbostypes"
15+
"github.com/offchainlabs/nitro/arbos/espresso"
1516
"github.com/offchainlabs/nitro/arbos/l2pricing"
1617
"github.com/offchainlabs/nitro/arbos/util"
1718
"github.com/offchainlabs/nitro/solgen/go/precompilesgen"
@@ -129,6 +130,7 @@ func ProduceBlock(
129130
message *arbostypes.L1IncomingMessage,
130131
delayedMessagesRead uint64,
131132
lastBlockHeader *types.Header,
133+
lastHotShotCommitment *espresso.Commitment,
132134
statedb *state.StateDB,
133135
chainContext core.ChainContext,
134136
chainConfig *params.ChainConfig,
@@ -158,7 +160,7 @@ func ProduceBlock(
158160

159161
hooks := NoopSequencingHooks()
160162
return ProduceBlockAdvanced(
161-
message.Header, txes, delayedMessagesRead, lastBlockHeader, statedb, chainContext, chainConfig, hooks,
163+
message.Header, txes, delayedMessagesRead, lastBlockHeader, lastHotShotCommitment, statedb, chainContext, chainConfig, hooks,
162164
)
163165
}
164166

@@ -168,6 +170,7 @@ func ProduceBlockAdvanced(
168170
txes types.Transactions,
169171
delayedMessagesRead uint64,
170172
lastBlockHeader *types.Header,
173+
lastHotShotCommitment *espresso.Commitment,
171174
statedb *state.StateDB,
172175
chainContext core.ChainContext,
173176
chainConfig *params.ChainConfig,
@@ -191,6 +194,29 @@ func ProduceBlockAdvanced(
191194
l1Timestamp: l1Header.Timestamp,
192195
}
193196

197+
// Espresso-specific validation
198+
// TODO test: https://github.com/EspressoSystems/espresso-sequencer/issues/772
199+
if chainConfig.Espresso {
200+
jst := l1Header.BlockJustification
201+
if jst == nil {
202+
return nil, nil, errors.New("batch missing espresso justification")
203+
204+
}
205+
hotshotHeader := jst.Header
206+
if *lastHotShotCommitment != hotshotHeader.Commit() {
207+
return nil, nil, errors.New("invalid hotshot header")
208+
}
209+
var roots = []*espresso.NmtRoot{&hotshotHeader.TransactionsRoot}
210+
var proofs = []*espresso.NmtProof{&l1Header.BlockJustification.Proof}
211+
// If the validation function below were not mocked, we would need to serialize the transactions
212+
// in the batch here. To avoid the unnecessary overhead, we provide an empty array instead.
213+
var txs []espresso.Bytes
214+
err := espresso.ValidateBatchTransactions(chainConfig.ChainID.Uint64(), roots, proofs, txs)
215+
if err != nil {
216+
return nil, nil, errors.New("failed to validate namespace proof)")
217+
}
218+
}
219+
194220
header := createNewHeader(lastBlockHeader, l1Info, state, chainConfig)
195221
signer := types.MakeSigner(chainConfig, header.Number, header.Time)
196222
// Note: blockGasLeft will diverge from the actual gas left during execution in the event of invalid txs,
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)