1 Star 0 Fork 0

Sole / erigon-etl

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

Erigon-etl

Based on erigon and erigon-lib, parsing the full-node data from erigon clients.

Pre(Required)

Replace the accessors_chain.go ReadBody function

//github.com/erigon/core/rawdb/accessors_chain.go
func ReadBody(db kv.Getter, hash common.Hash, number uint64) (*types.Body, uint64, uint32) {
	data := ReadStorageBodyRLP(db, hash, number)
	if len(data) == 0 {
		return nil, 0, 0
	}
	bodyForStorage := new(types.BodyForStorage)
	err := rlp.DecodeBytes(data, bodyForStorage)
	if err != nil {
		log.Error("Invalid block body RLP", "hash", hash, "err", err)
		return nil, 0, 0
	}
	body := new(types.Body)
	body.Uncles = bodyForStorage.Uncles

	return body, bodyForStorage.BaseTxId + 1, bodyForStorage.TxAmount
}

Add the trace-filtering.go FilterWithoutStream function

// github.com/erigon/cmd/rpcdaemon/commands/trace_filtering.go
func (api *TraceAPIImpl) FilterWithoutStream(ctx context.Context, req TraceFilterRequest) ([][]byte, error) {
	dbtx, err1 := api.kv.BeginRo(ctx)
	if err1 != nil {
		return nil, fmt.Errorf("traceFilter cannot open tx: %w", err1)
	}
	defer dbtx.Rollback()

	var fromBlock uint64
	var toBlock uint64
	if req.FromBlock == nil {
		fromBlock = 0
	} else {
		fromBlock = uint64(*req.FromBlock)
	}

	if req.ToBlock == nil {
		headNumber := rawdb.ReadHeaderNumber(dbtx, rawdb.ReadHeadHeaderHash(dbtx))
		toBlock = *headNumber
	} else {
		toBlock = uint64(*req.ToBlock)
	}

	if fromBlock > toBlock {
		return nil, fmt.Errorf("invalid parameters: fromBlock cannot be greater than toBlock")
	}

	fromAddresses := make(map[common.Address]struct{}, len(req.FromAddress))
	toAddresses := make(map[common.Address]struct{}, len(req.ToAddress))

	var (
		allBlocks roaring64.Bitmap
		blocksTo  roaring64.Bitmap
	)

	for _, addr := range req.FromAddress {
		if addr != nil {
			b, err := bitmapdb.Get64(dbtx, kv.CallFromIndex, addr.Bytes(), fromBlock, toBlock)
			if err != nil {
				if errors.Is(err, ethdb.ErrKeyNotFound) {
					continue
				}
				return nil, err
			}
			allBlocks.Or(b)
			fromAddresses[*addr] = struct{}{}
		}
	}

	for _, addr := range req.ToAddress {
		if addr != nil {
			b, err := bitmapdb.Get64(dbtx, kv.CallToIndex, addr.Bytes(), fromBlock, toBlock)
			if err != nil {
				if errors.Is(err, ethdb.ErrKeyNotFound) {
					continue
				}
				return 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(fromBlock, toBlock+1)
	} else {
		allBlocks.RemoveRange(0, fromBlock)
		allBlocks.RemoveRange(toBlock+1, uint64(0x100000000))
	}

	chainConfig, err := api.chainConfig(dbtx)
	if err != nil {
		return nil, err
	}

	var json = jsoniter.ConfigCompatibleWithStandardLibrary
	first := true
	// Execute all transactions in picked blocks

	count := uint64(^uint(0)) // this just makes it easier to use below
	if req.Count != nil {
		count = *req.Count
	}
	after := uint64(0) // this just makes it easier to use below
	if req.After != nil {
		after = *req.After
	}
	nSeen := uint64(0)
	nExported := uint64(0)

	it := allBlocks.Iterator()
	for it.HasNext() {
		b := uint64(it.Next())
		// Extract transactions from block
		hash, hashErr := rawdb.ReadCanonicalHash(dbtx, b)
		if hashErr != nil {
			return nil, hashErr
		}

		block, bErr := api.blockWithSenders(dbtx, hash, b)
		if bErr != nil {
			return nil, bErr
		}
		if block == nil {
			return nil, fmt.Errorf("could not find block %x %d", hash, b)
		}

		blockHash := block.Hash()
		blockNumber := block.NumberU64()
		txs := block.Transactions()
		t, tErr := api.callManyTransactions(ctx, dbtx, txs, []string{TraceTypeTrace}, block.ParentHash(), rpc.BlockNumber(block.NumberU64()-1), block.Header(), -1 /* all tx indices */, types.MakeSigner(chainConfig, b))
		if tErr != nil {
			return nil, tErr
		}
		includeAll := len(fromAddresses) == 0 && len(toAddresses) == 0
		tracesResultBytes := make([][]byte, 0)
		for i, trace := range t {
			txPosition := uint64(i)
			txHash := txs[i].Hash()
			// Check if transaction concerns any of the addresses we wanted
			for _, pt := range trace.Trace {
				if includeAll || filter_trace(pt, fromAddresses, toAddresses) {
					nSeen++
					pt.BlockHash = &blockHash
					pt.BlockNumber = &blockNumber
					pt.TransactionHash = &txHash
					pt.TransactionPosition = &txPosition
					b, err := json.Marshal(pt)
					if err != nil {
						return nil, err
					}
					if nSeen > after && nExported < count {
						if first {
							first = false
						}
						tracesResultBytes = append(tracesResultBytes, b)
						nExported++
					}
				}
			}
		}
		minerReward, uncleRewards := ethash.AccumulateRewards(chainConfig, block.Header(), block.Uncles())
		if _, ok := toAddresses[block.Coinbase()]; ok || includeAll {
			nSeen++
			var tr ParityTrace
			var rewardAction = &RewardTraceAction{}
			rewardAction.Author = block.Coinbase()
			rewardAction.RewardType = "block" // nolint: goconst
			rewardAction.Value.ToInt().Set(minerReward.ToBig())
			tr.Action = rewardAction
			tr.BlockHash = &common.Hash{}
			copy(tr.BlockHash[:], block.Hash().Bytes())
			tr.BlockNumber = new(uint64)
			*tr.BlockNumber = block.NumberU64()
			tr.Type = "reward" // nolint: goconst
			tr.TraceAddress = []int{}
			b, err := json.Marshal(tr)
			if err != nil {
				return nil, err
			}
			if nSeen > after && nExported < count {
				if first {
					first = false
				}
				tracesResultBytes = append(tracesResultBytes, b)
				nExported++
			}
		}
		for i, uncle := range block.Uncles() {
			if _, ok := toAddresses[uncle.Coinbase]; ok || includeAll {
				if i < len(uncleRewards) {
					nSeen++
					var tr ParityTrace
					rewardAction := &RewardTraceAction{}
					rewardAction.Author = uncle.Coinbase
					rewardAction.RewardType = "uncle" // nolint: goconst
					rewardAction.Value.ToInt().Set(uncleRewards[i].ToBig())
					tr.Action = rewardAction
					tr.BlockHash = &common.Hash{}
					copy(tr.BlockHash[:], block.Hash().Bytes())
					tr.BlockNumber = new(uint64)
					*tr.BlockNumber = block.NumberU64()
					tr.Type = "reward" // nolint: goconst
					tr.TraceAddress = []int{}
					b, err := json.Marshal(tr)
					if err != nil {
						return nil, err
					}
					if nSeen > after && nExported < count {
						if first {
							first = false
						}
						tracesResultBytes = append(tracesResultBytes, b)
						nExported++
					}
				}
			}
		}
	}
	return tracesResultBytes, nil
}

Build

require:

go 1.18+

Linux platform

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./dist/bin/erigon-etl

Windows platform

SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -o .\dist\bin\erigon-etl

Run

Export blocks and transactions

erigon-etl export_blocks_and_transactions --start-block 0 --end-block 1000 \
--blocks-output blocks.csv --transactions-output transactions.csv \
--provider-file ./mdbx.dat

Export token transfers

erigon-etl export_token_transfers --start-block 0 --end-block 1000 \
--output transfers.csv --provider-file ./mdbx.dat

Export traces

erigon-etl export_traces --start-block 0 --end-block 1000 \
--output transfers.csv --provider-file ./mdbx.dat

空文件

简介

Erigon-ETL Based on Erigon(3th popularity ethereum client) to Fetch Data From File to CSV 展开 收起
Go 等 3 种语言
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Go
1
https://gitee.com/mchen19/erigon-etl.git
git@gitee.com:mchen19/erigon-etl.git
mchen19
erigon-etl
erigon-etl
master

搜索帮助