Skip to content

Commit

Permalink
feat: refactoring and mint tests
Browse files Browse the repository at this point in the history
  • Loading branch information
refcell committed Jan 30, 2023
1 parent 6af0257 commit c113fb9
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 201 deletions.
38 changes: 38 additions & 0 deletions configs/optimism/goerli-basic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"network": {
"blockchain": "Optimism",
"network": "Goerli",
"sub_network_identifier": null
},
"online_url": "http://localhost:8080",
"data_directory": "",
"http_timeout": 300,
"max_retries": 100,
"max_online_connections": 500,
"force_retry": true,
"max_sync_concurrency": 64,
"tip_delay": 120,
"max_reorg_depth": 64,
"log_configuration": false,
"compression_disabled": true,
"l0_in_memory_enabled": true,
"all_in_memory_enabled": true,
"table_size": 1,
"value_log_file_size": 1024,
"construction": null,
"data": {
"start_index": 4307133,
"reconciliation_disabled": true,
"inactive_discrepancy_search_disabled": true,
"balance_tracking_disabled": true,
"initial_balance_fetch_disabled":true,
"active_reconciliation_concurrency": 32,
"bootstrap_balances": "",
"log_balance_changes": true,
"log_transactions": true,
"log_blocks": true,
"end_conditions": {
"tip": true
}
}
}
8 changes: 4 additions & 4 deletions configs/optimism/goerli.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
"construction": null,
"data": {
"start_index": 4307133,
"reconciliation_disabled": true,
"inactive_discrepancy_search_disabled": true,
"balance_tracking_disabled": true,
"initial_balance_fetch_disabled":true,
"reconciliation_disabled": false,
"inactive_discrepancy_search_disabled": false,
"balance_tracking_disabled": false,
"initial_balance_fetch_disabled": false,
"active_reconciliation_concurrency": 32,
"bootstrap_balances": "",
"log_balance_changes": true,
Expand Down
194 changes: 0 additions & 194 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
@@ -1,212 +1,18 @@
package client

import (
"context"
"fmt"
"math/big"
"strings"

"github.com/coinbase/rosetta-geth-sdk/configuration"
"github.com/mdehoog/op-rosetta/pkg/handlers"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"

evmClient "github.com/coinbase/rosetta-geth-sdk/client"
"github.com/coinbase/rosetta-geth-sdk/services"
sdkTypes "github.com/coinbase/rosetta-geth-sdk/types"
RosettaTypes "github.com/coinbase/rosetta-sdk-go/types"
EthTypes "github.com/ethereum/go-ethereum/core/types"
)

// OpClient wraps the [evmClient.SDKClient] to add Optimism-specific functionality.
type OpClient struct {
*evmClient.SDKClient
}

func (c *OpClient) ParseOps(
tx *evmClient.LoadedTransaction,
) ([]*RosettaTypes.Operation, error) {
var ops []*RosettaTypes.Operation

if tx.Receipt.Type == L1ToL2DepositType && len(tx.Trace) > 0 && tx.Transaction.IsSystemTx() {
trace := tx.Trace[0]
traceType := strings.ToUpper(trace.Type)
opStatus := sdkTypes.SuccessStatus
from := evmClient.MustChecksum(trace.From.String())
to := evmClient.MustChecksum(trace.To.String())
metadata := map[string]interface{}{}

if from != to {
feeOps, err := handlers.FeeOps(tx)
if err != nil {
return nil, err
}
ops = append(ops, feeOps...)
}

toOp := &RosettaTypes.Operation{
OperationIdentifier: &RosettaTypes.OperationIdentifier{
Index: int64(len(ops) + 0),
},
Type: traceType,
Status: RosettaTypes.String(opStatus),
Account: &RosettaTypes.AccountIdentifier{
Address: to,
},
Amount: &RosettaTypes.Amount{
Value: trace.Value.String(),
Currency: sdkTypes.Currency,
},
Metadata: metadata,
}
ops = append(ops, toOp)
return ops, nil
}

feeOps, err := handlers.FeeOps(tx)
if err != nil {
return nil, err
}
ops = append(ops, feeOps...)

ops = append(ops, handlers.MintOps(tx, len(ops))...)
// ops = append(ops, handlers.BurnOps(tx, len(ops))...)
traceOps := services.TraceOps(tx.Trace, len(ops))
ops = append(ops, traceOps...)

return ops, nil
}

func (c *OpClient) GetBlockReceipts(
ctx context.Context,
blockHash common.Hash,
txs []evmClient.RPCTransaction,
baseFee *big.Int,
) ([]*evmClient.RosettaTxReceipt, error) {
receipts := make([]*evmClient.RosettaTxReceipt, len(txs))
if len(txs) == 0 {
return receipts, nil
}

ethReceipts := make([]*EthTypes.Receipt, len(txs))
reqs := make([]rpc.BatchElem, len(txs))
for i := range reqs {
reqs[i] = rpc.BatchElem{
Method: "eth_getTransactionReceipt",
Args: []interface{}{txs[i].TxExtraInfo.TxHash.String()},
Result: &ethReceipts[i],
}
}

maxBatchSize := 25
for i := 0; i < len(txs); i += maxBatchSize {
if i+maxBatchSize < len(txs) {
if err := c.BatchCallContext(ctx, reqs[i:i+maxBatchSize]); err != nil {
return nil, err
}
} else {
if err := c.BatchCallContext(ctx, reqs[i:]); err != nil {
return nil, err
}
}
}

for i := range reqs {
if reqs[i].Error != nil {
return nil, reqs[i].Error
}

gasPrice, err := evmClient.EffectiveGasPrice(txs[i].Tx, baseFee)
if err != nil {
return nil, err
}
gasUsed := new(big.Int).SetUint64(ethReceipts[i].GasUsed)
feeAmount := new(big.Int).Mul(gasUsed, gasPrice)
if ethReceipts[i].L1Fee != nil {
feeAmount.Add(feeAmount, ethReceipts[i].L1Fee)
}

receiptJSON, err := ethReceipts[i].MarshalJSON()
if err != nil {
return nil, fmt.Errorf("unable to marshal receipt for %x: %v", txs[i].Tx.Hash().Hex(), err)
}
receipt := &evmClient.RosettaTxReceipt{
Type: ethReceipts[i].Type,
GasPrice: gasPrice,
GasUsed: gasUsed,
Logs: ethReceipts[i].Logs,
// This is a hack to get around the fact that the RosettaTxReceipt doesn't contain L1 fees. We add the raw receipt here so we can access other rollup fields later
RawMessage: receiptJSON,
TransactionFee: feeAmount,
}

receipts[i] = receipt

if ethReceipts[i] == nil {
return nil, fmt.Errorf("got empty receipt for %x", txs[i].Tx.Hash().Hex())
}

if ethReceipts[i].BlockHash != blockHash {
return nil, fmt.Errorf(
"%w: expected block hash %s for Transaction but got %s",
sdkTypes.ErrClientBlockOrphaned,
blockHash.Hex(),
ethReceipts[i].BlockHash.Hex(),
)
}
}

return receipts, nil
}

func (c *OpClient) GetTransactionReceipt(
ctx context.Context,
tx *evmClient.LoadedTransaction,
) (*evmClient.RosettaTxReceipt, error) {
var r *EthTypes.Receipt
err := c.CallContext(ctx, &r, "eth_getTransactionReceipt", tx.TxHash)
if err == nil {
if r == nil {
return nil, ethereum.NotFound
}
}
gasPrice, err := evmClient.EffectiveGasPrice(tx.Transaction, tx.BaseFee)
if err != nil {
return nil, err
}
gasUsed := new(big.Int).SetUint64(r.GasUsed)
feeAmount := new(big.Int).Mul(gasUsed, gasPrice)
if r.L1Fee != nil {
feeAmount.Add(feeAmount, r.L1Fee)
}

return &evmClient.RosettaTxReceipt{
GasPrice: gasPrice,
GasUsed: gasUsed,
Logs: r.Logs,
RawMessage: nil,
TransactionFee: feeAmount,
}, err
}

// GetNativeTransferGasLimit is Ethereum's custom implementation of estimating gas.
func (c *OpClient) GetNativeTransferGasLimit(ctx context.Context, toAddress string,
fromAddress string, value *big.Int) (uint64, error) {
if len(toAddress) == 0 || value == nil {
// We guard against malformed inputs that may have been generated using
// a previous version of asset's rosetta
return 21000, nil
}
to := common.HexToAddress(toAddress)
return c.EstimateGas(ctx, ethereum.CallMsg{
From: common.HexToAddress(fromAddress),
To: &to,
Value: value,
})
}

// NewOpClient creates a client that can interact with the Optimism network.
func NewOpClient(cfg *configuration.Configuration) (*OpClient, error) {
client, err := evmClient.NewClient(cfg, nil)
Expand Down
96 changes: 96 additions & 0 deletions pkg/client/client_blocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package client

import (
"context"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"

evmClient "github.com/coinbase/rosetta-geth-sdk/client"
sdkTypes "github.com/coinbase/rosetta-geth-sdk/types"
EthTypes "github.com/ethereum/go-ethereum/core/types"
)

func (c *OpClient) GetBlockReceipts(
ctx context.Context,
blockHash common.Hash,
txs []evmClient.RPCTransaction,
baseFee *big.Int,
) ([]*evmClient.RosettaTxReceipt, error) {
receipts := make([]*evmClient.RosettaTxReceipt, len(txs))
if len(txs) == 0 {
return receipts, nil
}

ethReceipts := make([]*EthTypes.Receipt, len(txs))
reqs := make([]rpc.BatchElem, len(txs))
for i := range reqs {
reqs[i] = rpc.BatchElem{
Method: "eth_getTransactionReceipt",
Args: []interface{}{txs[i].TxExtraInfo.TxHash.String()},
Result: &ethReceipts[i],
}
}

maxBatchSize := 25
for i := 0; i < len(txs); i += maxBatchSize {
if i+maxBatchSize < len(txs) {
if err := c.BatchCallContext(ctx, reqs[i:i+maxBatchSize]); err != nil {
return nil, err
}
} else {
if err := c.BatchCallContext(ctx, reqs[i:]); err != nil {
return nil, err
}
}
}

for i := range reqs {
if reqs[i].Error != nil {
return nil, reqs[i].Error
}

gasPrice, err := evmClient.EffectiveGasPrice(txs[i].Tx, baseFee)
if err != nil {
return nil, err
}
gasUsed := new(big.Int).SetUint64(ethReceipts[i].GasUsed)
feeAmount := new(big.Int).Mul(gasUsed, gasPrice)
if ethReceipts[i].L1Fee != nil {
feeAmount.Add(feeAmount, ethReceipts[i].L1Fee)
}

receiptJSON, err := ethReceipts[i].MarshalJSON()
if err != nil {
return nil, fmt.Errorf("unable to marshal receipt for %x: %v", txs[i].Tx.Hash().Hex(), err)
}
receipt := &evmClient.RosettaTxReceipt{
Type: ethReceipts[i].Type,
GasPrice: gasPrice,
GasUsed: gasUsed,
Logs: ethReceipts[i].Logs,
// This is a hack to get around the fact that the RosettaTxReceipt doesn't contain L1 fees. We add the raw receipt here so we can access other rollup fields later
RawMessage: receiptJSON,
TransactionFee: feeAmount,
}

receipts[i] = receipt

if ethReceipts[i] == nil {
return nil, fmt.Errorf("got empty receipt for %x", txs[i].Tx.Hash().Hex())
}

if ethReceipts[i].BlockHash != blockHash {
return nil, fmt.Errorf(
"%w: expected block hash %s for Transaction but got %s",
sdkTypes.ErrClientBlockOrphaned,
blockHash.Hex(),
ethReceipts[i].BlockHash.Hex(),
)
}
}

return receipts, nil
}
25 changes: 25 additions & 0 deletions pkg/client/client_gas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package client

import (
"context"
"math/big"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
)

// GetNativeTransferGasLimit is Ethereum's custom implementation of estimating gas.
func (c *OpClient) GetNativeTransferGasLimit(ctx context.Context, toAddress string,
fromAddress string, value *big.Int) (uint64, error) {
if len(toAddress) == 0 || value == nil {
// We guard against malformed inputs that may have been generated using
// a previous version of asset's rosetta
return 21000, nil
}
to := common.HexToAddress(toAddress)
return c.EstimateGas(ctx, ethereum.CallMsg{
From: common.HexToAddress(fromAddress),
To: &to,
Value: value,
})
}
Loading

0 comments on commit c113fb9

Please sign in to comment.