mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
feat: add scroll_api (#893)
* update eth/api.go * update internal/web3ext/web3ext.go * fix * update eth/backend.go * update ethclient/ethclient.go
This commit is contained in:
parent
65af7ee9e5
commit
1c9cc6d621
6 changed files with 459 additions and 6 deletions
237
eth/api_scroll.go
Normal file
237
eth/api_scroll.go
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ScrollAPI provides private RPC methods to query the L1 message database.
|
||||||
|
type ScrollAPI struct {
|
||||||
|
eth *Ethereum
|
||||||
|
}
|
||||||
|
|
||||||
|
// l1MessageTxRPC is the RPC-layer representation of an L1 message.
|
||||||
|
type l1MessageTxRPC struct {
|
||||||
|
QueueIndex uint64 `json:"queueIndex"`
|
||||||
|
Gas uint64 `json:"gas"`
|
||||||
|
To *common.Address `json:"to"`
|
||||||
|
Value *hexutil.Big `json:"value"`
|
||||||
|
Data hexutil.Bytes `json:"data"`
|
||||||
|
Sender common.Address `json:"sender"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewScrollAPI creates a new RPC service to query the L1 message database.
|
||||||
|
func NewScrollAPI(eth *Ethereum) *ScrollAPI {
|
||||||
|
return &ScrollAPI{eth: eth}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetL1SyncHeight returns the latest synced L1 block height from the local database.
|
||||||
|
func (api *ScrollAPI) GetL1SyncHeight(ctx context.Context) (height *uint64, err error) {
|
||||||
|
return rawdb.ReadSyncedL1BlockNumber(api.eth.ChainDb()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetL1MessageByIndex queries an L1 message by its index in the local database.
|
||||||
|
func (api *ScrollAPI) GetL1MessageByIndex(ctx context.Context, queueIndex uint64) (height *l1MessageTxRPC, err error) {
|
||||||
|
msg := rawdb.ReadL1Message(api.eth.ChainDb(), queueIndex)
|
||||||
|
if msg == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
rpcMsg := l1MessageTxRPC{
|
||||||
|
QueueIndex: msg.QueueIndex,
|
||||||
|
Gas: msg.Gas,
|
||||||
|
To: msg.To,
|
||||||
|
Value: (*hexutil.Big)(msg.Value),
|
||||||
|
Data: msg.Data,
|
||||||
|
Sender: msg.Sender,
|
||||||
|
Hash: types.NewTx(msg).Hash(),
|
||||||
|
}
|
||||||
|
return &rpcMsg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFirstQueueIndexNotInL2Block returns the first L1 message queue index that is
|
||||||
|
// not included in the chain up to and including the provided block.
|
||||||
|
func (api *ScrollAPI) GetFirstQueueIndexNotInL2Block(ctx context.Context, hash common.Hash) (queueIndex *uint64, err error) {
|
||||||
|
return rawdb.ReadFirstQueueIndexNotInL2Block(api.eth.ChainDb(), hash), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLatestRelayedQueueIndex returns the highest L1 message queue index included in the canonical chain.
|
||||||
|
func (api *ScrollAPI) GetLatestRelayedQueueIndex(ctx context.Context) (queueIndex *uint64, err error) {
|
||||||
|
block := api.eth.blockchain.CurrentBlock()
|
||||||
|
queueIndex, err = api.GetFirstQueueIndexNotInL2Block(ctx, block.Hash())
|
||||||
|
if queueIndex == nil || err != nil {
|
||||||
|
return queueIndex, err
|
||||||
|
}
|
||||||
|
if *queueIndex == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
lastIncluded := *queueIndex - 1
|
||||||
|
return &lastIncluded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires
|
||||||
|
// a `ScrollAPI`.
|
||||||
|
func (api *ScrollAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, fullTx bool) (map[string]interface{}, error) {
|
||||||
|
fields := ethapi.RPCMarshalBlock(b, true, fullTx, api.eth.APIBackend.ChainConfig())
|
||||||
|
fields["totalDifficulty"] = (*hexutil.Big)(api.eth.APIBackend.GetTd(ctx, b.Hash()))
|
||||||
|
rc := rawdb.ReadBlockRowConsumption(api.eth.ChainDb(), b.Hash())
|
||||||
|
if rc != nil {
|
||||||
|
fields["rowConsumption"] = rc
|
||||||
|
} else {
|
||||||
|
fields["rowConsumption"] = nil
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||||
|
// detail, otherwise only the transaction hash is returned.
|
||||||
|
func (api *ScrollAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||||
|
block, err := api.eth.APIBackend.BlockByHash(ctx, hash)
|
||||||
|
if block != nil {
|
||||||
|
return api.rpcMarshalBlock(ctx, block, fullTx)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByNumber returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||||
|
// detail, otherwise only the transaction hash is returned.
|
||||||
|
func (api *ScrollAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||||
|
block, err := api.eth.APIBackend.BlockByNumber(ctx, number)
|
||||||
|
if block != nil {
|
||||||
|
return api.rpcMarshalBlock(ctx, block, fullTx)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumSkippedTransactions returns the number of skipped transactions.
|
||||||
|
func (api *ScrollAPI) GetNumSkippedTransactions(ctx context.Context) (uint64, error) {
|
||||||
|
return rawdb.ReadNumSkippedTransactions(api.eth.ChainDb()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncStatus includes L2 block sync height, L1 rollup sync height,
|
||||||
|
// L1 message sync height, and L2 finalized block height.
|
||||||
|
type SyncStatus struct {
|
||||||
|
L2BlockSyncHeight uint64 `json:"l2BlockSyncHeight,omitempty"`
|
||||||
|
L1RollupSyncHeight uint64 `json:"l1RollupSyncHeight,omitempty"`
|
||||||
|
L1MessageSyncHeight uint64 `json:"l1MessageSyncHeight,omitempty"`
|
||||||
|
L2FinalizedBlockHeight uint64 `json:"l2FinalizedBlockHeight,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncStatus returns the overall rollup status including L2 block sync height, L1 rollup sync height,
|
||||||
|
// L1 message sync height, and L2 finalized block height.
|
||||||
|
func (api *ScrollAPI) SyncStatus(_ context.Context) *SyncStatus {
|
||||||
|
status := &SyncStatus{}
|
||||||
|
|
||||||
|
l2BlockHeader := api.eth.blockchain.CurrentHeader()
|
||||||
|
if l2BlockHeader != nil {
|
||||||
|
status.L2BlockSyncHeight = l2BlockHeader.Number.Uint64()
|
||||||
|
}
|
||||||
|
|
||||||
|
l1RollupSyncHeightPtr := rawdb.ReadRollupEventSyncedL1BlockNumber(api.eth.ChainDb())
|
||||||
|
if l1RollupSyncHeightPtr != nil {
|
||||||
|
status.L1RollupSyncHeight = *l1RollupSyncHeightPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
l1MessageSyncHeightPtr := rawdb.ReadSyncedL1BlockNumber(api.eth.ChainDb())
|
||||||
|
if l1MessageSyncHeightPtr != nil {
|
||||||
|
status.L1MessageSyncHeight = *l1MessageSyncHeightPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
l2FinalizedBlockHeightPtr := rawdb.ReadFinalizedL2BlockNumber(api.eth.ChainDb())
|
||||||
|
if l2FinalizedBlockHeightPtr != nil {
|
||||||
|
status.L2FinalizedBlockHeight = *l2FinalizedBlockHeightPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateL1DataFee returns an estimate of the L1 data fee required to
|
||||||
|
// process the given transaction against the current pending block.
|
||||||
|
func (api *ScrollAPI) EstimateL1DataFee(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
|
||||||
|
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
||||||
|
if blockNrOrHash != nil {
|
||||||
|
bNrOrHash = *blockNrOrHash
|
||||||
|
}
|
||||||
|
|
||||||
|
l1DataFee, err := ethapi.EstimateL1MsgFee(ctx, api.eth.APIBackend, args, bNrOrHash, nil, 0, api.eth.APIBackend.RPCGasCap(), api.eth.APIBackend.ChainConfig())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to estimate L1 data fee: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := hexutil.Uint64(l1DataFee.Uint64())
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPCTransaction is the standard RPC transaction return type with some additional skip-related fields.
|
||||||
|
type RPCTransaction struct {
|
||||||
|
ethapi.RPCTransaction
|
||||||
|
SkipReason string `json:"skipReason"`
|
||||||
|
SkipBlockNumber *hexutil.Big `json:"skipBlockNumber"`
|
||||||
|
SkipBlockHash *common.Hash `json:"skipBlockHash,omitempty"`
|
||||||
|
|
||||||
|
// wrapped traces, currently only available for `scroll_getSkippedTransaction` API, when `MinerStoreSkippedTxTracesFlag` is set
|
||||||
|
Traces *types.BlockTrace `json:"traces,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSkippedTransaction returns a skipped transaction by its hash.
|
||||||
|
func (api *ScrollAPI) GetSkippedTransaction(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
||||||
|
stx := rawdb.ReadSkippedTransaction(api.eth.ChainDb(), hash)
|
||||||
|
if stx == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var rpcTx RPCTransaction
|
||||||
|
rpcTx.RPCTransaction = *ethapi.NewRPCTransaction(stx.Tx, common.Hash{}, 0, 0, 0, nil, api.eth.blockchain.Config())
|
||||||
|
rpcTx.SkipReason = stx.Reason
|
||||||
|
rpcTx.SkipBlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(stx.BlockNumber))
|
||||||
|
rpcTx.SkipBlockHash = stx.BlockHash
|
||||||
|
if len(stx.TracesBytes) != 0 {
|
||||||
|
traces := &types.BlockTrace{}
|
||||||
|
if err := json.Unmarshal(stx.TracesBytes, traces); err != nil {
|
||||||
|
return nil, fmt.Errorf("fail to Unmarshal traces for skipped tx, hash: %s, err: %w", hash.String(), err)
|
||||||
|
}
|
||||||
|
rpcTx.Traces = traces
|
||||||
|
}
|
||||||
|
return &rpcTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSkippedTransactionHashes returns a list of skipped transaction hashes between the two indices provided (inclusive).
|
||||||
|
func (api *ScrollAPI) GetSkippedTransactionHashes(ctx context.Context, from uint64, to uint64) ([]common.Hash, error) {
|
||||||
|
it := rawdb.IterateSkippedTransactionsFrom(api.eth.ChainDb(), from)
|
||||||
|
defer it.Release()
|
||||||
|
|
||||||
|
var hashes []common.Hash
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
if it.Index() > to {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hashes = append(hashes, it.TransactionHash())
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashes, nil
|
||||||
|
}
|
||||||
|
|
@ -354,6 +354,9 @@ func (s *Ethereum) APIs() []rpc.API {
|
||||||
}, {
|
}, {
|
||||||
Namespace: "net",
|
Namespace: "net",
|
||||||
Service: s.netRPCService,
|
Service: s.netRPCService,
|
||||||
|
}, {
|
||||||
|
Namespace: "scroll",
|
||||||
|
Service: NewScrollAPI(s),
|
||||||
},
|
},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
@ -66,6 +67,11 @@ func (ec *Client) Client() *rpc.Client {
|
||||||
return ec.c
|
return ec.c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetHeader expose the function, in able to set http header.
|
||||||
|
func (ec *Client) SetHeader(key, value string) {
|
||||||
|
ec.c.SetHeader(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
// Blockchain Access
|
// Blockchain Access
|
||||||
|
|
||||||
// ChainID retrieves the current chain ID for transaction replay protection.
|
// ChainID retrieves the current chain ID for transaction replay protection.
|
||||||
|
|
@ -366,6 +372,129 @@ func (ec *Client) GetTxBlockTraceOnTopOfBlock(ctx context.Context, tx *types.Tra
|
||||||
return blockTrace, ec.c.CallContext(ctx, &blockTrace, "scroll_getTxBlockTraceOnTopOfBlock", tx, blockNumberOrHash, config)
|
return blockTrace, ec.c.CallContext(ctx, &blockTrace, "scroll_getTxBlockTraceOnTopOfBlock", tx, blockNumberOrHash, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNumSkippedTransactions returns the ...
|
||||||
|
func (ec *Client) GetNumSkippedTransactions(ctx context.Context) (uint64, error) {
|
||||||
|
var num uint64
|
||||||
|
return num, ec.c.CallContext(ctx, &num, "scroll_getNumSkippedTransactions")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSkippedTransactionHashes returns the BlockTrace given the tx and block.
|
||||||
|
func (ec *Client) GetSkippedTransactionHashes(ctx context.Context, from uint64, to uint64) ([]common.Hash, error) {
|
||||||
|
hashes := []common.Hash{}
|
||||||
|
return hashes, ec.c.CallContext(ctx, &hashes, "scroll_getSkippedTransactionHashes", from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSkippedTransaction returns the BlockTrace given the tx and block.
|
||||||
|
func (ec *Client) GetSkippedTransaction(ctx context.Context, txHash common.Hash) (*eth.RPCTransaction, error) {
|
||||||
|
tx := ð.RPCTransaction{}
|
||||||
|
return tx, ec.c.CallContext(ctx, &tx, "scroll_getSkippedTransaction", txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
type rpcRowConsumption struct {
|
||||||
|
RowConsumption types.RowConsumption `json:"rowConsumption"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
|
func (r *rpcRowConsumption) UnmarshalJSON(input []byte) error {
|
||||||
|
type rpcRowConsumption struct {
|
||||||
|
RowConsumption types.RowConsumption `json:"rowConsumption"`
|
||||||
|
}
|
||||||
|
var dec rpcRowConsumption
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dec.RowConsumption == nil {
|
||||||
|
return errors.New("missing required field 'RowConsumption' for rpcRowConsumption")
|
||||||
|
}
|
||||||
|
r.RowConsumption = dec.RowConsumption
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByNumberOrHash returns the requested block
|
||||||
|
func (ec *Client) GetBlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.BlockWithRowConsumption, error) {
|
||||||
|
var raw json.RawMessage
|
||||||
|
var err error
|
||||||
|
if number, ok := blockNrOrHash.Number(); ok {
|
||||||
|
err = ec.c.CallContext(ctx, &raw, "scroll_getBlockByNumber", number, true)
|
||||||
|
}
|
||||||
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
|
err = ec.c.CallContext(ctx, &raw, "scroll_getBlockByHash", hash, true)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(raw) == 0 {
|
||||||
|
return nil, ethereum.NotFound
|
||||||
|
}
|
||||||
|
// Decode header and transactions.
|
||||||
|
var head *types.Header
|
||||||
|
var body rpcBlock
|
||||||
|
var rpcRc rpcRowConsumption
|
||||||
|
var rc *types.RowConsumption
|
||||||
|
if err := json.Unmarshal(raw, &head); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(raw, &body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(raw, &rpcRc); err != nil {
|
||||||
|
// don't return error here if there is no RowConsumption data, because many l2geth nodes will not have this data
|
||||||
|
// instead of error l2_watcher and other services that require RowConsumption should check it
|
||||||
|
rc = nil
|
||||||
|
} else {
|
||||||
|
rc = &rpcRc.RowConsumption
|
||||||
|
}
|
||||||
|
// Quick-verify transaction and uncle lists. This mostly helps with debugging the server.
|
||||||
|
if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 {
|
||||||
|
return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles")
|
||||||
|
}
|
||||||
|
if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 {
|
||||||
|
return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles")
|
||||||
|
}
|
||||||
|
if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 {
|
||||||
|
return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions")
|
||||||
|
}
|
||||||
|
if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 {
|
||||||
|
return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions")
|
||||||
|
}
|
||||||
|
// Load uncles because they are not included in the block response.
|
||||||
|
var uncles []*types.Header
|
||||||
|
if len(body.UncleHashes) > 0 {
|
||||||
|
uncles = make([]*types.Header, len(body.UncleHashes))
|
||||||
|
reqs := make([]rpc.BatchElem, len(body.UncleHashes))
|
||||||
|
for i := range reqs {
|
||||||
|
reqs[i] = rpc.BatchElem{
|
||||||
|
Method: "eth_getUncleByBlockHashAndIndex",
|
||||||
|
Args: []interface{}{body.Hash, hexutil.EncodeUint64(uint64(i))},
|
||||||
|
Result: &uncles[i],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := ec.c.BatchCallContext(ctx, reqs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range reqs {
|
||||||
|
if reqs[i].Error != nil {
|
||||||
|
return nil, reqs[i].Error
|
||||||
|
}
|
||||||
|
if uncles[i] == nil {
|
||||||
|
return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fill the sender cache of transactions in the block.
|
||||||
|
txs := make([]*types.Transaction, len(body.Transactions))
|
||||||
|
for i, tx := range body.Transactions {
|
||||||
|
if tx.From != nil {
|
||||||
|
setSenderFromServer(tx.tx, *tx.From, body.Hash)
|
||||||
|
}
|
||||||
|
txs[i] = tx.tx
|
||||||
|
}
|
||||||
|
block := types.NewBlockWithHeader(head).WithBody(txs, uncles)
|
||||||
|
return &types.BlockWithRowConsumption{
|
||||||
|
Block: block,
|
||||||
|
RowConsumption: rc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// State Access
|
// State Access
|
||||||
|
|
||||||
// NetworkID returns the network ID for this client.
|
// NetworkID returns the network ID for this client.
|
||||||
|
|
|
||||||
|
|
@ -1522,9 +1522,9 @@ type RPCTransaction struct {
|
||||||
QueueIndex *hexutil.Uint64 `json:"queueIndex,omitempty"`
|
QueueIndex *hexutil.Uint64 `json:"queueIndex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRPCTransaction returns a transaction that will serialize to the RPC
|
// NewRPCTransaction returns a transaction that will serialize to the RPC
|
||||||
// representation, with the given location metadata set (if available).
|
// representation, with the given location metadata set (if available).
|
||||||
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction {
|
func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction {
|
||||||
signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
|
signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
|
||||||
from, _ := types.Sender(signer, tx)
|
from, _ := types.Sender(signer, tx)
|
||||||
v, r, s := tx.RawSignatureValues()
|
v, r, s := tx.RawSignatureValues()
|
||||||
|
|
@ -1627,7 +1627,7 @@ func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, conf
|
||||||
blockNumber = current.Number.Uint64()
|
blockNumber = current.Number.Uint64()
|
||||||
blockTime = current.Time
|
blockTime = current.Time
|
||||||
}
|
}
|
||||||
return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config)
|
return NewRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
||||||
|
|
@ -1636,7 +1636,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param
|
||||||
if index >= uint64(len(txs)) {
|
if index >= uint64(len(txs)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config)
|
return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
|
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
|
||||||
|
|
@ -1840,7 +1840,7 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil
|
return NewRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil
|
||||||
}
|
}
|
||||||
// No finalized transaction, try to retrieve it from the pool
|
// No finalized transaction, try to retrieve it from the pool
|
||||||
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainCo
|
||||||
}
|
}
|
||||||
|
|
||||||
// rpcTransaction
|
// rpcTransaction
|
||||||
rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config)
|
rpcTx := NewRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config)
|
||||||
if data, err := json.Marshal(rpcTx); err != nil {
|
if data, err := json.Marshal(rpcTx); err != nil {
|
||||||
t.Fatalf("test %d: marshalling failed; %v", i, err)
|
t.Fatalf("test %d: marshalling failed; %v", i, err)
|
||||||
} else if err = tx2.UnmarshalJSON(data); err != nil {
|
} else if err = tx2.UnmarshalJSON(data); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ var Modules = map[string]string{
|
||||||
"les": LESJs,
|
"les": LESJs,
|
||||||
"vflux": VfluxJs,
|
"vflux": VfluxJs,
|
||||||
"dev": DevJs,
|
"dev": DevJs,
|
||||||
|
"scroll": ScrollJs,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CliqueJs = `
|
const CliqueJs = `
|
||||||
|
|
@ -911,3 +912,86 @@ web3._extend({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const ScrollJs = `
|
||||||
|
web3._extend({
|
||||||
|
property: 'scroll',
|
||||||
|
methods: [
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getBlockTraceByNumber',
|
||||||
|
call: 'scroll_getBlockTraceByNumberOrHash',
|
||||||
|
params: 1,
|
||||||
|
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getBlockTraceByHash',
|
||||||
|
call: 'scroll_getBlockTraceByNumberOrHash',
|
||||||
|
params: 1
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getTxBlockTraceOnTopOfBlock',
|
||||||
|
call: 'scroll_getTxBlockTraceOnTopOfBlock',
|
||||||
|
params: 3,
|
||||||
|
inputFormatter: [web3._extend.formatters.inputTransactionFormatter, null, null]
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getL1MessageByIndex',
|
||||||
|
call: 'scroll_getL1MessageByIndex',
|
||||||
|
params: 1
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getFirstQueueIndexNotInL2Block',
|
||||||
|
call: 'scroll_getFirstQueueIndexNotInL2Block',
|
||||||
|
params: 1
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getBlockByHash',
|
||||||
|
call: 'scroll_getBlockByHash',
|
||||||
|
params: 2,
|
||||||
|
inputFormatter: [null, function (val) { return !!val; }]
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getBlockByNumber',
|
||||||
|
call: 'scroll_getBlockByNumber',
|
||||||
|
params: 2,
|
||||||
|
inputFormatter: [null, function (val) { return !!val; }]
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getSkippedTransaction',
|
||||||
|
call: 'scroll_getSkippedTransaction',
|
||||||
|
params: 1
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getSkippedTransactionHashes',
|
||||||
|
call: 'scroll_getSkippedTransactionHashes',
|
||||||
|
params: 2
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'estimateL1DataFee',
|
||||||
|
call: 'scroll_estimateL1DataFee',
|
||||||
|
params: 2,
|
||||||
|
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter],
|
||||||
|
outputFormatter: web3._extend.utils.toDecimal
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
properties:
|
||||||
|
[
|
||||||
|
new web3._extend.Property({
|
||||||
|
name: 'l1SyncHeight',
|
||||||
|
getter: 'scroll_getL1SyncHeight'
|
||||||
|
}),
|
||||||
|
new web3._extend.Property({
|
||||||
|
name: 'latestRelayedQueueIndex',
|
||||||
|
getter: 'scroll_getLatestRelayedQueueIndex'
|
||||||
|
}),
|
||||||
|
new web3._extend.Property({
|
||||||
|
name: 'numSkippedTransactions',
|
||||||
|
getter: 'scroll_getNumSkippedTransactions'
|
||||||
|
}),
|
||||||
|
new web3._extend.Property({
|
||||||
|
name: 'syncStatus',
|
||||||
|
getter: 'scroll_syncStatus',
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue