client.go 19.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package rollup

import (
	"errors"
	"fmt"
	"math/big"
	"strconv"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-resty/resty/v2"
)

16 17 18 19 20 21 22 23 24 25
// Constants that are used to compare against values in the deserialized JSON
// fetched by the RollupClient
const (
	sequencer = "sequencer"
	l1        = "l1"
)

// errElementNotFound represents the error case of the remote element not being
// found. It applies to transactions, queue elements and batches
var errElementNotFound = errors.New("element not found")
26

27 28 29 30
// errHttpError represents the error case of when the remote server
// returns a 400 or greater error
var errHTTPError = errors.New("http error")

31 32
// Batch represents the data structure that is submitted with
// a series of transactions to layer one
33 34 35 36 37 38 39 40 41 42 43
type Batch struct {
	Index             uint64         `json:"index"`
	Root              common.Hash    `json:"root,omitempty"`
	Size              uint32         `json:"size,omitempty"`
	PrevTotalElements uint32         `json:"prevTotalElements,omitempty"`
	ExtraData         hexutil.Bytes  `json:"extraData,omitempty"`
	BlockNumber       uint64         `json:"blockNumber"`
	Timestamp         uint64         `json:"timestamp"`
	Submitter         common.Address `json:"submitter"`
}

44 45 46 47
// EthContext represents the L1 EVM context that is injected into
// the OVM at runtime. It is updated with each `enqueue` transaction
// and needs to be fetched from a remote server to be updated when
// too much time has passed between `enqueue` transactions.
48 49 50 51 52 53
type EthContext struct {
	BlockNumber uint64      `json:"blockNumber"`
	BlockHash   common.Hash `json:"blockHash"`
	Timestamp   uint64      `json:"timestamp"`
}

54 55
// SyncStatus represents the state of the remote server. The SyncService
// does not want to begin syncing until the remote server has fully synced.
56 57 58 59 60 61
type SyncStatus struct {
	Syncing                      bool   `json:"syncing"`
	HighestKnownTransactionIndex uint64 `json:"highestKnownTransactionIndex"`
	CurrentTransactionIndex      uint64 `json:"currentTransactionIndex"`
}

62 63
// L1GasPrice represents the gas price of L1. It is used as part of the gas
// estimatation logic.
64 65 66 67
type L1GasPrice struct {
	GasPrice string `json:"gasPrice"`
}

68 69
// transaction represents the return result of the remote server.
// It either came from a batch or was replicated from the sequencer.
70 71 72 73 74
type transaction struct {
	Index       uint64          `json:"index"`
	BatchIndex  uint64          `json:"batchIndex"`
	BlockNumber uint64          `json:"blockNumber"`
	Timestamp   uint64          `json:"timestamp"`
75
	Value       *hexutil.Big    `json:"value"`
76
	GasLimit    uint64          `json:"gasLimit,string"`
77 78 79 80 81 82 83 84
	Target      common.Address  `json:"target"`
	Origin      *common.Address `json:"origin"`
	Data        hexutil.Bytes   `json:"data"`
	QueueOrigin string          `json:"queueOrigin"`
	QueueIndex  *uint64         `json:"queueIndex"`
	Decoded     *decoded        `json:"decoded"`
}

85
// Enqueue represents an `enqueue` transaction or a L1 to L2 transaction.
86 87 88 89
type Enqueue struct {
	Index       *uint64         `json:"ctcIndex"`
	Target      *common.Address `json:"target"`
	Data        *hexutil.Bytes  `json:"data"`
90
	GasLimit    *uint64         `json:"gasLimit,string"`
91 92 93 94 95 96
	Origin      *common.Address `json:"origin"`
	BlockNumber *uint64         `json:"blockNumber"`
	Timestamp   *uint64         `json:"timestamp"`
	QueueIndex  *uint64         `json:"index"`
}

97
// signature represents a secp256k1 ECDSA signature
98 99 100 101 102 103
type signature struct {
	R hexutil.Bytes `json:"r"`
	S hexutil.Bytes `json:"s"`
	V uint          `json:"v"`
}

104 105 106
// decoded represents the decoded transaction from the batch.
// When this struct exists in other structs and is set to `nil`,
// 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 112
	GasPrice  uint64          `json:"gasPrice,string"`
	Nonce     uint64          `json:"nonce,string"`
113 114
	Target    *common.Address `json:"target"`
	Data      hexutil.Bytes   `json:"data"`
115 116
}

117 118
// RollupClient is able to query for information
// that is required by the SyncService
119 120 121
type RollupClient interface {
	GetEnqueue(index uint64) (*types.Transaction, error)
	GetLatestEnqueue() (*types.Transaction, error)
122 123 124 125
	GetLatestEnqueueIndex() (*uint64, error)
	GetTransaction(uint64, Backend) (*types.Transaction, error)
	GetLatestTransaction(Backend) (*types.Transaction, error)
	GetLatestTransactionIndex(Backend) (*uint64, error)
126
	GetEthContext(uint64) (*EthContext, error)
127 128
	GetLatestEthContext() (*EthContext, error)
	GetLastConfirmedEnqueue() (*types.Transaction, error)
129
	GetLatestTransactionBatch() (*Batch, []*types.Transaction, error)
130
	GetLatestTransactionBatchIndex() (*uint64, error)
131
	GetTransactionBatch(uint64) (*Batch, []*types.Transaction, error)
132
	SyncStatus(Backend) (*SyncStatus, error)
133
	GetL1GasPrice() (*big.Int, error)
134 135
}

136
// Client is an HTTP based RollupClient
137 138
type Client struct {
	client *resty.Client
139
	signer *types.EIP155Signer
140 141
}

142 143
// TransactionResponse represents the response from the remote server when
// querying transactions.
144 145 146 147 148
type TransactionResponse struct {
	Transaction *transaction `json:"transaction"`
	Batch       *Batch       `json:"batch"`
}

149 150 151 152 153 154 155 156
// TransactionBatchResponse represents the response from the remote server
// when querying batches.
type TransactionBatchResponse struct {
	Batch        *Batch         `json:"batch"`
	Transactions []*transaction `json:"transactions"`
}

// NewClient create a new Client given a remote HTTP url and a chain id
157 158 159
func NewClient(url string, chainID *big.Int) *Client {
	client := resty.New()
	client.SetHostURL(url)
160
	client.SetHeader("User-Agent", "sequencer")
161 162 163 164 165 166 167 168 169
	client.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
		statusCode := r.StatusCode()
		if statusCode >= 400 {
			method := r.Request.Method
			url := r.Request.URL
			return fmt.Errorf("%d cannot %s %s: %w", statusCode, method, url, errHTTPError)
		}
		return nil
	})
170
	signer := types.NewEIP155Signer(chainID)
171 172 173 174 175 176 177

	return &Client{
		client: client,
		signer: &signer,
	}
}

178
// GetEnqueue fetches an `enqueue` transaction by queue index
179 180 181 182 183 184 185 186 187 188
func (c *Client) GetEnqueue(index uint64) (*types.Transaction, error) {
	str := strconv.FormatUint(index, 10)
	response, err := c.client.R().
		SetPathParams(map[string]string{
			"index": str,
		}).
		SetResult(&Enqueue{}).
		Get("/enqueue/index/{index}")

	if err != nil {
189
		return nil, fmt.Errorf("cannot fetch enqueue: %w", err)
190 191 192 193 194 195 196 197 198 199
	}
	enqueue, ok := response.Result().(*Enqueue)
	if !ok {
		return nil, fmt.Errorf("Cannot fetch enqueue %d", index)
	}
	if enqueue == nil {
		return nil, fmt.Errorf("Cannot deserialize enqueue %d", index)
	}
	tx, err := enqueueToTransaction(enqueue)
	if err != nil {
200
		return nil, err
201 202 203 204
	}
	return tx, nil
}

205 206
// enqueueToTransaction turns an Enqueue into a types.Transaction
// so that it can be consumed by the SyncService
207
func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) {
208 209 210
	if enqueue == nil {
		return nil, errElementNotFound
	}
211 212 213
	// When the queue index is nil, is means that the enqueue'd transaction
	// does not exist.
	if enqueue.QueueIndex == nil {
214
		return nil, errElementNotFound
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	}
	// The queue index is the nonce
	nonce := *enqueue.QueueIndex

	if enqueue.Target == nil {
		return nil, errors.New("Target not found for enqueue tx")
	}
	target := *enqueue.Target

	if enqueue.GasLimit == nil {
		return nil, errors.New("Gas limit not found for enqueue tx")
	}
	gasLimit := *enqueue.GasLimit
	if enqueue.Origin == nil {
		return nil, errors.New("Origin not found for enqueue tx")
	}
	origin := *enqueue.Origin
	if enqueue.BlockNumber == nil {
		return nil, errors.New("Blocknumber not found for enqueue tx")
	}
	blockNumber := new(big.Int).SetUint64(*enqueue.BlockNumber)
	if enqueue.Timestamp == nil {
		return nil, errors.New("Timestamp not found for enqueue tx")
	}
	timestamp := *enqueue.Timestamp

	if enqueue.Data == nil {
		return nil, errors.New("Data not found for enqueue tx")
	}
	data := *enqueue.Data

246
	// enqueue transactions have no value
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	value := big.NewInt(0)
	tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data)

	// The index does not get a check as it is allowed to be nil in the context
	// of an enqueue transaction that has yet to be included into the CTC
	txMeta := types.NewTransactionMeta(
		blockNumber,
		timestamp,
		&origin,
		types.QueueOriginL1ToL2,
		enqueue.Index,
		enqueue.QueueIndex,
		data,
	)
	tx.SetTransactionMeta(txMeta)

	return tx, nil
}

266 267
// GetLatestEnqueue fetches the latest `enqueue`, meaning the `enqueue`
// transaction with the greatest queue index.
268 269 270 271 272 273
func (c *Client) GetLatestEnqueue() (*types.Transaction, error) {
	response, err := c.client.R().
		SetResult(&Enqueue{}).
		Get("/enqueue/latest")

	if err != nil {
274
		return nil, fmt.Errorf("cannot fetch latest enqueue: %w", err)
275 276 277 278 279 280 281
	}
	enqueue, ok := response.Result().(*Enqueue)
	if !ok {
		return nil, errors.New("Cannot fetch latest enqueue")
	}
	tx, err := enqueueToTransaction(enqueue)
	if err != nil {
282
		return nil, fmt.Errorf("Cannot parse enqueue tx: %w", err)
283 284 285 286
	}
	return tx, nil
}

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
// GetLatestEnqueueIndex returns the latest `enqueue()` index
func (c *Client) GetLatestEnqueueIndex() (*uint64, error) {
	tx, err := c.GetLatestEnqueue()
	if err != nil {
		return nil, err
	}
	index := tx.GetMeta().QueueIndex
	if index == nil {
		return nil, errors.New("Latest queue index is nil")
	}
	return index, nil
}

// GetLatestTransactionIndex returns the latest CTC index that has been batch
// submitted or not, depending on the backend
func (c *Client) GetLatestTransactionIndex(backend Backend) (*uint64, error) {
	tx, err := c.GetLatestTransaction(backend)
	if err != nil {
		return nil, err
	}
	index := tx.GetMeta().Index
	if index == nil {
		return nil, errors.New("Latest index is nil")
	}
	return index, nil
}

// GetLatestTransactionBatchIndex returns the latest transaction batch index
func (c *Client) GetLatestTransactionBatchIndex() (*uint64, error) {
	batch, _, err := c.GetLatestTransactionBatch()
	if err != nil {
		return nil, err
	}
	index := batch.Index
	return &index, nil
}

324 325
// batchedTransactionToTransaction converts a transaction into a
// types.Transaction that can be consumed by the SyncService
326
func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signer) (*types.Transaction, error) {
327
	// `nil` transactions are not found
328 329
	if res == nil {
		return nil, errElementNotFound
330 331 332 333
	}
	// The queue origin must be either sequencer of l1, otherwise
	// it is considered an unknown queue origin and will not be processed
	var queueOrigin types.QueueOrigin
334 335
	switch res.QueueOrigin {
	case sequencer:
336
		queueOrigin = types.QueueOriginSequencer
337
	case l1:
338
		queueOrigin = types.QueueOriginL1ToL2
339
	default:
340
		return nil, fmt.Errorf("Unknown queue origin: %s", res.QueueOrigin)
341 342 343
	}
	// Transactions that have been decoded are
	// Queue Origin Sequencer transactions
344 345 346
	if res.Decoded != nil {
		nonce := res.Decoded.Nonce
		to := res.Decoded.Target
347
		value := (*big.Int)(res.Decoded.Value)
348 349 350
		// Note: there are two gas limits, one top level and
		// another on the raw transaction itself. Maybe maxGasLimit
		// for the top level?
351 352 353
		gasLimit := res.Decoded.GasLimit
		gasPrice := new(big.Int).SetUint64(res.Decoded.GasPrice)
		data := res.Decoded.Data
354 355

		var tx *types.Transaction
356
		if to == nil {
357 358
			tx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, data)
		} else {
359
			tx = types.NewTransaction(nonce, *to, value, gasLimit, gasPrice, data)
360 361 362
		}

		txMeta := types.NewTransactionMeta(
363 364 365
			new(big.Int).SetUint64(res.BlockNumber),
			res.Timestamp,
			res.Origin,
366
			queueOrigin,
367 368 369
			&res.Index,
			res.QueueIndex,
			res.Data,
370 371 372
		)
		tx.SetTransactionMeta(txMeta)

373
		r, s := res.Decoded.Signature.R, res.Decoded.Signature.S
374 375 376
		sig := make([]byte, crypto.SignatureLength)
		copy(sig[32-len(r):32], r)
		copy(sig[64-len(s):64], s)
377
		sig[64] = byte(res.Decoded.Signature.V)
378 379 380 381 382 383 384 385 386 387 388 389

		tx, err := tx.WithSignature(signer, sig[:])
		if err != nil {
			return nil, fmt.Errorf("Cannot add signature to transaction: %w", err)
		}

		return tx, nil
	}

	// The transaction is  either an L1 to L2 transaction or it does not have a
	// known deserialization
	nonce := uint64(0)
390 391
	if res.QueueOrigin == l1 {
		if res.QueueIndex == nil {
392 393
			return nil, errors.New("Queue origin L1 to L2 without a queue index")
		}
394
		nonce = *res.QueueIndex
395
	}
396 397 398 399
	target := res.Target
	gasLimit := res.GasLimit
	data := res.Data
	origin := res.Origin
400
	value := (*big.Int)(res.Value)
401
	tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data)
402
	txMeta := types.NewTransactionMeta(
403 404
		new(big.Int).SetUint64(res.BlockNumber),
		res.Timestamp,
405 406
		origin,
		queueOrigin,
407 408 409
		&res.Index,
		res.QueueIndex,
		res.Data,
410 411 412 413 414
	)
	tx.SetTransactionMeta(txMeta)
	return tx, nil
}

415
// GetTransaction will get a transaction by Canonical Transaction Chain index
416
func (c *Client) GetTransaction(index uint64, backend Backend) (*types.Transaction, error) {
417 418 419 420 421
	str := strconv.FormatUint(index, 10)
	response, err := c.client.R().
		SetPathParams(map[string]string{
			"index": str,
		}).
422 423 424
		SetQueryParams(map[string]string{
			"backend": backend.String(),
		}).
425 426 427 428
		SetResult(&TransactionResponse{}).
		Get("/transaction/index/{index}")

	if err != nil {
429
		return nil, fmt.Errorf("cannot fetch transaction: %w", err)
430 431 432 433 434
	}
	res, ok := response.Result().(*TransactionResponse)
	if !ok {
		return nil, fmt.Errorf("could not get tx with index %d", index)
	}
435
	return batchedTransactionToTransaction(res.Transaction, c.signer)
436 437
}

438 439
// GetLatestTransaction will get the latest transaction, meaning the transaction
// with the greatest Canonical Transaction Chain index
440
func (c *Client) GetLatestTransaction(backend Backend) (*types.Transaction, error) {
441 442
	response, err := c.client.R().
		SetResult(&TransactionResponse{}).
443 444 445
		SetQueryParams(map[string]string{
			"backend": backend.String(),
		}).
446 447 448
		Get("/transaction/latest")

	if err != nil {
449
		return nil, fmt.Errorf("cannot fetch latest transactions: %w", err)
450 451 452
	}
	res, ok := response.Result().(*TransactionResponse)
	if !ok {
453
		return nil, errors.New("Cannot get latest transaction")
454 455
	}

456
	return batchedTransactionToTransaction(res.Transaction, c.signer)
457 458
}

459
// GetEthContext will return the EthContext by block number
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
func (c *Client) GetEthContext(blockNumber uint64) (*EthContext, error) {
	str := strconv.FormatUint(blockNumber, 10)
	response, err := c.client.R().
		SetPathParams(map[string]string{
			"blocknumber": str,
		}).
		SetResult(&EthContext{}).
		Get("/eth/context/blocknumber/{blocknumber}")

	if err != nil {
		return nil, err
	}

	context, ok := response.Result().(*EthContext)
	if !ok {
		return nil, errors.New("Cannot parse EthContext")
	}
	return context, nil
}

480
// GetLatestEthContext will return the latest EthContext
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
func (c *Client) GetLatestEthContext() (*EthContext, error) {
	response, err := c.client.R().
		SetResult(&EthContext{}).
		Get("/eth/context/latest")

	if err != nil {
		return nil, fmt.Errorf("Cannot fetch eth context: %w", err)
	}

	context, ok := response.Result().(*EthContext)
	if !ok {
		return nil, errors.New("Cannot parse EthContext")
	}

	return context, nil
}

498 499
// GetLastConfirmedEnqueue will get the last `enqueue` transaction that has been
// batched up
500 501 502 503 504
func (c *Client) GetLastConfirmedEnqueue() (*types.Transaction, error) {
	enqueue, err := c.GetLatestEnqueue()
	if err != nil {
		return nil, fmt.Errorf("Cannot get latest enqueue: %w", err)
	}
505
	// This should only happen if there are no L1 to L2 transactions yet
506
	if enqueue == nil {
507
		return nil, errElementNotFound
508 509 510 511 512 513
	}
	// Work backwards looking for the first enqueue
	// to have an index, which means it has been included
	// in the canonical transaction chain.
	for {
		meta := enqueue.GetMeta()
514
		// The enqueue has an index so it has been confirmed
515 516 517
		if meta.Index != nil {
			return enqueue, nil
		}
518
		// There is no queue index so this is a bug
519 520 521
		if meta.QueueIndex == nil {
			return nil, fmt.Errorf("queue index is nil")
		}
522
		// No enqueue transactions have been confirmed yet
523
		if *meta.QueueIndex == uint64(0) {
524
			return nil, errElementNotFound
525 526 527 528 529 530 531 532 533
		}
		next, err := c.GetEnqueue(*meta.QueueIndex - 1)
		if err != nil {
			return nil, fmt.Errorf("cannot get enqueue %d: %w", *meta.Index, err)
		}
		enqueue = next
	}
}

534
// SyncStatus will query the remote server to determine if it is still syncing
535
func (c *Client) SyncStatus(backend Backend) (*SyncStatus, error) {
536 537
	response, err := c.client.R().
		SetResult(&SyncStatus{}).
538 539 540
		SetQueryParams(map[string]string{
			"backend": backend.String(),
		}).
541 542 543 544 545 546 547 548 549 550 551 552 553
		Get("/eth/syncing")

	if err != nil {
		return nil, fmt.Errorf("Cannot fetch sync status: %w", err)
	}

	status, ok := response.Result().(*SyncStatus)
	if !ok {
		return nil, fmt.Errorf("Cannot parse sync status")
	}

	return status, nil
}
554

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
// GetLatestTransactionBatch will return the latest transaction batch
func (c *Client) GetLatestTransactionBatch() (*Batch, []*types.Transaction, error) {
	response, err := c.client.R().
		SetResult(&TransactionBatchResponse{}).
		Get("/batch/transaction/latest")

	if err != nil {
		return nil, nil, errors.New("Cannot get latest transaction batch")
	}
	txBatch, ok := response.Result().(*TransactionBatchResponse)
	if !ok {
		return nil, nil, fmt.Errorf("Cannot parse transaction batch response")
	}
	return parseTransactionBatchResponse(txBatch, c.signer)
}

// GetTransactionBatch will return the transaction batch by batch index
func (c *Client) GetTransactionBatch(index uint64) (*Batch, []*types.Transaction, error) {
	str := strconv.FormatUint(index, 10)
	response, err := c.client.R().
		SetResult(&TransactionBatchResponse{}).
		SetPathParams(map[string]string{
			"index": str,
		}).
		Get("/batch/transaction/index/{index}")

	if err != nil {
Mark Tyneway's avatar
Mark Tyneway committed
582
		return nil, nil, fmt.Errorf("Cannot get transaction batch %d: %w", index, err)
583 584 585 586 587 588 589 590 591 592
	}
	txBatch, ok := response.Result().(*TransactionBatchResponse)
	if !ok {
		return nil, nil, fmt.Errorf("Cannot parse transaction batch response")
	}
	return parseTransactionBatchResponse(txBatch, c.signer)
}

// parseTransactionBatchResponse will turn a TransactionBatchResponse into a
// Batch and its corresponding types.Transactions
593
func parseTransactionBatchResponse(txBatch *TransactionBatchResponse, signer *types.EIP155Signer) (*Batch, []*types.Transaction, error) {
594 595
	if txBatch == nil || txBatch.Batch == nil {
		return nil, nil, errElementNotFound
596 597 598 599 600 601 602 603 604 605 606 607 608 609
	}
	batch := txBatch.Batch
	txs := make([]*types.Transaction, len(txBatch.Transactions))
	for i, tx := range txBatch.Transactions {
		transaction, err := batchedTransactionToTransaction(tx, signer)
		if err != nil {
			return nil, nil, fmt.Errorf("Cannot parse transaction batch: %w", err)
		}
		txs[i] = transaction
	}
	return batch, txs, nil
}

// GetL1GasPrice will return the current gas price on L1
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
func (c *Client) GetL1GasPrice() (*big.Int, error) {
	response, err := c.client.R().
		SetResult(&L1GasPrice{}).
		Get("/eth/gasprice")

	if err != nil {
		return nil, fmt.Errorf("Cannot fetch L1 gas price: %w", err)
	}

	gasPriceResp, ok := response.Result().(*L1GasPrice)
	if !ok {
		return nil, fmt.Errorf("Cannot parse L1 gas price response")
	}

	gasPrice, ok := new(big.Int).SetString(gasPriceResp.GasPrice, 10)
	if !ok {
		return nil, fmt.Errorf("Cannot parse response as big number")
	}

	return gasPrice, nil
}