From 79b42c9dc01e493391cbafef06ed5744545f88fa Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Thu, 26 Jan 2023 16:34:52 +0700 Subject: [PATCH] e3: ots_getContractCreator (#6705) --- cmd/rpcdaemon/commands/debug_api_test.go | 13 +- cmd/rpcdaemon/commands/eth_receipts.go | 24 +++- cmd/rpcdaemon/commands/otterscan_api.go | 7 +- .../commands/otterscan_contract_creator.go | 130 +++++++++++++++++- .../commands/otterscan_generic_tracer.go | 43 +++++- cmd/rpcdaemon/commands/trace_filtering.go | 109 +++++++++------ core/state/temporal/kv_temporal.go | 52 +++---- go.mod | 2 +- go.sum | 4 +- 9 files changed, 281 insertions(+), 103 deletions(-) diff --git a/cmd/rpcdaemon/commands/debug_api_test.go b/cmd/rpcdaemon/commands/debug_api_test.go index f4d4058d13d..1bd2911e091 100644 --- a/cmd/rpcdaemon/commands/debug_api_test.go +++ b/cmd/rpcdaemon/commands/debug_api_test.go @@ -12,6 +12,7 @@ import ( "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/iter" "github.com/ledgerwatch/erigon-lib/kv/kvcache" + "github.com/ledgerwatch/erigon-lib/kv/order" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state/temporal" @@ -317,10 +318,10 @@ func TestMapTxNum2BlockNum(t *testing.T) { require.NoError(t, err) defer tx.Rollback() - txNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 1024, 0, false, -1) + txNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 1024, -1, order.Desc, -1) require.NoError(t, err) txNumsIter := MapDescendTxNum2BlockNum(tx, txNums) - expectTxNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 1024, 0, false, -1) + expectTxNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 1024, -1, order.Desc, -1) require.NoError(t, err) checkIter(t, expectTxNums, txNumsIter) }) @@ -329,10 +330,10 @@ func TestMapTxNum2BlockNum(t *testing.T) { require.NoError(t, err) defer tx.Rollback() - txNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, true, -1) + txNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, order.Asc, -1) require.NoError(t, err) txNumsIter := MapDescendTxNum2BlockNum(tx, txNums) - expectTxNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, true, -1) + expectTxNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, order.Asc, -1) require.NoError(t, err) checkIter(t, expectTxNums, txNumsIter) }) @@ -341,10 +342,10 @@ func TestMapTxNum2BlockNum(t *testing.T) { require.NoError(t, err) defer tx.Rollback() - txNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, true, 2) + txNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, order.Asc, 2) require.NoError(t, err) txNumsIter := MapDescendTxNum2BlockNum(tx, txNums) - expectTxNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, true, 2) + expectTxNums, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], 0, 1024, order.Asc, 2) require.NoError(t, err) checkIter(t, expectTxNums, txNumsIter) }) diff --git a/cmd/rpcdaemon/commands/eth_receipts.go b/cmd/rpcdaemon/commands/eth_receipts.go index eea2f2ed15c..b3c457e182e 100644 --- a/cmd/rpcdaemon/commands/eth_receipts.go +++ b/cmd/rpcdaemon/commands/eth_receipts.go @@ -15,6 +15,7 @@ import ( "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/bitmapdb" "github.com/ledgerwatch/erigon-lib/kv/iter" + "github.com/ledgerwatch/erigon-lib/kv/order" "github.com/ledgerwatch/erigon-lib/kv/rawdbv3" "github.com/ledgerwatch/log/v3" @@ -391,7 +392,7 @@ func (api *APIImpl) getLogsV3(ctx context.Context, tx kv.TemporalTx, begin, end if err != nil { return nil, err } - exec := newIntraBlockExec(tx, chainConfig, api.engine(), api._blockReader) + exec := txnExecutor(tx, chainConfig, api.engine(), api._blockReader, nil) var blockHash libcommon.Hash var header *types.Header @@ -464,6 +465,8 @@ type intraBlockExec struct { chainConfig *chain.Config evm *vm.EVM + tracer GenericTracer + // calculated by .changeBlock() blockHash libcommon.Hash blockNum uint64 @@ -474,18 +477,24 @@ type intraBlockExec struct { vmConfig *vm.Config } -func newIntraBlockExec(tx kv.TemporalTx, chainConfig *chain.Config, engine consensus.EngineReader, br services.FullBlockReader) *intraBlockExec { +func txnExecutor(tx kv.TemporalTx, chainConfig *chain.Config, engine consensus.EngineReader, br services.FullBlockReader, tracer GenericTracer) *intraBlockExec { stateReader := state.NewHistoryReaderV3() stateReader.SetTx(tx) - return &intraBlockExec{ + + ie := &intraBlockExec{ engine: engine, chainConfig: chainConfig, br: br, stateReader: stateReader, + tracer: tracer, evm: vm.NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chainConfig, vm.Config{}), vmConfig: &vm.Config{}, ibs: state.New(stateReader), } + if tracer != nil { + ie.vmConfig = &vm.Config{Debug: true, Tracer: tracer} + } + return ie } func (e *intraBlockExec) changeBlock(header *types.Header) { @@ -514,6 +523,11 @@ func (e *intraBlockExec) execTx(txNum uint64, txIndex int, txn types.Transaction if err != nil { return nil, nil, fmt.Errorf("%w: blockNum=%d, txNum=%d, %s", err, e.blockNum, txNum, e.ibs.Error()) } + if e.vmConfig.Tracer != nil { + if e.tracer.Found() { + e.tracer.SetTransaction(txn) + } + } return e.ibs.GetLogs(txHash), res, nil } @@ -534,7 +548,7 @@ func getTopicsBitmapV3(tx kv.TemporalTx, topics [][]libcommon.Hash, from, to uin var bitmapForORing iter.U64 = iter.Array[uint64]([]uint64{}) for _, topic := range sub { - it, err := tx.IndexRange(temporal.LogTopicIdx, topic.Bytes(), from, to, true, -1) + it, err := tx.IndexRange(temporal.LogTopicIdx, topic.Bytes(), int(from), int(to), order.Asc, -1) if err != nil { return nil, err } @@ -556,7 +570,7 @@ func getAddrsBitmapV3(tx kv.TemporalTx, addrs []libcommon.Address, from, to uint } var rx iter.U64 for _, addr := range addrs { - it, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], from, to, true, -1) + it, err := tx.IndexRange(temporal.LogAddrIdx, addr[:], int(from), int(to), true, -1) if err != nil { return nil, err } diff --git a/cmd/rpcdaemon/commands/otterscan_api.go b/cmd/rpcdaemon/commands/otterscan_api.go index ab0b7c59bcf..4869c845a83 100644 --- a/cmd/rpcdaemon/commands/otterscan_api.go +++ b/cmd/rpcdaemon/commands/otterscan_api.go @@ -12,6 +12,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/iter" + "github.com/ledgerwatch/erigon-lib/kv/order" "github.com/ledgerwatch/erigon-lib/kv/rawdbv3" "github.com/ledgerwatch/erigon/core/state/temporal" "github.com/ledgerwatch/log/v3" @@ -266,18 +267,18 @@ func (api *OtterscanAPIImpl) searchTransactionsBeforeV3(tx kv.TemporalTx, ctx co if err != nil { return nil, err } - itTo, err := tx.IndexRange(temporal.TracesToIdx, addr[:], from, 0, false, -1) + itTo, err := tx.IndexRange(temporal.TracesToIdx, addr[:], int(from), -1, order.Desc, -1) if err != nil { return nil, err } - itFrom, err := tx.IndexRange(temporal.TracesFromIdx, addr[:], from, 0, false, -1) + itFrom, err := tx.IndexRange(temporal.TracesFromIdx, addr[:], int(from), -1, order.Desc, -1) if err != nil { return nil, err } txNums := iter.Union[uint64](itFrom, itTo) txNumsIter := MapDescendTxNum2BlockNum(tx, txNums) - exec := newIntraBlockExec(tx, chainConfig, api.engine(), api._blockReader) + exec := txnExecutor(tx, chainConfig, api.engine(), api._blockReader, nil) var blockHash libcommon.Hash var header *types.Header txs := make([]*RPCTransaction, 0, pageSize) diff --git a/cmd/rpcdaemon/commands/otterscan_contract_creator.go b/cmd/rpcdaemon/commands/otterscan_contract_creator.go index 521eab7b8c9..eca330e87a6 100644 --- a/cmd/rpcdaemon/commands/otterscan_contract_creator.go +++ b/cmd/rpcdaemon/commands/otterscan_contract_creator.go @@ -7,9 +7,14 @@ import ( "sort" libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/cmp" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/bitmapdb" + "github.com/ledgerwatch/erigon-lib/kv/order" + "github.com/ledgerwatch/erigon-lib/kv/rawdbv3" "github.com/ledgerwatch/erigon-lib/kv/temporal/historyv2" + "github.com/ledgerwatch/erigon/core/state/temporal" + "github.com/ledgerwatch/erigon/eth/stagedsync/stages" "github.com/ledgerwatch/log/v3" "github.com/ledgerwatch/erigon/core/state" @@ -44,6 +49,123 @@ func (api *OtterscanAPIImpl) GetContractCreator(ctx context.Context, addr libcom return nil, nil } + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + + var acc accounts.Account + if api.historyV3(tx) { + ttx := tx.(kv.TemporalTx) + headNumber, err := stages.GetStageProgress(tx, stages.Execution) + if err != nil { + return nil, err + } + lastTxNum, _ := rawdbv3.TxNums.Max(tx, headNumber) + + // Contract; search for creation tx; navigate forward on AccountsHistory/ChangeSets + // + // We traversing history Index - because it's cheaper than traversing History + // and probe History periodically. In result will have small range of blocks. For binary search or full-scan. + // + // popular contracts may have dozens of states changes due to ETH deposits/withdraw after contract creation, + // so it is optimal to search from the beginning even if the contract has multiple + // incarnations. + var prevTxnID, nextTxnID uint64 + it, err := ttx.IndexRange(temporal.AccountsHistoryIdx, addr[:], 0, int(lastTxNum+1), order.Asc, -1) + if err != nil { + return nil, err + } + for i := 0; it.HasNext(); i++ { + txnID, _ := it.Next() + + if i%4096 != 0 { // probe history periodically, not on every change + nextTxnID = txnID + continue + } + + v, ok, err := ttx.HistoryGet(temporal.AccountsHistory, addr[:], txnID) + if err != nil { + log.Error("Unexpected error, couldn't find changeset", "txNum", i, "addr", addr) + panic(err) + } + if !ok { + err = fmt.Errorf("couldn't find history txnID=%v addr=%v", txnID, addr) + log.Error("[rpc] Unexpected error", "err", err) + return nil, err + } + if len(v) == 0 { // creation, but maybe not our Incarnation + prevTxnID = txnID + continue + } + + if err := acc.DecodeForStorage(v); err != nil { + return nil, err + } + // Found the shard where the incarnation change happens; ignore all next index values + if acc.Incarnation >= plainStateAcc.Incarnation { + nextTxnID = txnID + break + } + prevTxnID = txnID + } + + // The sort.Search function finds the first block where the incarnation has + // changed to the desired one, so we get the previous block from the bitmap; + // however if the creationTxnID block is already the first one from the bitmap, it means + // the block we want is the max block from the previous shard. + var creationTxnID uint64 + var searchErr error + + if nextTxnID == 0 { + nextTxnID = prevTxnID + 1 + } + // Binary search in [prevTxnID, nextTxnID] range; get first block where desired incarnation appears + // can be replaced by full-scan over ttx.HistoryRange([prevTxnID, nextTxnID])? + _ = sort.Search(int(nextTxnID-prevTxnID), func(i int) bool { + txnID := uint64(i) + prevTxnID + v, ok, err := ttx.HistoryGet(temporal.AccountsHistory, addr[:], txnID) + if err != nil { + log.Error("[rpc] Unexpected error, couldn't find changeset", "txNum", i, "addr", addr) + panic(err) + } + if !ok { + return false + } + if len(v) == 0 { + creationTxnID = cmp.Max(creationTxnID, txnID) + return false + } + + if err := acc.DecodeForStorage(v); err != nil { + searchErr = err + return false + } + if acc.Incarnation < plainStateAcc.Incarnation { + creationTxnID = cmp.Max(creationTxnID, txnID) + return false + } + return true + }) + if searchErr != nil { + return nil, searchErr + } + + _, bn, _ := rawdbv3.TxNums.FindBlockNum(tx, creationTxnID) + minTxNum, _ := rawdbv3.TxNums.Min(tx, bn) + txIndex := creationTxnID - minTxNum - 1 /* system-contract */ + + // Trace block, find tx and contract creator + tracer := NewCreateTracer(ctx, addr) + if err := api.genericTracer(tx, ctx, bn, creationTxnID, txIndex, chainConfig, tracer); err != nil { + return nil, err + } + return &ContractCreatorData{ + Tx: tracer.Tx.Hash(), + Creator: tracer.Creator, + }, nil + } + // Contract; search for creation tx; navigate forward on AccountsHistory/ChangeSets // // We search shards in forward order on purpose because popular contracts may have @@ -73,7 +195,6 @@ func (api *OtterscanAPIImpl) GetContractCreator(ctx context.Context, addr libcom return nil, fmt.Errorf("could't find any shard for account history addr=%v", addr) } - var acc accounts.Account bm := bitmapdb.NewBitmap64() defer bitmapdb.ReturnToPool64(bm) prevShardMaxBl := uint64(0) @@ -153,14 +274,9 @@ func (api *OtterscanAPIImpl) GetContractCreator(ctx context.Context, addr libcom if r > 0 { blockFound = blocks[r-1] } - // Trace block, find tx and contract creator - chainConfig, err := api.chainConfig(tx) - if err != nil { - return nil, err - } tracer := NewCreateTracer(ctx, addr) - if err := api.genericTracer(tx, ctx, blockFound, chainConfig, tracer); err != nil { + if err := api.genericTracer(tx, ctx, blockFound, 0, 0, chainConfig, tracer); err != nil { return nil, err } diff --git a/cmd/rpcdaemon/commands/otterscan_generic_tracer.go b/cmd/rpcdaemon/commands/otterscan_generic_tracer.go index cb6cd3d065e..78faef80517 100644 --- a/cmd/rpcdaemon/commands/otterscan_generic_tracer.go +++ b/cmd/rpcdaemon/commands/otterscan_generic_tracer.go @@ -22,16 +22,38 @@ type GenericTracer interface { Found() bool } -func (api *OtterscanAPIImpl) genericTracer(dbtx kv.Tx, ctx context.Context, blockNum uint64, chainConfig *chain.Config, tracer GenericTracer) error { - block, err := api.blockByNumberWithSenders(dbtx, blockNum) - if err != nil { - return err - } - if block == nil { +func (api *OtterscanAPIImpl) genericTracer(dbtx kv.Tx, ctx context.Context, blockNum, txnID, txIndex uint64, chainConfig *chain.Config, tracer GenericTracer) error { + if api.historyV3(dbtx) { + ttx := dbtx.(kv.TemporalTx) + executor := txnExecutor(ttx, chainConfig, api.engine(), api._blockReader, tracer) + + // if block number changed, calculate all related field + header, err := api._blockReader.HeaderByNumber(ctx, ttx, blockNum) + if err != nil { + return err + } + if header == nil { + log.Warn("[rpc] header is nil", "blockNum", blockNum) + return nil + } + executor.changeBlock(header) + + txn, err := api._txnReader.TxnByIdxInBlock(ctx, ttx, blockNum, int(txIndex)) + if err != nil { + return err + } + if txn == nil { + log.Warn("[rpc] tx is nil", "blockNum", blockNum, "txIndex", txIndex) + return nil + } + _, _, err = executor.execTx(txnID, int(txIndex), txn) + if err != nil { + return err + } return nil } - reader, err := rpchelper.CreateHistoryStateReader(dbtx, blockNum, 0, api.historyV3(dbtx), chainConfig.ChainName) + reader, err := rpchelper.CreateHistoryStateReader(dbtx, blockNum, txIndex, api.historyV3(dbtx), chainConfig.ChainName) if err != nil { return err } @@ -51,6 +73,13 @@ func (api *OtterscanAPIImpl) genericTracer(dbtx kv.Tx, ctx context.Context, bloc return h } engine := api.engine() + block, err := api.blockByNumberWithSenders(dbtx, blockNum) + if err != nil { + return err + } + if block == nil { + return nil + } header := block.Header() rules := chainConfig.Rules(block.NumberU64(), header.Time) diff --git a/cmd/rpcdaemon/commands/trace_filtering.go b/cmd/rpcdaemon/commands/trace_filtering.go index 5158a0fd4ee..014efb37f6d 100644 --- a/cmd/rpcdaemon/commands/trace_filtering.go +++ b/cmd/rpcdaemon/commands/trace_filtering.go @@ -12,6 +12,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/bitmapdb" + "github.com/ledgerwatch/erigon-lib/kv/order" "github.com/ledgerwatch/erigon-lib/kv/rawdbv3" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/hexutil" @@ -240,63 +241,87 @@ func traceFilterBitmaps(tx kv.Tx, req TraceFilterRequest, from, to uint64) (from toAddresses = make(map[libcommon.Address]struct{}, len(req.ToAddress)) allBlocks = roaring64.New() var blocksTo roaring64.Bitmap - if ttx, casted := tx.(kv.TemporalTx); casted { - for _, addr := range req.FromAddress { - if addr != nil { - it, err := ttx.IndexRange(temporal.TracesFromIdx, addr.Bytes(), from, to, true, -1) + for _, addr := range req.FromAddress { + if addr != nil { + b, err := bitmapdb.Get64(tx, kv.CallFromIndex, addr.Bytes(), from, to) + if err != nil { if errors.Is(err, ethdb.ErrKeyNotFound) { continue } - b, err := it.(bitmapdb.ToBitmap).ToBitmap() - if err != nil { - return nil, nil, nil, err - } - allBlocks.Or(b) - fromAddresses[*addr] = struct{}{} + return nil, nil, nil, err } + allBlocks.Or(b) + fromAddresses[*addr] = struct{}{} } + } - for _, addr := range req.ToAddress { - if addr != nil { - it, err := ttx.IndexRange(temporal.TracesToIdx, addr.Bytes(), from, to, true, -1) + for _, addr := range req.ToAddress { + if addr != nil { + b, err := bitmapdb.Get64(tx, kv.CallToIndex, addr.Bytes(), from, to) + if err != nil { if errors.Is(err, ethdb.ErrKeyNotFound) { continue } - b, err := it.(bitmapdb.ToBitmap).ToBitmap() - if err != nil { - return nil, nil, nil, err - } - blocksTo.Or(b) - toAddresses[*addr] = struct{}{} + return nil, nil, nil, err } + blocksTo.Or(b) + toAddresses[*addr] = struct{}{} } + } + + switch req.Mode { + case TraceFilterModeIntersection: + allBlocks.And(&blocksTo) + case TraceFilterModeUnion: + fallthrough + default: + allBlocks.Or(&blocksTo) + } + + // Special case - if no addresses specified, take all traces + if len(req.FromAddress) == 0 && len(req.ToAddress) == 0 { + allBlocks.AddRange(from, to) } else { - for _, addr := range req.FromAddress { - if addr != nil { - b, err := bitmapdb.Get64(tx, kv.CallFromIndex, addr.Bytes(), from, to) - if err != nil { - if errors.Is(err, ethdb.ErrKeyNotFound) { - continue - } - return nil, nil, nil, err - } - allBlocks.Or(b) - fromAddresses[*addr] = struct{}{} + allBlocks.RemoveRange(0, from) + allBlocks.RemoveRange(to, uint64(0x100000000)) + } + + return fromAddresses, toAddresses, allBlocks, nil +} + +func traceFilterBitmapsV3(tx kv.TemporalTx, req TraceFilterRequest, from, to uint64) (fromAddresses, toAddresses map[libcommon.Address]struct{}, allBlocks *roaring64.Bitmap, err error) { + fromAddresses = make(map[libcommon.Address]struct{}, len(req.FromAddress)) + toAddresses = make(map[libcommon.Address]struct{}, len(req.ToAddress)) + allBlocks = roaring64.New() + var blocksTo roaring64.Bitmap + + for _, addr := range req.FromAddress { + if addr != nil { + it, err := tx.IndexRange(temporal.TracesFromIdx, addr.Bytes(), int(from), int(to), order.Asc, -1) + if errors.Is(err, ethdb.ErrKeyNotFound) { + continue + } + b, err := it.(bitmapdb.ToBitmap).ToBitmap() + if err != nil { + return nil, nil, nil, err } + allBlocks.Or(b) + fromAddresses[*addr] = struct{}{} } + } - for _, addr := range req.ToAddress { - if addr != nil { - b, err := bitmapdb.Get64(tx, kv.CallToIndex, addr.Bytes(), from, to) - if err != nil { - if errors.Is(err, ethdb.ErrKeyNotFound) { - continue - } - return nil, nil, nil, err - } - blocksTo.Or(b) - toAddresses[*addr] = struct{}{} + for _, addr := range req.ToAddress { + if addr != nil { + it, err := tx.IndexRange(temporal.TracesToIdx, addr.Bytes(), int(from), int(to), order.Asc, -1) + if errors.Is(err, ethdb.ErrKeyNotFound) { + continue + } + b, err := it.(bitmapdb.ToBitmap).ToBitmap() + if err != nil { + return nil, nil, nil, err } + blocksTo.Or(b) + toAddresses[*addr] = struct{}{} } } @@ -578,7 +603,7 @@ func (api *TraceAPIImpl) filterV3(ctx context.Context, dbtx kv.TemporalTx, fromB return err } toTxNum++ //+1 because internally Erigon using semantic [from, to), but some RPC have different semantic - fromAddresses, toAddresses, allTxs, err := traceFilterBitmaps(dbtx, req, fromTxNum, toTxNum) + fromAddresses, toAddresses, allTxs, err := traceFilterBitmapsV3(dbtx, req, fromTxNum, toTxNum) if err != nil { return err } diff --git a/core/state/temporal/kv_temporal.go b/core/state/temporal/kv_temporal.go index ef9d14015af..4cb6f05fb4c 100644 --- a/core/state/temporal/kv_temporal.go +++ b/core/state/temporal/kv_temporal.go @@ -137,6 +137,10 @@ const ( ) const ( + AccountsHistoryIdx kv.InvertedIdx = "AccountsHistoryIdx" + StorageHistoryIdx kv.InvertedIdx = "StorageHistoryIdx" + CodeHistoryIdx kv.InvertedIdx = "CodeHistoryIdx" + LogTopicIdx kv.InvertedIdx = "LogTopicIdx" LogAddrIdx kv.InvertedIdx = "LogAddrIdx" TracesFromIdx kv.InvertedIdx = "TracesFromIdx" @@ -271,42 +275,30 @@ type Cursor struct { hitoryV3 bool } -func (tx *Tx) IndexRange(name kv.InvertedIdx, key []byte, fromTs, toTs uint64, asc order.By, limit int) (timestamps iter.U64, err error) { - return tx.IndexStream(name, key, fromTs, toTs, asc, limit) -} - -// [fromTs, toTs) -func (tx *Tx) IndexStream(name kv.InvertedIdx, key []byte, fromTs, toTs uint64, asc order.By, limit int) (timestamps iter.U64, err error) { +func (tx *Tx) IndexRange(name kv.InvertedIdx, k []byte, fromTs, toTs int, asc order.By, limit int) (timestamps iter.U64, err error) { switch name { + case AccountsHistoryIdx: + timestamps, err = tx.agg.AccountHistoyIdxIterator(k, fromTs, toTs, asc, limit, tx) + case StorageHistoryIdx: + timestamps, err = tx.agg.StorageHistoyIdxIterator(k, fromTs, toTs, asc, limit, tx) + case CodeHistoryIdx: + timestamps, err = tx.agg.CodeHistoyIdxIterator(k, fromTs, toTs, asc, limit, tx) case LogTopicIdx: - t, err := tx.agg.LogTopicIterator(key, fromTs, toTs, asc, limit, tx) - if err != nil { - return nil, err - } - tx.resourcesToClose = append(tx.resourcesToClose, t) - return t, nil + timestamps, err = tx.agg.LogTopicIterator(k, fromTs, toTs, asc, limit, tx) case LogAddrIdx: - t, err := tx.agg.LogAddrIterator(key, fromTs, toTs, asc, limit, tx) - if err != nil { - return nil, err - } - tx.resourcesToClose = append(tx.resourcesToClose, t) - return t, nil + timestamps, err = tx.agg.LogAddrIterator(k, fromTs, toTs, asc, limit, tx) case TracesFromIdx: - t, err := tx.agg.TraceFromIterator(key, fromTs, toTs, asc, limit, tx) - if err != nil { - return nil, err - } - tx.resourcesToClose = append(tx.resourcesToClose, t) - return t, nil + timestamps, err = tx.agg.TraceFromIterator(k, fromTs, toTs, asc, limit, tx) case TracesToIdx: - t, err := tx.agg.TraceToIterator(key, fromTs, toTs, asc, limit, tx) - if err != nil { - return nil, err - } - tx.resourcesToClose = append(tx.resourcesToClose, t) - return t, nil + timestamps, err = tx.agg.TraceToIterator(k, fromTs, toTs, asc, limit, tx) default: return nil, fmt.Errorf("unexpected history name: %s", name) } + if err != nil { + return nil, err + } + if closer, ok := timestamps.(kv.Closer); ok { + tx.resourcesToClose = append(tx.resourcesToClose, closer) + } + return timestamps, nil } diff --git a/go.mod b/go.mod index 3ff61e729d7..79704871b1f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ledgerwatch/erigon go 1.18 require ( - github.com/ledgerwatch/erigon-lib v0.0.0-20230126034024-fd7c9ab148df + github.com/ledgerwatch/erigon-lib v0.0.0-20230126091935-5b0b4800f3d7 github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20230120022649-cd9409a200da github.com/ledgerwatch/log/v3 v3.7.0 github.com/ledgerwatch/secp256k1 v1.0.0 diff --git a/go.sum b/go.sum index 248f0f4f131..f9ccc2da6f6 100644 --- a/go.sum +++ b/go.sum @@ -555,8 +555,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3PYPwICLl+/9oulQauOuETfgFvhBDffs0= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/ledgerwatch/erigon-lib v0.0.0-20230126034024-fd7c9ab148df h1:J5SVVdaAaHNkhdo4YK5UR015514O9tWQQv0ycAHVeD8= -github.com/ledgerwatch/erigon-lib v0.0.0-20230126034024-fd7c9ab148df/go.mod h1:dv/j9yNeEs4+HYq/x6/g2DVUGKBsRuB3yeVsWuuFH1U= +github.com/ledgerwatch/erigon-lib v0.0.0-20230126091935-5b0b4800f3d7 h1:REPNO8VhnIqfAae8MFpS7m5qSm3Kj7OcK01cpilzdRM= +github.com/ledgerwatch/erigon-lib v0.0.0-20230126091935-5b0b4800f3d7/go.mod h1:dv/j9yNeEs4+HYq/x6/g2DVUGKBsRuB3yeVsWuuFH1U= github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20230120022649-cd9409a200da h1:lQQBOHzAUThkymfXJj/m07vAjyMx9XoMMy3OomaeOrA= github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20230120022649-cd9409a200da/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo= github.com/ledgerwatch/log/v3 v3.7.0 h1:aFPEZdwZx4jzA3+/Pf8wNDN5tCI0cIolq/kfvgcM+og=