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