Skip to content

Commit 8c92ada

Browse files
authored
Add attestation quote in batch poster (#306)
* Add attestation quote in batch poster * write file * update batch poster * use read file * update to userDataHash * reduce file permissions * nit
1 parent 4b77041 commit 8c92ada

File tree

2 files changed

+84
-10
lines changed

2 files changed

+84
-10
lines changed

arbnode/batch_poster.go

+83-9
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ import (
1313
"fmt"
1414
"math"
1515
"math/big"
16+
"os"
1617
"strings"
1718
"sync/atomic"
1819
"time"
1920

21+
"github.com/ethereum/go-ethereum/crypto"
22+
2023
"github.com/andybalholm/brotli"
2124
"github.com/spf13/pflag"
2225

@@ -182,13 +185,13 @@ type BatchPosterConfig struct {
182185
Dangerous BatchPosterDangerousConfig `koanf:"dangerous"`
183186
ReorgResistanceMargin time.Duration `koanf:"reorg-resistance-margin" reload:"hot"`
184187
CheckBatchCorrectness bool `koanf:"check-batch-correctness"`
185-
186-
gasRefunder common.Address
187-
l1BlockBound l1BlockBound
188-
188+
gasRefunder common.Address
189+
l1BlockBound l1BlockBound
189190
// 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"`
192195
}
193196

194197
func (c *BatchPosterConfig) Validate() error {
@@ -241,6 +244,8 @@ func BatchPosterConfigAddOptions(prefix string, f *pflag.FlagSet) {
241244
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")
242245
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\"")
243246
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")
244249
redislock.AddConfigOptions(prefix+".redis-lock", f)
245250
dataposter.DataPosterConfigAddOptions(prefix+".data-poster", f, dataposter.DefaultDataPosterConfig)
246251
genericconf.WalletConfigAddOptions(prefix+".parent-chain-wallet", f, DefaultBatchPosterConfig.ParentChainWallet.Pathname)
@@ -272,6 +277,8 @@ var DefaultBatchPosterConfig = BatchPosterConfig{
272277
GasEstimateBaseFeeMultipleBips: arbmath.OneInUBips * 3 / 2,
273278
ReorgResistanceMargin: 10 * time.Minute,
274279
CheckBatchCorrectness: true,
280+
UserDataAttestationFile: "",
281+
QuoteFile: "",
275282
}
276283

277284
var DefaultBatchPosterL1WalletConfig = genericconf.WalletConfig{
@@ -1116,11 +1123,16 @@ func (b *BatchPoster) encodeAddBatch(
11161123
var calldata []byte
11171124
var kzgBlobs []kzg4844.Blob
11181125
var err error
1126+
var userData []byte
11191127
if use4844 {
11201128
kzgBlobs, err = blobs.EncodeBlobs(l2MessageData)
11211129
if err != nil {
11221130
return nil, nil, fmt.Errorf("failed to encode blobs: %w", err)
11231131
}
1132+
_, blobHashes, err := blobs.ComputeCommitmentsAndHashes(kzgBlobs)
1133+
if err != nil {
1134+
return nil, nil, fmt.Errorf("failed to compute blob hashes: %w", err)
1135+
}
11241136
// EIP4844 transactions to the sequencer inbox will not use transaction calldata for L2 info.
11251137
calldata, err = method.Inputs.Pack(
11261138
seqNum,
@@ -1129,6 +1141,25 @@ func (b *BatchPoster) encodeAddBatch(
11291141
new(big.Int).SetUint64(uint64(prevMsgNum)),
11301142
new(big.Int).SetUint64(uint64(newMsgNum)),
11311143
)
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+
}
11321163
} else {
11331164
calldata, err = method.Inputs.Pack(
11341165
seqNum,
@@ -1138,15 +1169,58 @@ func (b *BatchPoster) encodeAddBatch(
11381169
new(big.Int).SetUint64(uint64(prevMsgNum)),
11391170
new(big.Int).SetUint64(uint64(newMsgNum)),
11401171
)
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+
}
11411181
}
1142-
if err != nil {
1143-
return nil, nil, err
1144-
}
1182+
// TODO: when contract is updated add attestationQuote to the calldata
11451183
fullCalldata := append([]byte{}, method.ID...)
11461184
fullCalldata = append(fullCalldata, calldata...)
11471185
return fullCalldata, kzgBlobs, nil
11481186
}
11491187

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+
11501224
var ErrNormalGasEstimationFailed = errors.New("normal gas estimation failed")
11511225

11521226
type estimateGasParams struct {

arbnode/transaction_streamer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ func (s *TransactionStreamer) SubmitEspressoTransactionPos(pos arbutil.MessageIn
14981498
if err != nil && dbutil.IsErrNotFound(err) {
14991499
// if the key doesn't exist, create a new array with the pos
15001500
pendingTxnsPos = []*arbutil.MessageIndex{&pos}
1501-
} else if pendingTxnsPos[len(pendingTxnsPos)-1] == &pos {
1501+
} else if len(pendingTxnsPos) > 0 && pendingTxnsPos[len(pendingTxnsPos)-1] == &pos {
15021502
return fmt.Errorf("Submitting the same position messages %v", pos)
15031503
} else {
15041504
pendingTxnsPos = append(pendingTxnsPos, &pos)

0 commit comments

Comments
 (0)