github.com/Cleverse/go-ethereum@v0.0.0-20220927095127-45113064e7f2/arbitrum/apibackend.go (about) 1 package arbitrum 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "math/big" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/ethereum/go-ethereum" 13 "github.com/ethereum/go-ethereum/eth" 14 "github.com/ethereum/go-ethereum/eth/tracers" 15 "github.com/ethereum/go-ethereum/log" 16 17 "github.com/ethereum/go-ethereum/accounts" 18 "github.com/ethereum/go-ethereum/common" 19 "github.com/ethereum/go-ethereum/consensus" 20 "github.com/ethereum/go-ethereum/core" 21 "github.com/ethereum/go-ethereum/core/bloombits" 22 "github.com/ethereum/go-ethereum/core/rawdb" 23 "github.com/ethereum/go-ethereum/core/state" 24 "github.com/ethereum/go-ethereum/core/types" 25 "github.com/ethereum/go-ethereum/core/vm" 26 "github.com/ethereum/go-ethereum/eth/filters" 27 "github.com/ethereum/go-ethereum/ethdb" 28 "github.com/ethereum/go-ethereum/event" 29 "github.com/ethereum/go-ethereum/internal/ethapi" 30 "github.com/ethereum/go-ethereum/params" 31 "github.com/ethereum/go-ethereum/rpc" 32 ) 33 34 type APIBackend struct { 35 b *Backend 36 37 fallbackClient types.FallbackClient 38 sync SyncProgressBackend 39 } 40 41 type timeoutFallbackClient struct { 42 impl types.FallbackClient 43 timeout time.Duration 44 } 45 46 func (c *timeoutFallbackClient) CallContext(ctxIn context.Context, result interface{}, method string, args ...interface{}) error { 47 ctx, cancel := context.WithTimeout(ctxIn, c.timeout) 48 defer cancel() 49 return c.impl.CallContext(ctx, result, method, args) 50 } 51 52 func createFallbackClient(fallbackClientUrl string, fallbackClientTimeout time.Duration) (types.FallbackClient, error) { 53 if fallbackClientUrl == "" { 54 return nil, nil 55 } 56 if strings.HasPrefix(fallbackClientUrl, "error:") { 57 fields := strings.Split(fallbackClientUrl, ":")[1:] 58 errNumber, convErr := strconv.ParseInt(fields[0], 0, 0) 59 if convErr == nil { 60 fields = fields[1:] 61 } else { 62 errNumber = -32000 63 } 64 types.SetFallbackError(strings.Join(fields, ":"), int(errNumber)) 65 return nil, nil 66 } 67 var fallbackClient types.FallbackClient 68 var err error 69 fallbackClient, err = rpc.Dial(fallbackClientUrl) 70 if fallbackClient == nil || err != nil { 71 return nil, fmt.Errorf("failed creating fallback connection: %w", err) 72 } 73 if fallbackClientTimeout != 0 { 74 fallbackClient = &timeoutFallbackClient{ 75 impl: fallbackClient, 76 timeout: fallbackClientTimeout, 77 } 78 } 79 return fallbackClient, nil 80 } 81 82 type SyncProgressBackend interface { 83 SyncProgressMap() map[string]interface{} 84 } 85 86 func createRegisterAPIBackend(backend *Backend, sync SyncProgressBackend, fallbackClientUrl string, fallbackClientTimeout time.Duration) error { 87 fallbackClient, err := createFallbackClient(fallbackClientUrl, fallbackClientTimeout) 88 if err != nil { 89 return err 90 } 91 backend.apiBackend = &APIBackend{ 92 b: backend, 93 fallbackClient: fallbackClient, 94 sync: sync, 95 } 96 backend.stack.RegisterAPIs(backend.apiBackend.GetAPIs()) 97 return nil 98 } 99 100 func (a *APIBackend) GetAPIs() []rpc.API { 101 apis := ethapi.GetAPIs(a) 102 103 apis = append(apis, rpc.API{ 104 Namespace: "eth", 105 Version: "1.0", 106 Service: filters.NewFilterAPI(a, false, 5*time.Minute), 107 Public: true, 108 }) 109 110 apis = append(apis, rpc.API{ 111 Namespace: "net", 112 Version: "1.0", 113 Service: NewPublicNetAPI(a.ChainConfig().ChainID.Uint64()), 114 Public: true, 115 }) 116 117 apis = append(apis, rpc.API{ 118 Namespace: "txpool", 119 Version: "1.0", 120 Service: NewPublicTxPoolAPI(), 121 Public: true, 122 }) 123 124 apis = append(apis, tracers.APIs(a)...) 125 126 return apis 127 } 128 129 func (a *APIBackend) blockChain() *core.BlockChain { 130 return a.b.arb.BlockChain() 131 } 132 133 func (a *APIBackend) GetArbitrumNode() interface{} { 134 return a.b.arb.ArbNode() 135 } 136 137 // General Ethereum API 138 func (a *APIBackend) SyncProgressMap() map[string]interface{} { 139 return a.sync.SyncProgressMap() 140 } 141 142 func (a *APIBackend) SyncProgress() ethereum.SyncProgress { 143 progress := a.sync.SyncProgressMap() 144 145 if progress == nil || len(progress) == 0 { 146 return ethereum.SyncProgress{} 147 } 148 return ethereum.SyncProgress{ 149 CurrentBlock: 0, 150 HighestBlock: 1, 151 } 152 } 153 154 func (a *APIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 155 return big.NewInt(0), nil // there's no tips in L2 156 } 157 158 func (a *APIBackend) FeeHistory( 159 ctx context.Context, 160 blocks int, 161 newestBlock rpc.BlockNumber, 162 rewardPercentiles []float64, 163 ) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { 164 165 if core.GetArbOSSpeedLimitPerSecond == nil { 166 return nil, nil, nil, nil, errors.New("ArbOS not installed") 167 } 168 169 nitroGenesis := rpc.BlockNumber(a.ChainConfig().ArbitrumChainParams.GenesisBlockNum) 170 newestBlock, latestBlock := a.blockChain().ClipToPostNitroGenesis(newestBlock) 171 172 maxFeeHistory := int(a.b.config.FeeHistoryMaxBlockCount) 173 if blocks > maxFeeHistory { 174 log.Warn("Sanitizing fee history length", "requested", blocks, "truncated", maxFeeHistory) 175 blocks = maxFeeHistory 176 } 177 if blocks < 1 { 178 // returning with no data and no error means there are no retrievable blocks 179 return common.Big0, nil, nil, nil, nil 180 } 181 182 // don't attempt to include blocks before genesis 183 if rpc.BlockNumber(blocks) > (newestBlock - nitroGenesis) { 184 blocks = int(newestBlock - nitroGenesis + 1) 185 } 186 oldestBlock := int(newestBlock) + 1 - blocks 187 188 // inform that tipping has no effect on inclusion 189 rewards := make([][]*big.Int, blocks) 190 zeros := make([]*big.Int, len(rewardPercentiles)) 191 for i := range zeros { 192 zeros[i] = common.Big0 193 } 194 for i := range rewards { 195 rewards[i] = zeros 196 } 197 if len(rewardPercentiles) == 0 { 198 rewards = nil 199 } 200 201 // use the most recent average compute rate for all blocks 202 // note: while we could query this value for each block, it'd be prohibitively expensive 203 state, _, err := a.StateAndHeaderByNumber(ctx, rpc.BlockNumber(newestBlock)) 204 if err != nil { 205 return common.Big0, nil, nil, nil, err 206 } 207 speedLimit, err := core.GetArbOSSpeedLimitPerSecond(state) 208 if err != nil { 209 return common.Big0, nil, nil, nil, err 210 } 211 212 gasUsed := make([]float64, blocks) 213 basefees := make([]*big.Int, blocks+1) // the RPC semantics are to predict the future value 214 215 // collect the basefees 216 baseFeeLookup := newestBlock + 1 217 if newestBlock == latestBlock { 218 baseFeeLookup = newestBlock 219 } 220 var prevTimestamp uint64 221 var timeSinceLastTimeChange uint64 222 var currentTimestampGasUsed uint64 223 if rpc.BlockNumber(oldestBlock) > nitroGenesis { 224 header, err := a.HeaderByNumber(ctx, rpc.BlockNumber(oldestBlock-1)) 225 if err != nil { 226 return common.Big0, nil, nil, nil, err 227 } 228 prevTimestamp = header.Time 229 } 230 for block := oldestBlock; block <= int(baseFeeLookup); block++ { 231 header, err := a.HeaderByNumber(ctx, rpc.BlockNumber(block)) 232 if err != nil { 233 return common.Big0, nil, nil, nil, err 234 } 235 basefees[block-oldestBlock] = header.BaseFee 236 237 if block > int(newestBlock) { 238 break 239 } 240 241 if header.Time > prevTimestamp { 242 timeSinceLastTimeChange = header.Time - prevTimestamp 243 currentTimestampGasUsed = 0 244 } 245 246 receipts := a.blockChain().GetReceiptsByHash(header.ReceiptHash) 247 for _, receipt := range receipts { 248 if receipt.GasUsed > receipt.GasUsedForL1 { 249 currentTimestampGasUsed += receipt.GasUsed - receipt.GasUsedForL1 250 } 251 } 252 253 prevTimestamp = header.Time 254 255 // In vanilla geth, this RPC returns the gasUsed ratio so a client can know how the basefee will change 256 // To emulate this, we translate the compute rate into something similar, centered at an analogous 0.5 257 var fullnessAnalogue float64 258 if timeSinceLastTimeChange > 0 { 259 fullnessAnalogue = float64(currentTimestampGasUsed) / float64(speedLimit) / float64(timeSinceLastTimeChange) / 2.0 260 if fullnessAnalogue > 1.0 { 261 fullnessAnalogue = 1.0 262 } 263 } else { 264 // We haven't looked far enough back to know the last timestamp change, 265 // so treat this block as full. 266 fullnessAnalogue = 1.0 267 } 268 gasUsed[block-oldestBlock] = fullnessAnalogue 269 270 } 271 if newestBlock == latestBlock { 272 basefees[blocks] = basefees[blocks-1] // guess the basefee won't change 273 } 274 275 return big.NewInt(int64(oldestBlock)), rewards, basefees, gasUsed, nil 276 } 277 278 func (a *APIBackend) ChainDb() ethdb.Database { 279 return a.b.chainDb 280 } 281 282 func (a *APIBackend) AccountManager() *accounts.Manager { 283 return a.b.stack.AccountManager() 284 } 285 286 func (a *APIBackend) ExtRPCEnabled() bool { 287 panic("not implemented") // TODO: Implement 288 } 289 290 func (a *APIBackend) RPCGasCap() uint64 { 291 return a.b.config.RPCGasCap 292 } 293 294 func (a *APIBackend) RPCTxFeeCap() float64 { 295 return a.b.config.RPCTxFeeCap 296 } 297 298 func (a *APIBackend) RPCEVMTimeout() time.Duration { 299 return a.b.config.RPCEVMTimeout 300 } 301 302 func (a *APIBackend) UnprotectedAllowed() bool { 303 return true // TODO: is that true? 304 } 305 306 // Blockchain API 307 func (a *APIBackend) SetHead(number uint64) { 308 panic("not implemented") // TODO: Implement 309 } 310 311 func (a *APIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { 312 return HeaderByNumber(a.blockChain(), number), nil 313 } 314 315 func (a *APIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 316 return a.blockChain().GetHeaderByHash(hash), nil 317 } 318 319 func HeaderByNumber(blockchain *core.BlockChain, number rpc.BlockNumber) *types.Header { 320 if number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber { 321 return blockchain.CurrentBlock().Header() 322 } 323 return blockchain.GetHeaderByNumber(uint64(number.Int64())) 324 } 325 326 func HeaderByNumberOrHash(blockchain *core.BlockChain, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { 327 number, isnum := blockNrOrHash.Number() 328 if isnum { 329 return HeaderByNumber(blockchain, number), nil 330 } 331 hash, ishash := blockNrOrHash.Hash() 332 if ishash { 333 return blockchain.GetHeaderByHash(hash), nil 334 } 335 return nil, errors.New("invalid arguments; neither block nor hash specified") 336 } 337 338 func (a *APIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { 339 return HeaderByNumberOrHash(a.blockChain(), blockNrOrHash) 340 } 341 342 func (a *APIBackend) CurrentHeader() *types.Header { 343 return a.blockChain().CurrentHeader() 344 } 345 346 func (a *APIBackend) CurrentBlock() *types.Block { 347 return a.blockChain().CurrentBlock() 348 } 349 350 func (a *APIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { 351 if number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber { 352 return a.blockChain().CurrentBlock(), nil 353 } 354 return a.blockChain().GetBlockByNumber(uint64(number.Int64())), nil 355 } 356 357 func (a *APIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 358 return a.blockChain().GetBlockByHash(hash), nil 359 } 360 361 func (a *APIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { 362 number, isnum := blockNrOrHash.Number() 363 if isnum { 364 return a.BlockByNumber(ctx, number) 365 } 366 hash, ishash := blockNrOrHash.Hash() 367 if ishash { 368 return a.BlockByHash(ctx, hash) 369 } 370 return nil, errors.New("invalid arguments; neither block nor hash specified") 371 } 372 373 func (a *APIBackend) stateAndHeaderFromHeader(header *types.Header, err error) (*state.StateDB, *types.Header, error) { 374 if err != nil { 375 return nil, header, err 376 } 377 if header == nil { 378 return nil, nil, errors.New("header not found") 379 } 380 if !a.blockChain().Config().IsArbitrumNitro(header.Number) { 381 return nil, header, types.ErrUseFallback 382 } 383 state, err := a.blockChain().StateAt(header.Root) 384 return state, header, err 385 } 386 387 func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { 388 return a.stateAndHeaderFromHeader(a.HeaderByNumber(ctx, number)) 389 } 390 391 func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { 392 return a.stateAndHeaderFromHeader(a.HeaderByNumberOrHash(ctx, blockNrOrHash)) 393 } 394 395 func (a *APIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { 396 if !a.blockChain().Config().IsArbitrumNitro(block.Number()) { 397 return nil, types.ErrUseFallback 398 } 399 // DEV: This assumes that `StateAtBlock` only accesses the blockchain and chainDb fields 400 return eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtBlock(block, reexec, base, checkLive, preferDisk) 401 } 402 403 func (a *APIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { 404 if !a.blockChain().Config().IsArbitrumNitro(block.Number()) { 405 return nil, vm.BlockContext{}, nil, types.ErrUseFallback 406 } 407 // DEV: This assumes that `StateAtTransaction` only accesses the blockchain and chainDb fields 408 return eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtTransaction(block, txIndex, reexec) 409 } 410 411 func (a *APIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 412 return a.blockChain().GetReceiptsByHash(hash), nil 413 } 414 415 func (a *APIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { 416 if header := a.blockChain().GetHeaderByHash(hash); header != nil { 417 return a.blockChain().GetTd(hash, header.Number.Uint64()) 418 } 419 return nil 420 } 421 422 func (a *APIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { 423 vmError := func() error { return nil } 424 if vmConfig == nil { 425 vmConfig = a.blockChain().GetVMConfig() 426 } 427 txContext := core.NewEVMTxContext(msg) 428 context := core.NewEVMBlockContext(header, a.blockChain(), nil) 429 return vm.NewEVM(context, txContext, state, a.blockChain().Config(), *vmConfig), vmError, nil 430 } 431 432 func (a *APIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 433 return a.blockChain().SubscribeChainEvent(ch) 434 } 435 436 func (a *APIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 437 return a.blockChain().SubscribeChainHeadEvent(ch) 438 } 439 440 func (a *APIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { 441 return a.blockChain().SubscribeChainSideEvent(ch) 442 } 443 444 // Transaction pool API 445 func (a *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { 446 return a.b.EnqueueL2Message(ctx, signedTx) 447 } 448 449 func (a *APIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { 450 tx, blockHash, blockNumber, index := rawdb.ReadTransaction(a.b.chainDb, txHash) 451 return tx, blockHash, blockNumber, index, nil 452 } 453 454 func (a *APIBackend) GetPoolTransactions() (types.Transactions, error) { 455 // Arbitrum doesn't have a pool 456 return types.Transactions{}, nil 457 } 458 459 func (a *APIBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { 460 // Arbitrum doesn't have a pool 461 return nil 462 } 463 464 func (a *APIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { 465 stateDB, err := a.blockChain().State() 466 if err != nil { 467 return 0, err 468 } 469 return stateDB.GetNonce(addr), nil 470 } 471 472 func (a *APIBackend) Stats() (pending int, queued int) { 473 panic("not implemented") // TODO: Implement 474 } 475 476 func (a *APIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { 477 panic("not implemented") // TODO: Implement 478 } 479 480 func (a *APIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { 481 panic("not implemented") // TODO: Implement 482 } 483 484 func (a *APIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 485 return a.b.SubscribeNewTxsEvent(ch) 486 } 487 488 // Filter API 489 func (a *APIBackend) BloomStatus() (uint64, uint64) { 490 sections, _, _ := a.b.bloomIndexer.Sections() 491 return a.b.config.BloomBitsBlocks, sections 492 } 493 494 func (a *APIBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { 495 receipts := a.blockChain().GetReceiptsByHash(blockHash) 496 if receipts == nil { 497 return nil, nil 498 } 499 logs := make([][]*types.Log, len(receipts)) 500 for i, receipt := range receipts { 501 logs[i] = receipt.Logs 502 } 503 return logs, nil 504 } 505 506 func (a *APIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { 507 for i := 0; i < bloomFilterThreads; i++ { 508 go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, a.b.bloomRequests) 509 } 510 } 511 512 func (a *APIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 513 return a.blockChain().SubscribeLogsEvent(ch) 514 } 515 516 func (a *APIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { 517 //Arbitrum doesn't really need pending logs. Logs are published as soon as we know them.. 518 return a.SubscribeLogsEvent(ch) 519 } 520 521 func (a *APIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 522 return a.blockChain().SubscribeRemovedLogsEvent(ch) 523 } 524 525 func (a *APIBackend) ChainConfig() *params.ChainConfig { 526 return a.blockChain().Config() 527 } 528 529 func (a *APIBackend) Engine() consensus.Engine { 530 return a.blockChain().Engine() 531 } 532 533 func (b *APIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { 534 return nil, nil 535 } 536 537 func (b *APIBackend) FallbackClient() types.FallbackClient { 538 return b.fallbackClient 539 }