@@ -30,20 +30,24 @@ import (
3030 "github.com/ava-labs/libevm/params"
3131 "github.com/ava-labs/libevm/rpc"
3232
33+ "github.com/ava-labs/strevm/saexec"
3334 "github.com/ava-labs/strevm/txgossip"
3435)
3536
36- // APIBackend returns an API backend backed by the VM.
37- func (vm * VM ) APIBackend () ethapi.Backend {
37+ // APIBackend is the union of all interfaces required to implement the SAE APIs.
38+ type APIBackend interface {
39+ ethapi.Backend
40+ filters.BloomOverrider
41+ }
42+
43+ // APIBackend returns an API backend backed by the [VM].
44+ func (vm * VM ) APIBackend () APIBackend {
3845 return vm .apiBackend
3946}
4047
4148func (vm * VM ) ethRPCServer () (* rpc.Server , error ) {
4249 b := vm .APIBackend ()
43- s := rpc .NewServer ()
4450
45- // Even if this function errors, we should close API to prevent a goroutine
46- // from leaking.
4751 filterSystem := filters .NewFilterSystem (b , filters.Config {})
4852 filterAPI := filters .NewFilterAPI (filterSystem , false /*isLightClient*/ )
4953 vm .toClose = append (vm .toClose , func () error {
@@ -108,6 +112,9 @@ func (vm *VM) ethRPCServer() (*rpc.Server, error) {
108112 // - eth_getRawTransactionByHash
109113 // - eth_pendingTransactions
110114 {"eth" , ethapi .NewTransactionAPI (b , new (ethapi.AddrLocker ))},
115+ // Standard Ethereum node APIS:
116+ // - eth_getLogs
117+ //
111118 // Geth-specific APIs:
112119 // - eth_subscribe
113120 // - newHeads
@@ -143,6 +150,7 @@ func (vm *VM) ethRPCServer() (*rpc.Server, error) {
143150 })
144151 }
145152
153+ s := rpc .NewServer ()
146154 for _ , api := range apis {
147155 if err := s .RegisterName (api .namespace , api .api ); err != nil {
148156 return nil , fmt .Errorf ("%T.RegisterName(%q, %T): %v" , s , api .namespace , api .api , err )
@@ -200,12 +208,51 @@ func (s *netAPI) Version() string {
200208 return s .chainID
201209}
202210
211+ // chainIndexer implements the subset of [ethapi.Backend] required to back a
212+ // [core.ChainIndexer].
213+ type chainIndexer struct {
214+ exec * saexec.Executor
215+ }
216+
217+ var _ core.ChainIndexerChain = chainIndexer {}
218+
219+ func (c chainIndexer ) CurrentHeader () * types.Header {
220+ return types .CopyHeader (c .exec .LastExecuted ().Header ())
221+ }
222+
223+ func (c chainIndexer ) SubscribeChainHeadEvent (ch chan <- core.ChainHeadEvent ) event.Subscription {
224+ return c .exec .SubscribeChainHeadEvent (ch )
225+ }
226+
227+ // A bloomOverrider constructs Bloom filters from persisted receipts instead of
228+ // relying on the [types.Header] field.
229+ type bloomOverrider struct {
230+ db ethdb.Database
231+ }
232+
233+ var _ filters.BloomOverrider = bloomOverrider {}
234+
235+ // OverrideHeaderBloom returns the Bloom filter of the receipts generated when
236+ // executing the respective block, whereas the [types.Header] carries those
237+ // settled by the block.
238+ func (b bloomOverrider ) OverrideHeaderBloom (header * types.Header ) types.Bloom {
239+ return types .CreateBloom (rawdb .ReadRawReceipts (
240+ b .db ,
241+ header .Hash (),
242+ header .Number .Uint64 (),
243+ ))
244+ }
245+
203246type ethAPIBackend struct {
204- * txgossip.Set
205247 vm * VM
206248 accountManager * accounts.Manager
207249
208- ethapi.Backend // TODO(arr4n) remove in favour of `var _ ethapi.Backend = (*ethAPIBackend)(nil)`
250+ * txgossip.Set
251+ chainIndexer
252+ bloomOverrider
253+ * bloomIndexer
254+
255+ ethapi.Backend // TODO(arr4n) remove once all methods are implemented
209256}
210257
211258func (b * ethAPIBackend ) ChainConfig () * params.ChainConfig {
@@ -224,10 +271,6 @@ func (b *ethAPIBackend) AccountManager() *accounts.Manager {
224271 return b .accountManager
225272}
226273
227- func (b * ethAPIBackend ) CurrentHeader () * types.Header {
228- return types .CopyHeader (b .vm .exec .LastExecuted ().Header ())
229- }
230-
231274func (b * ethAPIBackend ) CurrentBlock () * types.Header {
232275 return b .CurrentHeader ()
233276}
@@ -275,6 +318,29 @@ func (b *ethAPIBackend) GetPoolTransaction(txHash common.Hash) *types.Transactio
275318 return b .Set .Pool .Get (txHash )
276319}
277320
321+ func (b * ethAPIBackend ) GetBody (ctx context.Context , hash common.Hash , number rpc.BlockNumber ) (* types.Body , error ) {
322+ if hash == (common.Hash {}) {
323+ return nil , errors .New ("empty block hash" )
324+ }
325+ n , err := b .resolveBlockNumber (number )
326+ if err != nil {
327+ return nil , err
328+ }
329+
330+ if block , ok := b .vm .blocks .Load (hash ); ok {
331+ if block .NumberU64 () != n {
332+ return nil , fmt .Errorf ("found block number %d for hash %#x, expected %d" , block .NumberU64 (), hash , number )
333+ }
334+ return block .EthBlock ().Body (), nil
335+ }
336+
337+ return rawdb .ReadBody (b .vm .db , hash , n ), nil
338+ }
339+
340+ func (b * ethAPIBackend ) GetLogs (ctx context.Context , blockHash common.Hash , number uint64 ) ([][]* types.Log , error ) {
341+ return rawdb .ReadLogs (b .vm .db , blockHash , number ), nil
342+ }
343+
278344func (b * ethAPIBackend ) GetPoolTransactions () (types.Transactions , error ) {
279345 pending := b .Pool .Pending (txpool.PendingFilter {})
280346
@@ -355,10 +421,6 @@ func (b *ethAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Sub
355421 return b .vm .exec .SubscribeChainEvent (ch )
356422}
357423
358- func (b * ethAPIBackend ) SubscribeChainHeadEvent (ch chan <- core.ChainHeadEvent ) event.Subscription {
359- return b .vm .exec .SubscribeChainHeadEvent (ch )
360- }
361-
362424func (b * ethAPIBackend ) SubscribeChainSideEvent (chan <- core.ChainSideEvent ) event.Subscription {
363425 // SAE never reorgs, so there are no side events.
364426 return newNoopSubscription ()
0 commit comments