@@ -13,10 +13,13 @@ import (
13
13
"fmt"
14
14
"math"
15
15
"math/big"
16
+ "os"
16
17
"strings"
17
18
"sync/atomic"
18
19
"time"
19
20
21
+ "github.com/ethereum/go-ethereum/crypto"
22
+
20
23
"github.com/andybalholm/brotli"
21
24
"github.com/spf13/pflag"
22
25
@@ -182,13 +185,13 @@ type BatchPosterConfig struct {
182
185
Dangerous BatchPosterDangerousConfig `koanf:"dangerous"`
183
186
ReorgResistanceMargin time.Duration `koanf:"reorg-resistance-margin" reload:"hot"`
184
187
CheckBatchCorrectness bool `koanf:"check-batch-correctness"`
185
-
186
- gasRefunder common.Address
187
- l1BlockBound l1BlockBound
188
-
188
+ gasRefunder common.Address
189
+ l1BlockBound l1BlockBound
189
190
// Espresso specific flags
190
- LightClientAddress string `koanf:"light-client-address"`
191
- HotShotUrl string `koanf:"hotshot-url"`
191
+ LightClientAddress string `koanf:"light-client-address"`
192
+ HotShotUrl string `koanf:"hotshot-url"`
193
+ UserDataAttestationFile string `koanf:"user-data-attestation-file"`
194
+ QuoteFile string `koanf:"quote-file"`
192
195
}
193
196
194
197
func (c * BatchPosterConfig ) Validate () error {
@@ -241,6 +244,8 @@ func BatchPosterConfigAddOptions(prefix string, f *pflag.FlagSet) {
241
244
f .Uint64 (prefix + ".gas-estimate-base-fee-multiple-bips" , uint64 (DefaultBatchPosterConfig .GasEstimateBaseFeeMultipleBips ), "for gas estimation, use this multiple of the basefee (measured in basis points) as the max fee per gas" )
242
245
f .Duration (prefix + ".reorg-resistance-margin" , DefaultBatchPosterConfig .ReorgResistanceMargin , "do not post batch if its within this duration from layer 1 minimum bounds. Requires l1-block-bound option not be set to \" ignore\" " )
243
246
f .Bool (prefix + ".check-batch-correctness" , DefaultBatchPosterConfig .CheckBatchCorrectness , "setting this to true will run the batch against an inbox multiplexer and verifies that it produces the correct set of messages" )
247
+ f .String (prefix + ".user-data-attestation-file" , DefaultBatchPosterConfig .UserDataAttestationFile , "specifies the file containing the user data attestation" )
248
+ f .String (prefix + ".quote-file" , DefaultBatchPosterConfig .QuoteFile , "specifies the file containing the quote" )
244
249
redislock .AddConfigOptions (prefix + ".redis-lock" , f )
245
250
dataposter .DataPosterConfigAddOptions (prefix + ".data-poster" , f , dataposter .DefaultDataPosterConfig )
246
251
genericconf .WalletConfigAddOptions (prefix + ".parent-chain-wallet" , f , DefaultBatchPosterConfig .ParentChainWallet .Pathname )
@@ -272,6 +277,8 @@ var DefaultBatchPosterConfig = BatchPosterConfig{
272
277
GasEstimateBaseFeeMultipleBips : arbmath .OneInUBips * 3 / 2 ,
273
278
ReorgResistanceMargin : 10 * time .Minute ,
274
279
CheckBatchCorrectness : true ,
280
+ UserDataAttestationFile : "" ,
281
+ QuoteFile : "" ,
275
282
}
276
283
277
284
var DefaultBatchPosterL1WalletConfig = genericconf.WalletConfig {
@@ -1116,11 +1123,16 @@ func (b *BatchPoster) encodeAddBatch(
1116
1123
var calldata []byte
1117
1124
var kzgBlobs []kzg4844.Blob
1118
1125
var err error
1126
+ var userData []byte
1119
1127
if use4844 {
1120
1128
kzgBlobs , err = blobs .EncodeBlobs (l2MessageData )
1121
1129
if err != nil {
1122
1130
return nil , nil , fmt .Errorf ("failed to encode blobs: %w" , err )
1123
1131
}
1132
+ _ , blobHashes , err := blobs .ComputeCommitmentsAndHashes (kzgBlobs )
1133
+ if err != nil {
1134
+ return nil , nil , fmt .Errorf ("failed to compute blob hashes: %w" , err )
1135
+ }
1124
1136
// EIP4844 transactions to the sequencer inbox will not use transaction calldata for L2 info.
1125
1137
calldata , err = method .Inputs .Pack (
1126
1138
seqNum ,
@@ -1129,6 +1141,25 @@ func (b *BatchPoster) encodeAddBatch(
1129
1141
new (big.Int ).SetUint64 (uint64 (prevMsgNum )),
1130
1142
new (big.Int ).SetUint64 (uint64 (newMsgNum )),
1131
1143
)
1144
+ if err != nil {
1145
+ return nil , nil , fmt .Errorf ("failed to pack calldata: %w" , err )
1146
+ }
1147
+ // userData has blobHashes along with other calldata for EIP-4844 transactions
1148
+ userData , err = method .Inputs .Pack (
1149
+ seqNum ,
1150
+ new (big.Int ).SetUint64 (delayedMsg ),
1151
+ b .config ().gasRefunder ,
1152
+ new (big.Int ).SetUint64 (uint64 (prevMsgNum )),
1153
+ new (big.Int ).SetUint64 (uint64 (newMsgNum )),
1154
+ blobHashes ,
1155
+ )
1156
+ if err != nil {
1157
+ return nil , nil , fmt .Errorf ("failed to pack user data: %w" , err )
1158
+ }
1159
+ _ , err = b .getAttestationQuote (userData )
1160
+ if err != nil {
1161
+ return nil , nil , fmt .Errorf ("failed to get attestation quote: %w" , err )
1162
+ }
1132
1163
} else {
1133
1164
calldata , err = method .Inputs .Pack (
1134
1165
seqNum ,
@@ -1138,15 +1169,58 @@ func (b *BatchPoster) encodeAddBatch(
1138
1169
new (big.Int ).SetUint64 (uint64 (prevMsgNum )),
1139
1170
new (big.Int ).SetUint64 (uint64 (newMsgNum )),
1140
1171
)
1172
+
1173
+ if err != nil {
1174
+ return nil , nil , fmt .Errorf ("failed to pack calldata: %w" , err )
1175
+ }
1176
+
1177
+ _ , err = b .getAttestationQuote (calldata )
1178
+ if err != nil {
1179
+ return nil , nil , fmt .Errorf ("failed to get attestation quote: %w" , err )
1180
+ }
1141
1181
}
1142
- if err != nil {
1143
- return nil , nil , err
1144
- }
1182
+ // TODO: when contract is updated add attestationQuote to the calldata
1145
1183
fullCalldata := append ([]byte {}, method .ID ... )
1146
1184
fullCalldata = append (fullCalldata , calldata ... )
1147
1185
return fullCalldata , kzgBlobs , nil
1148
1186
}
1149
1187
1188
+ /**
1189
+ * This function generates the attestation quote for the user data.
1190
+ * The user data is hashed using keccak256 and then 32 bytes of padding is added to the hash.
1191
+ * The hash is then written to a file specified in the config. (For SGX: /dev/attestation/user_report_data)
1192
+ * The quote is then read from the file specified in the config. (For SGX: /dev/attestation/quote)
1193
+ */
1194
+ func (b * BatchPoster ) getAttestationQuote (userData []byte ) ([]byte , error ) {
1195
+ if (b .config ().UserDataAttestationFile == "" ) || (b .config ().QuoteFile == "" ) {
1196
+ return []byte {}, nil
1197
+ }
1198
+
1199
+ // keccak256 hash of userData
1200
+ userDataHash := crypto .Keccak256 (userData )
1201
+
1202
+ // Add 32 bytes of padding to the user data hash
1203
+ // because keccak256 hash is 32 bytes and sgx requires 64 bytes of user data
1204
+ for i := 0 ; i < 32 ; i += 1 {
1205
+ userDataHash = append (userDataHash , 0 )
1206
+ }
1207
+
1208
+ // Write the message to "/dev/attestation/user_report_data" in SGX
1209
+ err := os .WriteFile (b .config ().UserDataAttestationFile , userDataHash , 0600 )
1210
+ if err != nil {
1211
+ return []byte {}, fmt .Errorf ("failed to create user report data file: %w" , err )
1212
+ }
1213
+
1214
+ // Read the quote from "/dev/attestation/quote" in SGX
1215
+ attestationQuote , err := os .ReadFile (b .config ().QuoteFile )
1216
+ if err != nil {
1217
+ return []byte {}, fmt .Errorf ("failed to read quote file: %w" , err )
1218
+ }
1219
+
1220
+ log .Info ("Attestation quote generated" , "quote" , hex .EncodeToString (attestationQuote ))
1221
+ return attestationQuote , nil
1222
+ }
1223
+
1150
1224
var ErrNormalGasEstimationFailed = errors .New ("normal gas estimation failed" )
1151
1225
1152
1226
type estimateGasParams struct {
0 commit comments