github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/rollup/client.go (about) 1 package rollup 2 3 import ( 4 "errors" 5 "fmt" 6 "math/big" 7 "strconv" 8 9 "github.com/ethereum-optimism/optimism/l2geth/common" 10 "github.com/ethereum-optimism/optimism/l2geth/common/hexutil" 11 "github.com/ethereum-optimism/optimism/l2geth/core/types" 12 "github.com/ethereum-optimism/optimism/l2geth/crypto" 13 "github.com/go-resty/resty/v2" 14 ) 15 16 // Constants that are used to compare against values in the deserialized JSON 17 // fetched by the RollupClient 18 const ( 19 sequencer = "sequencer" 20 l1 = "l1" 21 ) 22 23 // errElementNotFound represents the error case of the remote element not being 24 // found. It applies to transactions, queue elements and batches 25 var errElementNotFound = errors.New("element not found") 26 27 // errHttpError represents the error case of when the remote server 28 // returns a 400 or greater error 29 var errHTTPError = errors.New("http error") 30 31 // Batch represents the data structure that is submitted with 32 // a series of transactions to layer one 33 type Batch struct { 34 Index uint64 `json:"index"` 35 Root common.Hash `json:"root,omitempty"` 36 Size uint32 `json:"size,omitempty"` 37 PrevTotalElements uint32 `json:"prevTotalElements,omitempty"` 38 ExtraData hexutil.Bytes `json:"extraData,omitempty"` 39 BlockNumber uint64 `json:"blockNumber"` 40 Timestamp uint64 `json:"timestamp"` 41 Submitter common.Address `json:"submitter"` 42 } 43 44 // EthContext represents the L1 EVM context that is injected into 45 // the OVM at runtime. It is updated with each `enqueue` transaction 46 // and needs to be fetched from a remote server to be updated when 47 // too much time has passed between `enqueue` transactions. 48 type EthContext struct { 49 BlockNumber uint64 `json:"blockNumber"` 50 BlockHash common.Hash `json:"blockHash"` 51 Timestamp uint64 `json:"timestamp"` 52 } 53 54 // SyncStatus represents the state of the remote server. The SyncService 55 // does not want to begin syncing until the remote server has fully synced. 56 type SyncStatus struct { 57 Syncing bool `json:"syncing"` 58 HighestKnownTransactionIndex uint64 `json:"highestKnownTransactionIndex"` 59 CurrentTransactionIndex uint64 `json:"currentTransactionIndex"` 60 } 61 62 // L1GasPrice represents the gas price of L1. It is used as part of the gas 63 // estimatation logic. 64 type L1GasPrice struct { 65 GasPrice string `json:"gasPrice"` 66 } 67 68 // transaction represents the return result of the remote server. 69 // It either came from a batch or was replicated from the sequencer. 70 type transaction struct { 71 Index uint64 `json:"index"` 72 BatchIndex uint64 `json:"batchIndex"` 73 BlockNumber uint64 `json:"blockNumber"` 74 Timestamp uint64 `json:"timestamp"` 75 Value *hexutil.Big `json:"value"` 76 GasLimit uint64 `json:"gasLimit,string"` 77 Target common.Address `json:"target"` 78 Origin *common.Address `json:"origin"` 79 Data hexutil.Bytes `json:"data"` 80 QueueOrigin string `json:"queueOrigin"` 81 QueueIndex *uint64 `json:"queueIndex"` 82 Decoded *decoded `json:"decoded"` 83 } 84 85 // Enqueue represents an `enqueue` transaction or a L1 to L2 transaction. 86 type Enqueue struct { 87 Index *uint64 `json:"ctcIndex"` 88 Target *common.Address `json:"target"` 89 Data *hexutil.Bytes `json:"data"` 90 GasLimit *uint64 `json:"gasLimit,string"` 91 Origin *common.Address `json:"origin"` 92 BlockNumber *uint64 `json:"blockNumber"` 93 Timestamp *uint64 `json:"timestamp"` 94 QueueIndex *uint64 `json:"index"` 95 } 96 97 // signature represents a secp256k1 ECDSA signature 98 type signature struct { 99 R hexutil.Bytes `json:"r"` 100 S hexutil.Bytes `json:"s"` 101 V uint `json:"v"` 102 } 103 104 // decoded represents the decoded transaction from the batch. 105 // When this struct exists in other structs and is set to `nil`, 106 // it means that the decoding failed. 107 type decoded struct { 108 Signature signature `json:"sig"` 109 Value *hexutil.Big `json:"value"` 110 GasLimit uint64 `json:"gasLimit,string"` 111 GasPrice uint64 `json:"gasPrice,string"` 112 Nonce uint64 `json:"nonce,string"` 113 Target *common.Address `json:"target"` 114 Data hexutil.Bytes `json:"data"` 115 } 116 117 // RollupClient is able to query for information 118 // that is required by the SyncService 119 type RollupClient interface { 120 GetEnqueue(index uint64) (*types.Transaction, error) 121 GetLatestEnqueue() (*types.Transaction, error) 122 GetLatestEnqueueIndex() (*uint64, error) 123 GetRawTransaction(uint64, Backend) (*TransactionResponse, error) 124 GetTransaction(uint64, Backend) (*types.Transaction, error) 125 GetLatestTransaction(Backend) (*types.Transaction, error) 126 GetLatestTransactionIndex(Backend) (*uint64, error) 127 GetEthContext(uint64) (*EthContext, error) 128 GetLatestEthContext() (*EthContext, error) 129 GetLastConfirmedEnqueue() (*types.Transaction, error) 130 GetLatestTransactionBatch() (*Batch, []*types.Transaction, error) 131 GetLatestTransactionBatchIndex() (*uint64, error) 132 GetTransactionBatch(uint64) (*Batch, []*types.Transaction, error) 133 SyncStatus(Backend) (*SyncStatus, error) 134 } 135 136 // Client is an HTTP based RollupClient 137 type Client struct { 138 client *resty.Client 139 chainID *big.Int 140 } 141 142 // TransactionResponse represents the response from the remote server when 143 // querying transactions. 144 type TransactionResponse struct { 145 Transaction *transaction `json:"transaction"` 146 Batch *Batch `json:"batch"` 147 } 148 149 // TransactionBatchResponse represents the response from the remote server 150 // when querying batches. 151 type TransactionBatchResponse struct { 152 Batch *Batch `json:"batch"` 153 Transactions []*transaction `json:"transactions"` 154 } 155 156 // NewClient create a new Client given a remote HTTP url and a chain id 157 func NewClient(url string, chainID *big.Int) *Client { 158 client := resty.New() 159 client.SetHostURL(url) 160 client.SetHeader("User-Agent", "sequencer") 161 client.OnAfterResponse(func(c *resty.Client, r *resty.Response) error { 162 statusCode := r.StatusCode() 163 if statusCode >= 400 { 164 method := r.Request.Method 165 url := r.Request.URL 166 return fmt.Errorf("%d cannot %s %s: %w", statusCode, method, url, errHTTPError) 167 } 168 return nil 169 }) 170 171 return &Client{ 172 client: client, 173 chainID: chainID, 174 } 175 } 176 177 // GetEnqueue fetches an `enqueue` transaction by queue index 178 func (c *Client) GetEnqueue(index uint64) (*types.Transaction, error) { 179 str := strconv.FormatUint(index, 10) 180 response, err := c.client.R(). 181 SetPathParams(map[string]string{ 182 "index": str, 183 }). 184 SetResult(&Enqueue{}). 185 Get("/enqueue/index/{index}") 186 187 if err != nil { 188 return nil, fmt.Errorf("cannot fetch enqueue: %w", err) 189 } 190 enqueue, ok := response.Result().(*Enqueue) 191 if !ok { 192 return nil, fmt.Errorf("Cannot fetch enqueue %d", index) 193 } 194 if enqueue == nil { 195 return nil, fmt.Errorf("Cannot deserialize enqueue %d", index) 196 } 197 tx, err := enqueueToTransaction(enqueue) 198 if err != nil { 199 return nil, err 200 } 201 return tx, nil 202 } 203 204 // enqueueToTransaction turns an Enqueue into a types.Transaction 205 // so that it can be consumed by the SyncService 206 func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) { 207 if enqueue == nil { 208 return nil, errElementNotFound 209 } 210 // When the queue index is nil, is means that the enqueue'd transaction 211 // does not exist. 212 if enqueue.QueueIndex == nil { 213 return nil, errElementNotFound 214 } 215 // The queue index is the nonce 216 nonce := *enqueue.QueueIndex 217 218 if enqueue.Target == nil { 219 return nil, errors.New("Target not found for enqueue tx") 220 } 221 target := *enqueue.Target 222 223 if enqueue.GasLimit == nil { 224 return nil, errors.New("Gas limit not found for enqueue tx") 225 } 226 gasLimit := *enqueue.GasLimit 227 if enqueue.Origin == nil { 228 return nil, errors.New("Origin not found for enqueue tx") 229 } 230 origin := *enqueue.Origin 231 if enqueue.BlockNumber == nil { 232 return nil, errors.New("Blocknumber not found for enqueue tx") 233 } 234 blockNumber := new(big.Int).SetUint64(*enqueue.BlockNumber) 235 if enqueue.Timestamp == nil { 236 return nil, errors.New("Timestamp not found for enqueue tx") 237 } 238 timestamp := *enqueue.Timestamp 239 240 if enqueue.Data == nil { 241 return nil, errors.New("Data not found for enqueue tx") 242 } 243 data := *enqueue.Data 244 245 // enqueue transactions have no value 246 value := big.NewInt(0) 247 tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data) 248 249 // The index does not get a check as it is allowed to be nil in the context 250 // of an enqueue transaction that has yet to be included into the CTC 251 txMeta := types.NewTransactionMeta( 252 blockNumber, 253 timestamp, 254 &origin, 255 types.QueueOriginL1ToL2, 256 enqueue.Index, 257 enqueue.QueueIndex, 258 data, 259 ) 260 tx.SetTransactionMeta(txMeta) 261 262 return tx, nil 263 } 264 265 // GetLatestEnqueue fetches the latest `enqueue`, meaning the `enqueue` 266 // transaction with the greatest queue index. 267 func (c *Client) GetLatestEnqueue() (*types.Transaction, error) { 268 response, err := c.client.R(). 269 SetResult(&Enqueue{}). 270 Get("/enqueue/latest") 271 272 if err != nil { 273 return nil, fmt.Errorf("cannot fetch latest enqueue: %w", err) 274 } 275 enqueue, ok := response.Result().(*Enqueue) 276 if !ok { 277 return nil, errors.New("Cannot fetch latest enqueue") 278 } 279 tx, err := enqueueToTransaction(enqueue) 280 if err != nil { 281 return nil, fmt.Errorf("Cannot parse enqueue tx: %w", err) 282 } 283 return tx, nil 284 } 285 286 // GetLatestEnqueueIndex returns the latest `enqueue()` index 287 func (c *Client) GetLatestEnqueueIndex() (*uint64, error) { 288 tx, err := c.GetLatestEnqueue() 289 if err != nil { 290 return nil, err 291 } 292 index := tx.GetMeta().QueueIndex 293 if index == nil { 294 return nil, errors.New("Latest queue index is nil") 295 } 296 return index, nil 297 } 298 299 // GetLatestTransactionIndex returns the latest CTC index that has been batch 300 // submitted or not, depending on the backend 301 func (c *Client) GetLatestTransactionIndex(backend Backend) (*uint64, error) { 302 tx, err := c.GetLatestTransaction(backend) 303 if err != nil { 304 return nil, err 305 } 306 index := tx.GetMeta().Index 307 if index == nil { 308 return nil, errors.New("Latest index is nil") 309 } 310 return index, nil 311 } 312 313 // GetLatestTransactionBatchIndex returns the latest transaction batch index 314 func (c *Client) GetLatestTransactionBatchIndex() (*uint64, error) { 315 batch, _, err := c.GetLatestTransactionBatch() 316 if err != nil { 317 return nil, err 318 } 319 index := batch.Index 320 return &index, nil 321 } 322 323 // batchedTransactionToTransaction converts a transaction into a 324 // types.Transaction that can be consumed by the SyncService 325 func batchedTransactionToTransaction(res *transaction, chainID *big.Int) (*types.Transaction, error) { 326 // `nil` transactions are not found 327 if res == nil { 328 return nil, errElementNotFound 329 } 330 // The queue origin must be either sequencer of l1, otherwise 331 // it is considered an unknown queue origin and will not be processed 332 var queueOrigin types.QueueOrigin 333 switch res.QueueOrigin { 334 case sequencer: 335 queueOrigin = types.QueueOriginSequencer 336 case l1: 337 queueOrigin = types.QueueOriginL1ToL2 338 default: 339 return nil, fmt.Errorf("Unknown queue origin: %s", res.QueueOrigin) 340 } 341 // Transactions that have been decoded are 342 // Queue Origin Sequencer transactions 343 if res.Decoded != nil { 344 nonce := res.Decoded.Nonce 345 to := res.Decoded.Target 346 value := (*big.Int)(res.Decoded.Value) 347 // Note: there are two gas limits, one top level and 348 // another on the raw transaction itself. Maybe maxGasLimit 349 // for the top level? 350 gasLimit := res.Decoded.GasLimit 351 gasPrice := new(big.Int).SetUint64(res.Decoded.GasPrice) 352 data := res.Decoded.Data 353 354 var tx *types.Transaction 355 if to == nil { 356 tx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, data) 357 } else { 358 tx = types.NewTransaction(nonce, *to, value, gasLimit, gasPrice, data) 359 } 360 361 txMeta := types.NewTransactionMeta( 362 new(big.Int).SetUint64(res.BlockNumber), 363 res.Timestamp, 364 res.Origin, 365 queueOrigin, 366 &res.Index, 367 res.QueueIndex, 368 res.Data, 369 ) 370 tx.SetTransactionMeta(txMeta) 371 372 r, s := res.Decoded.Signature.R, res.Decoded.Signature.S 373 sig := make([]byte, crypto.SignatureLength) 374 copy(sig[32-len(r):32], r) 375 copy(sig[64-len(s):64], s) 376 377 var signer types.Signer 378 if res.Decoded.Signature.V == 27 || res.Decoded.Signature.V == 28 { 379 signer = types.HomesteadSigner{} 380 sig[64] = byte(res.Decoded.Signature.V - 27) 381 } else { 382 signer = types.NewEIP155Signer(chainID) 383 sig[64] = byte(res.Decoded.Signature.V) 384 } 385 386 tx, err := tx.WithSignature(signer, sig[:]) 387 if err != nil { 388 return nil, fmt.Errorf("Cannot add signature to transaction: %w", err) 389 } 390 391 return tx, nil 392 } 393 394 // The transaction is either an L1 to L2 transaction or it does not have a 395 // known deserialization 396 nonce := uint64(0) 397 if res.QueueOrigin == l1 { 398 if res.QueueIndex == nil { 399 return nil, errors.New("Queue origin L1 to L2 without a queue index") 400 } 401 nonce = *res.QueueIndex 402 } 403 target := res.Target 404 gasLimit := res.GasLimit 405 data := res.Data 406 origin := res.Origin 407 value := (*big.Int)(res.Value) 408 tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data) 409 txMeta := types.NewTransactionMeta( 410 new(big.Int).SetUint64(res.BlockNumber), 411 res.Timestamp, 412 origin, 413 queueOrigin, 414 &res.Index, 415 res.QueueIndex, 416 res.Data, 417 ) 418 tx.SetTransactionMeta(txMeta) 419 return tx, nil 420 } 421 422 // GetTransaction will get a transaction by Canonical Transaction Chain index 423 func (c *Client) GetRawTransaction(index uint64, backend Backend) (*TransactionResponse, error) { 424 str := strconv.FormatUint(index, 10) 425 response, err := c.client.R(). 426 SetPathParams(map[string]string{ 427 "index": str, 428 }). 429 SetQueryParams(map[string]string{ 430 "backend": backend.String(), 431 }). 432 SetResult(&TransactionResponse{}). 433 Get("/transaction/index/{index}") 434 435 if err != nil { 436 return nil, fmt.Errorf("cannot fetch transaction: %w", err) 437 } 438 res, ok := response.Result().(*TransactionResponse) 439 if !ok { 440 return nil, fmt.Errorf("could not get tx with index %d", index) 441 } 442 return res, nil 443 } 444 445 // GetTransaction will get a transaction by Canonical Transaction Chain index 446 func (c *Client) GetTransaction(index uint64, backend Backend) (*types.Transaction, error) { 447 res, err := c.GetRawTransaction(index, backend) 448 if err != nil { 449 return nil, err 450 } 451 return batchedTransactionToTransaction(res.Transaction, c.chainID) 452 } 453 454 // GetLatestTransaction will get the latest transaction, meaning the transaction 455 // with the greatest Canonical Transaction Chain index 456 func (c *Client) GetLatestTransaction(backend Backend) (*types.Transaction, error) { 457 response, err := c.client.R(). 458 SetResult(&TransactionResponse{}). 459 SetQueryParams(map[string]string{ 460 "backend": backend.String(), 461 }). 462 Get("/transaction/latest") 463 464 if err != nil { 465 return nil, fmt.Errorf("cannot fetch latest transactions: %w", err) 466 } 467 res, ok := response.Result().(*TransactionResponse) 468 if !ok { 469 return nil, errors.New("Cannot get latest transaction") 470 } 471 472 return batchedTransactionToTransaction(res.Transaction, c.chainID) 473 } 474 475 // GetEthContext will return the EthContext by block number 476 func (c *Client) GetEthContext(blockNumber uint64) (*EthContext, error) { 477 str := strconv.FormatUint(blockNumber, 10) 478 response, err := c.client.R(). 479 SetPathParams(map[string]string{ 480 "blocknumber": str, 481 }). 482 SetResult(&EthContext{}). 483 Get("/eth/context/blocknumber/{blocknumber}") 484 485 if err != nil { 486 return nil, err 487 } 488 489 context, ok := response.Result().(*EthContext) 490 if !ok { 491 return nil, errors.New("Cannot parse EthContext") 492 } 493 return context, nil 494 } 495 496 // GetLatestEthContext will return the latest EthContext 497 func (c *Client) GetLatestEthContext() (*EthContext, error) { 498 response, err := c.client.R(). 499 SetResult(&EthContext{}). 500 Get("/eth/context/latest") 501 502 if err != nil { 503 return nil, fmt.Errorf("Cannot fetch eth context: %w", err) 504 } 505 506 context, ok := response.Result().(*EthContext) 507 if !ok { 508 return nil, errors.New("Cannot parse EthContext") 509 } 510 511 return context, nil 512 } 513 514 // GetLastConfirmedEnqueue will get the last `enqueue` transaction that has been 515 // batched up 516 func (c *Client) GetLastConfirmedEnqueue() (*types.Transaction, error) { 517 enqueue, err := c.GetLatestEnqueue() 518 if err != nil { 519 return nil, fmt.Errorf("Cannot get latest enqueue: %w", err) 520 } 521 // This should only happen if there are no L1 to L2 transactions yet 522 if enqueue == nil { 523 return nil, errElementNotFound 524 } 525 // Work backwards looking for the first enqueue 526 // to have an index, which means it has been included 527 // in the canonical transaction chain. 528 for { 529 meta := enqueue.GetMeta() 530 // The enqueue has an index so it has been confirmed 531 if meta.Index != nil { 532 return enqueue, nil 533 } 534 // There is no queue index so this is a bug 535 if meta.QueueIndex == nil { 536 return nil, fmt.Errorf("queue index is nil") 537 } 538 // No enqueue transactions have been confirmed yet 539 if *meta.QueueIndex == uint64(0) { 540 return nil, errElementNotFound 541 } 542 next, err := c.GetEnqueue(*meta.QueueIndex - 1) 543 if err != nil { 544 return nil, fmt.Errorf("cannot get enqueue %d: %w", *meta.Index, err) 545 } 546 enqueue = next 547 } 548 } 549 550 // SyncStatus will query the remote server to determine if it is still syncing 551 func (c *Client) SyncStatus(backend Backend) (*SyncStatus, error) { 552 response, err := c.client.R(). 553 SetResult(&SyncStatus{}). 554 SetQueryParams(map[string]string{ 555 "backend": backend.String(), 556 }). 557 Get("/eth/syncing") 558 559 if err != nil { 560 return nil, fmt.Errorf("Cannot fetch sync status: %w", err) 561 } 562 563 status, ok := response.Result().(*SyncStatus) 564 if !ok { 565 return nil, fmt.Errorf("Cannot parse sync status") 566 } 567 568 return status, nil 569 } 570 571 // GetLatestTransactionBatch will return the latest transaction batch 572 func (c *Client) GetLatestTransactionBatch() (*Batch, []*types.Transaction, error) { 573 response, err := c.client.R(). 574 SetResult(&TransactionBatchResponse{}). 575 Get("/batch/transaction/latest") 576 577 if err != nil { 578 return nil, nil, errors.New("Cannot get latest transaction batch") 579 } 580 txBatch, ok := response.Result().(*TransactionBatchResponse) 581 if !ok { 582 return nil, nil, fmt.Errorf("Cannot parse transaction batch response") 583 } 584 return parseTransactionBatchResponse(txBatch, c.chainID) 585 } 586 587 // GetTransactionBatch will return the transaction batch by batch index 588 func (c *Client) GetTransactionBatch(index uint64) (*Batch, []*types.Transaction, error) { 589 str := strconv.FormatUint(index, 10) 590 response, err := c.client.R(). 591 SetResult(&TransactionBatchResponse{}). 592 SetPathParams(map[string]string{ 593 "index": str, 594 }). 595 Get("/batch/transaction/index/{index}") 596 597 if err != nil { 598 return nil, nil, fmt.Errorf("Cannot get transaction batch %d: %w", index, err) 599 } 600 txBatch, ok := response.Result().(*TransactionBatchResponse) 601 if !ok { 602 return nil, nil, fmt.Errorf("Cannot parse transaction batch response") 603 } 604 return parseTransactionBatchResponse(txBatch, c.chainID) 605 } 606 607 // parseTransactionBatchResponse will turn a TransactionBatchResponse into a 608 // Batch and its corresponding types.Transactions 609 func parseTransactionBatchResponse(txBatch *TransactionBatchResponse, chainID *big.Int) (*Batch, []*types.Transaction, error) { 610 if txBatch == nil || txBatch.Batch == nil { 611 return nil, nil, errElementNotFound 612 } 613 batch := txBatch.Batch 614 txs := make([]*types.Transaction, len(txBatch.Transactions)) 615 for i, tx := range txBatch.Transactions { 616 transaction, err := batchedTransactionToTransaction(tx, chainID) 617 if err != nil { 618 return nil, nil, fmt.Errorf("Cannot parse transaction batch: %w", err) 619 } 620 txs[i] = transaction 621 } 622 return batch, txs, nil 623 }