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",
|
||||
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/hexutil"
|
||||
"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/rpc"
|
||||
)
|
||||
|
|
@ -66,6 +67,11 @@ func (ec *Client) Client() *rpc.Client {
|
|||
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
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// NetworkID returns the network ID for this client.
|
||||
|
|
|
|||
|
|
@ -1522,9 +1522,9 @@ type RPCTransaction struct {
|
|||
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).
|
||||
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)
|
||||
from, _ := types.Sender(signer, tx)
|
||||
v, r, s := tx.RawSignatureValues()
|
||||
|
|
@ -1627,7 +1627,7 @@ func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, conf
|
|||
blockNumber = current.Number.Uint64()
|
||||
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.
|
||||
|
|
@ -1636,7 +1636,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param
|
|||
if index >= uint64(len(txs)) {
|
||||
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.
|
||||
|
|
@ -1840,7 +1840,7 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H
|
|||
if err != nil {
|
||||
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
|
||||
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainCo
|
|||
}
|
||||
|
||||
// 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 {
|
||||
t.Fatalf("test %d: marshalling failed; %v", i, err)
|
||||
} else if err = tx2.UnmarshalJSON(data); err != nil {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ var Modules = map[string]string{
|
|||
"les": LESJs,
|
||||
"vflux": VfluxJs,
|
||||
"dev": DevJs,
|
||||
"scroll": ScrollJs,
|
||||
}
|
||||
|
||||
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