From 924f8021c57dbbed7c30ddf59520faf1d52524bf Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Tue, 19 Oct 2021 20:19:10 +0300 Subject: [PATCH 1/7] arbitrum: initial create backend and API --- arbitrum/apibackend.go | 245 ++++++++++++++++++++++++++++++++++++ arbitrum/arbos_interface.go | 12 ++ arbitrum/backend.go | 94 ++++++++++++++ 3 files changed, 351 insertions(+) create mode 100644 arbitrum/apibackend.go create mode 100644 arbitrum/arbos_interface.go create mode 100644 arbitrum/backend.go diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go new file mode 100644 index 000000000000..e87b8e18cf1b --- /dev/null +++ b/arbitrum/apibackend.go @@ -0,0 +1,245 @@ +package arbitrum + +import ( + "context" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" +) + +type ArbAPIBackend struct { + b *ArbBackend +} + +func createRegisterAPIBackend(backend *ArbBackend) { + backend.apiBackend = &ArbAPIBackend{ + b: backend, + } + backend.stack.RegisterAPIs(backend.apiBackend.GetAPIs()) +} + +func (a *ArbAPIBackend) GetAPIs() []rpc.API { + return ethapi.GetAPIs(a) +} + +// General Ethereum API +func (a *ArbAPIBackend) SyncProgress() ethereum.SyncProgress { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) ChainDb() ethdb.Database { + return a.b.ethDatabase +} + +func (a *ArbAPIBackend) AccountManager() *accounts.Manager { + return a.b.stack.AccountManager() +} + +func (a *ArbAPIBackend) ExtRPCEnabled() bool { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) RPCGasCap() uint64 { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) RPCTxFeeCap() float64 { + return a.b.ethConfig.RPCTxFeeCap +} + +func (a *ArbAPIBackend) UnprotectedAllowed() bool { + return true // TODO: is that true? +} + +// Blockchain API +func (a *ArbAPIBackend) SetHead(number uint64) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + if number == rpc.LatestBlockNumber { + return a.b.blockChain.CurrentBlock().Header(), nil + } + return a.b.blockChain.GetHeaderByNumber(uint64(number.Int64())), nil +} + +func (a *ArbAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + return a.b.blockChain.GetHeaderByHash(hash), nil +} + +func (a *ArbAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { + number, isnum := blockNrOrHash.Number() + if isnum { + return a.HeaderByNumber(ctx, number) + } + hash, ishash := blockNrOrHash.Hash() + if ishash { + return a.HeaderByHash(ctx, hash) + } + return nil, errors.New("invalid arguments; neither block nor hash specified") +} + +func (a *ArbAPIBackend) CurrentHeader() *types.Header { + return a.b.blockChain.CurrentHeader() +} + +func (a *ArbAPIBackend) CurrentBlock() *types.Block { + return a.b.blockChain.CurrentBlock() +} + +func (a *ArbAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { + return a.b.blockChain.GetBlockByNumber(uint64(number.Int64())), nil +} + +func (a *ArbAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { + return a.b.blockChain.GetBlockByHash(hash), nil +} + +func (a *ArbAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { + number, isnum := blockNrOrHash.Number() + if isnum { + return a.BlockByNumber(ctx, number) + } + hash, ishash := blockNrOrHash.Hash() + if ishash { + return a.BlockByHash(ctx, hash) + } + return nil, errors.New("invalid arguments; neither block nor hash specified") +} + +func (a *ArbAPIBackend) stateAndHeaderFromHeader(header *types.Header, err error) (*state.StateDB, *types.Header, error) { + if err != nil { + return nil, header, err + } + if header == nil { + return nil, nil, errors.New("header not found") + } + state, err := a.b.blockChain.StateAt(header.Root) + return state, header, err +} + +func (a *ArbAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { + return a.stateAndHeaderFromHeader(a.HeaderByNumber(ctx, number)) +} + +func (a *ArbAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { + return a.stateAndHeaderFromHeader(a.HeaderByNumberOrHash(ctx, blockNrOrHash)) +} + +func (a *ArbAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + return a.b.blockChain.GetReceiptsByHash(hash), nil +} + +func (a *ArbAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { + return a.b.blockChain.SubscribeChainEvent(ch) +} + +func (a *ArbAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + return a.b.blockChain.SubscribeChainHeadEvent(ch) +} + +func (a *ArbAPIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { + return a.b.blockChain.SubscribeChainSideEvent(ch) +} + +// Transaction pool API +func (a *ArbAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { + return a.b.EnqueueL2Message(signedTx) +} + +func (a *ArbAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + tx, blockHash, blockNumber, index := rawdb.ReadTransaction(a.b.ethDatabase, txHash) + return tx, blockHash, blockNumber, index, nil +} + +func (a *ArbAPIBackend) GetPoolTransactions() (types.Transactions, error) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) Stats() (pending int, queued int) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) SubscribeNewTxsEvent(_ chan<- core.NewTxsEvent) event.Subscription { + panic("not implemented") // TODO: Implement +} + +// Filter API +func (a *ArbAPIBackend) BloomStatus() (uint64, uint64) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + panic("not implemented") // TODO: Implement +} + +func (a *ArbAPIBackend) ChainConfig() *params.ChainConfig { + return a.b.blockChain.Config() +} + +func (a *ArbAPIBackend) Engine() consensus.Engine { + return a.b.blockChain.Engine() +} diff --git a/arbitrum/arbos_interface.go b/arbitrum/arbos_interface.go new file mode 100644 index 000000000000..4d486116dba4 --- /dev/null +++ b/arbitrum/arbos_interface.go @@ -0,0 +1,12 @@ +package arbitrum + +import ( + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" +) + +type ArbosWrapper interface { + BuildBlock(force bool) (*types.Block, types.Receipts, *state.StateDB) + + EnqueueSequencerTx(tx *types.Transaction) error +} diff --git a/arbitrum/backend.go b/arbitrum/backend.go new file mode 100644 index 000000000000..0d31213bdc08 --- /dev/null +++ b/arbitrum/backend.go @@ -0,0 +1,94 @@ +package arbitrum + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/node" +) + +type ArbBackend struct { + arbos ArbosWrapper + blockChain *core.BlockChain + stack *node.Node + chainId *big.Int + apiBackend *ArbAPIBackend + ethConfig *ethconfig.Config + ethDatabase ethdb.Database + + chanTxs chan *types.Transaction + chanClose chan struct{} //close coroutine + chanNewBlock chan struct{} //create new L2 block unless empty +} + +func NewBackend(stack *node.Node, config *ethconfig.Config, ethDatabase ethdb.Database, blockChain *core.BlockChain, chainId *big.Int, arbos ArbosWrapper) (*ArbBackend, error) { + backend := &ArbBackend{ + arbos: arbos, + blockChain: blockChain, + stack: stack, + chainId: chainId, + ethConfig: config, + ethDatabase: ethDatabase, + chanTxs: make(chan *types.Transaction, 100), + chanClose: make(chan struct{}, 1), + chanNewBlock: make(chan struct{}, 1), + } + stack.RegisterLifecycle(backend) + go backend.segmentQueueRutine() + + createRegisterAPIBackend(backend) + return backend, nil +} + +func (b *ArbBackend) APIBackend() *ArbAPIBackend { + return b.apiBackend +} + +func (b *ArbBackend) EnqueueL2Message(tx *types.Transaction) error { + b.chanTxs <- tx + return nil +} + +func (b *ArbBackend) CloseBlock() { + b.chanNewBlock <- struct{}{} +} + +func (b *ArbBackend) enqueueBlock(block *types.Block, reciepts types.Receipts, state *state.StateDB) { + if block == nil { + return + } + logs := make([]*types.Log, 0) + for _, receipt := range reciepts { + logs = append(logs, receipt.Logs...) + } + b.blockChain.WriteBlockWithState(block, reciepts, logs, state, true) +} + +func (b *ArbBackend) segmentQueueRutine() { + for { + select { + case tx := <-b.chanTxs: + b.arbos.EnqueueSequencerTx(tx) + case <-b.chanNewBlock: + b.enqueueBlock(b.arbos.BuildBlock(true)) + case <-b.chanClose: + return + } + } +} + +//TODO: this is used when registering backend as lifecycle in stack +func (b *ArbBackend) Start() error { + return nil +} + +func (b *ArbBackend) Stop() error { + + b.blockChain.Stop() + + return nil +} From 74545609e63aa2beb496192de7eff756b3a3ba58 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 20 Oct 2021 11:51:09 +0300 Subject: [PATCH 2/7] remove Arb from arbitrum typenames --- arbitrum/apibackend.go | 98 +++++++++++++++++++++--------------------- arbitrum/backend.go | 22 +++++----- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go index e87b8e18cf1b..825482cc706c 100644 --- a/arbitrum/apibackend.go +++ b/arbitrum/apibackend.go @@ -22,75 +22,75 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -type ArbAPIBackend struct { - b *ArbBackend +type APIBackend struct { + b *Backend } -func createRegisterAPIBackend(backend *ArbBackend) { - backend.apiBackend = &ArbAPIBackend{ +func createRegisterAPIBackend(backend *Backend) { + backend.apiBackend = &APIBackend{ b: backend, } backend.stack.RegisterAPIs(backend.apiBackend.GetAPIs()) } -func (a *ArbAPIBackend) GetAPIs() []rpc.API { +func (a *APIBackend) GetAPIs() []rpc.API { return ethapi.GetAPIs(a) } // General Ethereum API -func (a *ArbAPIBackend) SyncProgress() ethereum.SyncProgress { +func (a *APIBackend) SyncProgress() ethereum.SyncProgress { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { +func (a *APIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { +func (a *APIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) ChainDb() ethdb.Database { +func (a *APIBackend) ChainDb() ethdb.Database { return a.b.ethDatabase } -func (a *ArbAPIBackend) AccountManager() *accounts.Manager { +func (a *APIBackend) AccountManager() *accounts.Manager { return a.b.stack.AccountManager() } -func (a *ArbAPIBackend) ExtRPCEnabled() bool { +func (a *APIBackend) ExtRPCEnabled() bool { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) RPCGasCap() uint64 { +func (a *APIBackend) RPCGasCap() uint64 { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) RPCTxFeeCap() float64 { +func (a *APIBackend) RPCTxFeeCap() float64 { return a.b.ethConfig.RPCTxFeeCap } -func (a *ArbAPIBackend) UnprotectedAllowed() bool { +func (a *APIBackend) UnprotectedAllowed() bool { return true // TODO: is that true? } // Blockchain API -func (a *ArbAPIBackend) SetHead(number uint64) { +func (a *APIBackend) SetHead(number uint64) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { +func (a *APIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { if number == rpc.LatestBlockNumber { return a.b.blockChain.CurrentBlock().Header(), nil } return a.b.blockChain.GetHeaderByNumber(uint64(number.Int64())), nil } -func (a *ArbAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { +func (a *APIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { return a.b.blockChain.GetHeaderByHash(hash), nil } -func (a *ArbAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { +func (a *APIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { number, isnum := blockNrOrHash.Number() if isnum { return a.HeaderByNumber(ctx, number) @@ -102,23 +102,23 @@ func (a *ArbAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash return nil, errors.New("invalid arguments; neither block nor hash specified") } -func (a *ArbAPIBackend) CurrentHeader() *types.Header { +func (a *APIBackend) CurrentHeader() *types.Header { return a.b.blockChain.CurrentHeader() } -func (a *ArbAPIBackend) CurrentBlock() *types.Block { +func (a *APIBackend) CurrentBlock() *types.Block { return a.b.blockChain.CurrentBlock() } -func (a *ArbAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { +func (a *APIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { return a.b.blockChain.GetBlockByNumber(uint64(number.Int64())), nil } -func (a *ArbAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { +func (a *APIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { return a.b.blockChain.GetBlockByHash(hash), nil } -func (a *ArbAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { +func (a *APIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { number, isnum := blockNrOrHash.Number() if isnum { return a.BlockByNumber(ctx, number) @@ -130,7 +130,7 @@ func (a *ArbAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r return nil, errors.New("invalid arguments; neither block nor hash specified") } -func (a *ArbAPIBackend) stateAndHeaderFromHeader(header *types.Header, err error) (*state.StateDB, *types.Header, error) { +func (a *APIBackend) stateAndHeaderFromHeader(header *types.Header, err error) (*state.StateDB, *types.Header, error) { if err != nil { return nil, header, err } @@ -141,105 +141,105 @@ func (a *ArbAPIBackend) stateAndHeaderFromHeader(header *types.Header, err error return state, header, err } -func (a *ArbAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { +func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { return a.stateAndHeaderFromHeader(a.HeaderByNumber(ctx, number)) } -func (a *ArbAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { +func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { return a.stateAndHeaderFromHeader(a.HeaderByNumberOrHash(ctx, blockNrOrHash)) } -func (a *ArbAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { +func (a *APIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { return a.b.blockChain.GetReceiptsByHash(hash), nil } -func (a *ArbAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { +func (a *APIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (a *APIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { +func (a *APIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return a.b.blockChain.SubscribeChainEvent(ch) } -func (a *ArbAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { +func (a *APIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { return a.b.blockChain.SubscribeChainHeadEvent(ch) } -func (a *ArbAPIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { +func (a *APIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { return a.b.blockChain.SubscribeChainSideEvent(ch) } // Transaction pool API -func (a *ArbAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { +func (a *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { return a.b.EnqueueL2Message(signedTx) } -func (a *ArbAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { +func (a *APIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { tx, blockHash, blockNumber, index := rawdb.ReadTransaction(a.b.ethDatabase, txHash) return tx, blockHash, blockNumber, index, nil } -func (a *ArbAPIBackend) GetPoolTransactions() (types.Transactions, error) { +func (a *APIBackend) GetPoolTransactions() (types.Transactions, error) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { +func (a *APIBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { +func (a *APIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) Stats() (pending int, queued int) { +func (a *APIBackend) Stats() (pending int, queued int) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { +func (a *APIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { +func (a *APIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) SubscribeNewTxsEvent(_ chan<- core.NewTxsEvent) event.Subscription { +func (a *APIBackend) SubscribeNewTxsEvent(_ chan<- core.NewTxsEvent) event.Subscription { panic("not implemented") // TODO: Implement } // Filter API -func (a *ArbAPIBackend) BloomStatus() (uint64, uint64) { +func (a *APIBackend) BloomStatus() (uint64, uint64) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { +func (a *APIBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { +func (a *APIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { +func (a *APIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { +func (a *APIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { +func (a *APIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { panic("not implemented") // TODO: Implement } -func (a *ArbAPIBackend) ChainConfig() *params.ChainConfig { +func (a *APIBackend) ChainConfig() *params.ChainConfig { return a.b.blockChain.Config() } -func (a *ArbAPIBackend) Engine() consensus.Engine { +func (a *APIBackend) Engine() consensus.Engine { return a.b.blockChain.Engine() } diff --git a/arbitrum/backend.go b/arbitrum/backend.go index 0d31213bdc08..81adb9632608 100644 --- a/arbitrum/backend.go +++ b/arbitrum/backend.go @@ -11,12 +11,12 @@ import ( "github.com/ethereum/go-ethereum/node" ) -type ArbBackend struct { +type Backend struct { arbos ArbosWrapper blockChain *core.BlockChain stack *node.Node chainId *big.Int - apiBackend *ArbAPIBackend + apiBackend *APIBackend ethConfig *ethconfig.Config ethDatabase ethdb.Database @@ -25,8 +25,8 @@ type ArbBackend struct { chanNewBlock chan struct{} //create new L2 block unless empty } -func NewBackend(stack *node.Node, config *ethconfig.Config, ethDatabase ethdb.Database, blockChain *core.BlockChain, chainId *big.Int, arbos ArbosWrapper) (*ArbBackend, error) { - backend := &ArbBackend{ +func NewBackend(stack *node.Node, config *ethconfig.Config, ethDatabase ethdb.Database, blockChain *core.BlockChain, chainId *big.Int, arbos ArbosWrapper) (*Backend, error) { + backend := &Backend{ arbos: arbos, blockChain: blockChain, stack: stack, @@ -44,20 +44,20 @@ func NewBackend(stack *node.Node, config *ethconfig.Config, ethDatabase ethdb.Da return backend, nil } -func (b *ArbBackend) APIBackend() *ArbAPIBackend { +func (b *Backend) APIBackend() *APIBackend { return b.apiBackend } -func (b *ArbBackend) EnqueueL2Message(tx *types.Transaction) error { +func (b *Backend) EnqueueL2Message(tx *types.Transaction) error { b.chanTxs <- tx return nil } -func (b *ArbBackend) CloseBlock() { +func (b *Backend) CloseBlock() { b.chanNewBlock <- struct{}{} } -func (b *ArbBackend) enqueueBlock(block *types.Block, reciepts types.Receipts, state *state.StateDB) { +func (b *Backend) enqueueBlock(block *types.Block, reciepts types.Receipts, state *state.StateDB) { if block == nil { return } @@ -68,7 +68,7 @@ func (b *ArbBackend) enqueueBlock(block *types.Block, reciepts types.Receipts, s b.blockChain.WriteBlockWithState(block, reciepts, logs, state, true) } -func (b *ArbBackend) segmentQueueRutine() { +func (b *Backend) segmentQueueRutine() { for { select { case tx := <-b.chanTxs: @@ -82,11 +82,11 @@ func (b *ArbBackend) segmentQueueRutine() { } //TODO: this is used when registering backend as lifecycle in stack -func (b *ArbBackend) Start() error { +func (b *Backend) Start() error { return nil } -func (b *ArbBackend) Stop() error { +func (b *Backend) Stop() error { b.blockChain.Stop() From 4cd9e482e9b08ecf2533730cfdba07d79de4b7d4 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 20 Oct 2021 11:53:38 +0300 Subject: [PATCH 3/7] fix funcname typo --- arbitrum/backend.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arbitrum/backend.go b/arbitrum/backend.go index 81adb9632608..7fad0f051f53 100644 --- a/arbitrum/backend.go +++ b/arbitrum/backend.go @@ -38,7 +38,7 @@ func NewBackend(stack *node.Node, config *ethconfig.Config, ethDatabase ethdb.Da chanNewBlock: make(chan struct{}, 1), } stack.RegisterLifecycle(backend) - go backend.segmentQueueRutine() + go backend.segmentQueueRoutine() createRegisterAPIBackend(backend) return backend, nil @@ -68,7 +68,7 @@ func (b *Backend) enqueueBlock(block *types.Block, reciepts types.Receipts, stat b.blockChain.WriteBlockWithState(block, reciepts, logs, state, true) } -func (b *Backend) segmentQueueRutine() { +func (b *Backend) segmentQueueRoutine() { for { select { case tx := <-b.chanTxs: From ae2896942a8a54825011c2bb3f74d75b86d0403b Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 20 Oct 2021 17:25:13 +0300 Subject: [PATCH 4/7] arbitrum backend: support subscriptions --- arbitrum/apibackend.go | 24 ++++++++++++++++++------ arbitrum/backend.go | 10 ++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go index 825482cc706c..80ade414517c 100644 --- a/arbitrum/apibackend.go +++ b/arbitrum/apibackend.go @@ -4,6 +4,7 @@ import ( "context" "errors" "math/big" + "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" @@ -15,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -34,7 +36,15 @@ func createRegisterAPIBackend(backend *Backend) { } func (a *APIBackend) GetAPIs() []rpc.API { - return ethapi.GetAPIs(a) + apis := ethapi.GetAPIs(a) + + apis = append(apis, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: filters.NewPublicFilterAPI(a, false, 5*time.Minute), + Public: true, + }) + return apis } // General Ethereum API @@ -207,8 +217,8 @@ func (a *APIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, panic("not implemented") // TODO: Implement } -func (a *APIBackend) SubscribeNewTxsEvent(_ chan<- core.NewTxsEvent) event.Subscription { - panic("not implemented") // TODO: Implement +func (a *APIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + return a.b.SubscribeNewTxsEvent(ch) } // Filter API @@ -225,15 +235,17 @@ func (a *APIBackend) ServiceFilter(ctx context.Context, session *bloombits.Match } func (a *APIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { - panic("not implemented") // TODO: Implement + return a.b.blockChain.SubscribeLogsEvent(ch) } func (a *APIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - panic("not implemented") // TODO: Implement + //TODO: this is a nop subscription + //Arbitrum doesn't really need pending logs. Logs are published as soon as we know them.. + return event.NewSubscription(func(<-chan struct{}) error { return nil }) } func (a *APIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { - panic("not implemented") // TODO: Implement + return a.b.blockChain.SubscribeRemovedLogsEvent(ch) } func (a *APIBackend) ChainConfig() *params.ChainConfig { diff --git a/arbitrum/backend.go b/arbitrum/backend.go index 7fad0f051f53..a30145e91517 100644 --- a/arbitrum/backend.go +++ b/arbitrum/backend.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/node" ) @@ -20,6 +21,9 @@ type Backend struct { ethConfig *ethconfig.Config ethDatabase ethdb.Database + txFeed event.Feed + scope event.SubscriptionScope + chanTxs chan *types.Transaction chanClose chan struct{} //close coroutine chanNewBlock chan struct{} //create new L2 block unless empty @@ -57,6 +61,10 @@ func (b *Backend) CloseBlock() { b.chanNewBlock <- struct{}{} } +func (b *Backend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + return b.scope.Track(b.txFeed.Subscribe(ch)) +} + func (b *Backend) enqueueBlock(block *types.Block, reciepts types.Receipts, state *state.StateDB) { if block == nil { return @@ -72,6 +80,7 @@ func (b *Backend) segmentQueueRoutine() { for { select { case tx := <-b.chanTxs: + b.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}}) b.arbos.EnqueueSequencerTx(tx) case <-b.chanNewBlock: b.enqueueBlock(b.arbos.BuildBlock(true)) @@ -88,6 +97,7 @@ func (b *Backend) Start() error { func (b *Backend) Stop() error { + b.scope.Close() b.blockChain.Stop() return nil From 37a6c9416a5c05dcc8898fe95e62e7172ac4c92f Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 21 Oct 2021 06:41:26 +0300 Subject: [PATCH 5/7] subscribe to new logs when requesting pending --- arbitrum/apibackend.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go index 80ade414517c..a26cadd4e4c2 100644 --- a/arbitrum/apibackend.go +++ b/arbitrum/apibackend.go @@ -239,9 +239,8 @@ func (a *APIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscripti } func (a *APIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - //TODO: this is a nop subscription //Arbitrum doesn't really need pending logs. Logs are published as soon as we know them.. - return event.NewSubscription(func(<-chan struct{}) error { return nil }) + return a.SubscribeLogsEvent(ch) } func (a *APIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { From 9740de5e3f5b11c8e433fb5de2de1392e15f5167 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 21 Oct 2021 06:42:23 +0300 Subject: [PATCH 6/7] add l1header to enqueue seq. messages --- arbitrum/arbos_interface.go | 3 ++- arbitrum/backend.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arbitrum/arbos_interface.go b/arbitrum/arbos_interface.go index 4d486116dba4..7eb761e954af 100644 --- a/arbitrum/arbos_interface.go +++ b/arbitrum/arbos_interface.go @@ -8,5 +8,6 @@ import ( type ArbosWrapper interface { BuildBlock(force bool) (*types.Block, types.Receipts, *state.StateDB) - EnqueueSequencerTx(tx *types.Transaction) error + //l1header is header is nil if message doesn't yet appear in l1 + EnqueueSequencerTx(tx *types.Transaction, l1header *types.Header) error } diff --git a/arbitrum/backend.go b/arbitrum/backend.go index a30145e91517..db5418733dbe 100644 --- a/arbitrum/backend.go +++ b/arbitrum/backend.go @@ -81,7 +81,7 @@ func (b *Backend) segmentQueueRoutine() { select { case tx := <-b.chanTxs: b.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}}) - b.arbos.EnqueueSequencerTx(tx) + b.arbos.EnqueueSequencerTx(tx, nil) case <-b.chanNewBlock: b.enqueueBlock(b.arbos.BuildBlock(true)) case <-b.chanClose: From b70e4993209da4fe28fc8091c1ceda6e13a02dcf Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 21 Oct 2021 07:51:51 +0300 Subject: [PATCH 7/7] Revert "add l1header to enqueue seq. messages" This reverts commit 9740de5e3f5b11c8e433fb5de2de1392e15f5167. --- arbitrum/arbos_interface.go | 3 +-- arbitrum/backend.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arbitrum/arbos_interface.go b/arbitrum/arbos_interface.go index 7eb761e954af..4d486116dba4 100644 --- a/arbitrum/arbos_interface.go +++ b/arbitrum/arbos_interface.go @@ -8,6 +8,5 @@ import ( type ArbosWrapper interface { BuildBlock(force bool) (*types.Block, types.Receipts, *state.StateDB) - //l1header is header is nil if message doesn't yet appear in l1 - EnqueueSequencerTx(tx *types.Transaction, l1header *types.Header) error + EnqueueSequencerTx(tx *types.Transaction) error } diff --git a/arbitrum/backend.go b/arbitrum/backend.go index db5418733dbe..a30145e91517 100644 --- a/arbitrum/backend.go +++ b/arbitrum/backend.go @@ -81,7 +81,7 @@ func (b *Backend) segmentQueueRoutine() { select { case tx := <-b.chanTxs: b.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}}) - b.arbos.EnqueueSequencerTx(tx, nil) + b.arbos.EnqueueSequencerTx(tx) case <-b.chanNewBlock: b.enqueueBlock(b.arbos.BuildBlock(true)) case <-b.chanClose: