diff --git a/backend/.golangci.yml b/backend/.golangci.yml index ae3da8aff..d50264057 100644 --- a/backend/.golangci.yml +++ b/backend/.golangci.yml @@ -124,9 +124,6 @@ linters-settings: - "!**/pkg/exporter/modules/eth1.go" allow: - $gostd - deny: - - pkg: github.com/prysmaticlabs/prysm/v3 - desc: "Depending on your needs you might find something here https://github.com/wealdtech" main-logging: list-mode: lax # allow unless explicitely denied files: diff --git a/backend/cmd/evm_node_indexer/main.go b/backend/cmd/evm_node_indexer/main.go index 670e0c185..ec277fafb 100644 --- a/backend/cmd/evm_node_indexer/main.go +++ b/backend/cmd/evm_node_indexer/main.go @@ -3,7 +3,6 @@ package evm_node_indexer // imports import ( "bytes" - "compress/gzip" "context" "database/sql" "encoding/binary" @@ -19,7 +18,6 @@ import ( "sync/atomic" "time" - gcp_bigtable "cloud.google.com/go/bigtable" "github.com/ethereum/go-ethereum" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -29,7 +27,8 @@ import ( "google.golang.org/api/option" "github.com/gobitfly/beaconchain/pkg/commons/db" - "github.com/gobitfly/beaconchain/pkg/commons/hexutil" + "github.com/gobitfly/beaconchain/pkg/commons/db2/database" + "github.com/gobitfly/beaconchain/pkg/commons/db2/raw" "github.com/gobitfly/beaconchain/pkg/commons/log" "github.com/gobitfly/beaconchain/pkg/commons/metrics" "github.com/gobitfly/beaconchain/pkg/commons/types" @@ -40,15 +39,6 @@ import ( // defines const MAX_EL_BLOCK_NUMBER = int64(1_000_000_000_000 - 1) -const BT_COLUMNFAMILY_BLOCK = "b" -const BT_COLUMN_BLOCK = "b" -const BT_COLUMNFAMILY_RECEIPTS = "r" -const BT_COLUMN_RECEIPTS = "r" -const BT_COLUMNFAMILY_TRACES = "t" -const BT_COLUMN_TRACES = "t" -const BT_COLUMNFAMILY_UNCLES = "u" -const BT_COLUMN_UNCLES = "u" - const MAINNET_CHAINID = 1 const GOERLI_CHAINID = 5 const OPTIMISM_CHAINID = 10 @@ -68,17 +58,7 @@ const TRY_TO_RECOVER_ON_ERROR_COUNT = 8 // total retries, so with a value of 4, type jsonRpcReturnId struct { Id int64 `json:"id"` } -type fullBlockRawData struct { - blockNumber int64 - blockHash hexutil.Bytes - blockUnclesCount int - blockTxs []string - - blockCompressed hexutil.Bytes - receiptsCompressed hexutil.Bytes - tracesCompressed hexutil.Bytes - unclesCompressed hexutil.Bytes -} + type intRange struct { start int64 end int64 @@ -221,17 +201,14 @@ func Run() { log.Info("starting postgres completed") } - // init bigtable log.Info("init BT...") - btClient, err := gcp_bigtable.NewClient(context.Background(), utils.Config.Bigtable.Project, utils.Config.Bigtable.Instance, option.WithGRPCConnectionPool(1)) + bt, err := database.NewBigTable(utils.Config.Bigtable.Project, utils.Config.Bigtable.Instance, nil, option.WithGRPCConnectionPool(1)) if err != nil { log.Fatal(err, "creating new client for Bigtable", 0) // fatal, no point to continue without BT } - tableBlocksRaw := btClient.Open("blocks-raw") - if tableBlocksRaw == nil { - log.Fatal(err, "open blocks-raw table", 0) // fatal, no point to continue without BT - } - defer btClient.Close() + defer bt.Close() + + tableBlocksRaw := raw.NewStore(database.Wrap(bt, raw.Table)) log.Info("...init BT done.") // init el client @@ -344,9 +321,9 @@ func Run() { } // fill array with block numbers to check - blockRawData := make([]fullBlockRawData, l) + blockRawData := make([]raw.FullBlockData, l) for i := int64(0); i < l; i++ { - blockRawData[i].blockNumber = latestPGBlock + i - l + 1 + blockRawData[i].BlockNumber = latestPGBlock + i - l + 1 } // get all hashes from node @@ -387,20 +364,20 @@ func Run() { var i int var failCounter int for _, v := range blockRawData { - for i < matchingLength && v.blockNumber > matchingHashesBlockIdList[i] { + for i < matchingLength && v.BlockNumber > matchingHashesBlockIdList[i] { i++ } - if i >= matchingLength || v.blockNumber != matchingHashesBlockIdList[i] { + if i >= matchingLength || v.BlockNumber != matchingHashesBlockIdList[i] { failCounter++ if wrongHashRanges[wrongHashRangesIndex].start < 0 { - wrongHashRanges[wrongHashRangesIndex].start = v.blockNumber - wrongHashRanges[wrongHashRangesIndex].end = v.blockNumber - } else if wrongHashRanges[wrongHashRangesIndex].end+1 == v.blockNumber { - wrongHashRanges[wrongHashRangesIndex].end = v.blockNumber + wrongHashRanges[wrongHashRangesIndex].start = v.BlockNumber + wrongHashRanges[wrongHashRangesIndex].end = v.BlockNumber + } else if wrongHashRanges[wrongHashRangesIndex].end+1 == v.BlockNumber { + wrongHashRanges[wrongHashRangesIndex].end = v.BlockNumber } else { wrongHashRangesIndex++ - wrongHashRanges[wrongHashRangesIndex].start = v.blockNumber - wrongHashRanges[wrongHashRangesIndex].end = v.blockNumber + wrongHashRanges[wrongHashRangesIndex].start = v.BlockNumber + wrongHashRanges[wrongHashRangesIndex].end = v.BlockNumber } } } @@ -470,7 +447,7 @@ func Run() { } // improve the behaviour in case of an error -func _bulkExportBlocksHandler(tableBlocksRaw *gcp_bigtable.Table, blockRawData []fullBlockRawData, nodeRequestsAtOnce int64, deep int) error { +func _bulkExportBlocksHandler(tableBlocksRaw raw.Store, blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64, deep int) error { err := _bulkExportBlocksImpl(tableBlocksRaw, blockRawData, nodeRequestsAtOnce) if err != nil { if deep < TRY_TO_RECOVER_ON_ERROR_COUNT { @@ -480,9 +457,9 @@ func _bulkExportBlocksHandler(tableBlocksRaw *gcp_bigtable.Table, blockRawData [ { s := errorIdentifier.FindStringSubmatch(err.Error()) if len(s) >= 2 { // if we have a valid json error available, should be the case if it's a node issue - log.WarnWithFields(log.Fields{"deep": deep, "cause": s[1], "0block": blockRawData[0].blockNumber, "elements": elementCount}, "got an error and will try to fix it (sub)") + log.WarnWithFields(log.Fields{"deep": deep, "cause": s[1], "0block": blockRawData[0].BlockNumber, "elements": elementCount}, "got an error and will try to fix it (sub)") } else { // if we have a no json error available, should be the case if it's a BT or Postgres issue - log.WarnWithFields(log.Fields{"deep": deep, "cause": err, "0block": blockRawData[0].blockNumber, "elements": elementCount}, "got an error and will try to fix it (err)") + log.WarnWithFields(log.Fields{"deep": deep, "cause": err, "0block": blockRawData[0].BlockNumber, "elements": elementCount}, "got an error and will try to fix it (err)") } } @@ -512,13 +489,9 @@ func _bulkExportBlocksHandler(tableBlocksRaw *gcp_bigtable.Table, blockRawData [ } // export all blocks, heavy use of bulk & concurrency, providing a block raw data array (used by the other bulkExportBlocks+ functions) -func _bulkExportBlocksImpl(tableBlocksRaw *gcp_bigtable.Table, blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func _bulkExportBlocksImpl(tableBlocksRaw raw.Store, blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check values { - if tableBlocksRaw == nil { - return fmt.Errorf("tableBlocksRaw == nil") - } - l := int64(len(blockRawData)) if l < 1 || l > nodeRequestsAtOnce { return fmt.Errorf("blockRawData length (%d) is 0 or greater 'node requests at once' (%d)", l, nodeRequestsAtOnce) @@ -544,45 +517,12 @@ func _bulkExportBlocksImpl(tableBlocksRaw *gcp_bigtable.Table, blockRawData []fu } // write to bigtable - { - // prepare array - muts := []*gcp_bigtable.Mutation{} - keys := []string{} - for _, v := range blockRawData { - if len(v.blockCompressed) == 0 || len(v.tracesCompressed) == 0 { - log.Fatal(nil, "tried writing empty data to BT", 0, map[string]interface{}{"len(v.blockCompressed)": len(v.blockCompressed), "len(v.receiptsCompressed)": len(v.receiptsCompressed), "len(v.tracesCompressed)": len(v.tracesCompressed)}) // fatal, as if this is not working in the first place, it will never work - } - mut := gcp_bigtable.NewMutation() - mut.Set(BT_COLUMNFAMILY_BLOCK, BT_COLUMN_BLOCK, gcp_bigtable.Timestamp(0), v.blockCompressed) - if len(v.receiptsCompressed) < 1 { - log.Warnf("empty receipts at block %d lRec %d lTxs %d", v.blockNumber, len(v.receiptsCompressed), len(v.blockTxs)) - } - mut.Set(BT_COLUMNFAMILY_RECEIPTS, BT_COLUMN_RECEIPTS, gcp_bigtable.Timestamp(0), v.receiptsCompressed) - mut.Set(BT_COLUMNFAMILY_TRACES, BT_COLUMN_TRACES, gcp_bigtable.Timestamp(0), v.tracesCompressed) - if v.blockUnclesCount > 0 { - mut.Set(BT_COLUMNFAMILY_UNCLES, BT_COLUMN_UNCLES, gcp_bigtable.Timestamp(0), v.unclesCompressed) - } - muts = append(muts, mut) - keys = append(keys, fmt.Sprintf("%d:%12d", utils.Config.Chain.Id, MAX_EL_BLOCK_NUMBER-v.blockNumber)) - } - - // write - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - - var errs []error - errs, err = tableBlocksRaw.ApplyBulk(ctx, keys, muts) - if err != nil { - return fmt.Errorf("tableBlocksRaw.ApplyBulk err: %w", err) - } - for i, e := range errs { - return fmt.Errorf("tableBlocksRaw.ApplyBulk errs(%d): %w", i, e) - } + if err := tableBlocksRaw.AddBlocks(blockRawData); err != nil { + return fmt.Errorf("tableBlocksRaw.ApplyBulk err: %w", err) } // write to SQL - err = psqlAddElements(blockRawData) - if err != nil { + if err := psqlAddElements(blockRawData); err != nil { return fmt.Errorf("psqlAddElements: %w", err) } @@ -590,7 +530,7 @@ func _bulkExportBlocksImpl(tableBlocksRaw *gcp_bigtable.Table, blockRawData []fu } // export all blocks, heavy use of bulk & concurrency, providing a range array -func bulkExportBlocksRange(tableBlocksRaw *gcp_bigtable.Table, blockRanges []intRange, concurrency int64, nodeRequestsAtOnce int64, discordWebhookBlockThreshold *int64, discordWebhookReportUrl *string, discordWebhookUser *string) error { +func bulkExportBlocksRange(tableBlocksRaw raw.Store, blockRanges []intRange, concurrency int64, nodeRequestsAtOnce int64, discordWebhookBlockThreshold *int64, discordWebhookReportUrl *string, discordWebhookUser *string) error { { var blocksTotalCount int64 l := len(blockRanges) @@ -657,7 +597,7 @@ func bulkExportBlocksRange(tableBlocksRaw *gcp_bigtable.Table, blockRanges []int }() defer gOuterMustStop.Store(true) // kill the updater - blockRawData := make([]fullBlockRawData, 0, nodeRequestsAtOnce) + blockRawData := make([]raw.FullBlockData, 0, nodeRequestsAtOnce) blockRawDataLen := int64(0) Loop: for _, blockRange := range blockRanges { @@ -670,7 +610,7 @@ Loop: currentNodeBlockNumberLocalCopy := currentNodeBlockNumber.Load() for blockRawDataLen < nodeRequestsAtOnce && current <= blockRange.end { if currentNodeBlockNumberLocalCopy >= current { - blockRawData = append(blockRawData, fullBlockRawData{blockNumber: current}) + blockRawData = append(blockRawData, raw.FullBlockData{BlockNumber: current}) blockRawDataLen++ current++ } else { @@ -689,7 +629,7 @@ Loop: blocksProcessedIntv.Add(int64(len(brd))) return nil }) - blockRawData = make([]fullBlockRawData, 0, nodeRequestsAtOnce) + blockRawData = make([]raw.FullBlockData, 0, nodeRequestsAtOnce) blockRawDataLen = 0 } } @@ -769,32 +709,6 @@ func _formatInt64(value int64) string { return fmt.Sprintf("%d", value) } -// compress given byte slice -func compress(src []byte) []byte { - var buf bytes.Buffer - zw := gzip.NewWriter(&buf) - if _, err := zw.Write(src); err != nil { - log.Fatal(err, "error writing to gzip writer", 0) // fatal, as if this is not working in the first place, it will never work - } - if err := zw.Close(); err != nil { - log.Fatal(err, "error closing gzip writer", 0) // fatal, as if this is not working in the first place, it will never work - } - return buf.Bytes() -} - -// decompress given byte slice -/* func decompress(src []byte) []byte { - zr, err := gzip.NewReader(bytes.NewReader(src)) - if err != nil { - log.Fatal(err, "error creating gzip reader", 0) // fatal, as if this is not working in the first place, it will never work - } - data, err := io.ReadAll(zr) - if err != nil { - log.Fatal(err, "error reading from gzip reader", 0) // fatal, as if this is not working in the first place, it will never work - } - return data -} */ - // used by splitAndVerifyJsonArray to add an element to the list depending on its Id func _splitAndVerifyJsonArrayAddElement(r *[][]byte, element []byte, lastId int64) (int64, error) { // adding empty elements will cause issues, so we don't allow it @@ -1072,7 +986,7 @@ func psqlGetLatestBlock(useWriterDb bool) (int64, error) { // will add elements to sql, based on blockRawData // on conflict, it will only overwrite / change current entry if hash is different -func psqlAddElements(blockRawData []fullBlockRawData) error { +func psqlAddElements(blockRawData []raw.FullBlockData) error { l := len(blockRawData) if l <= 0 { return fmt.Errorf("error, got empty blockRawData array (%d)", l) @@ -1081,8 +995,8 @@ func psqlAddElements(blockRawData []fullBlockRawData) error { block_number := make([]int64, l) block_hash := make(pq.ByteaArray, l) for i, v := range blockRawData { - block_number[i] = v.blockNumber - block_hash[i] = v.blockHash + block_number[i] = v.BlockNumber + block_hash[i] = v.BlockHash } _, err := db.WriterDb.Exec(` @@ -1103,7 +1017,7 @@ func psqlAddElements(blockRawData []fullBlockRawData) error { } // will return a list of all provided block_ids where the hash in the database matches the provided list -func psqlGetHashHitsIdList(blockRawData []fullBlockRawData) ([]int64, error) { +func psqlGetHashHitsIdList(blockRawData []raw.FullBlockData) ([]int64, error) { l := len(blockRawData) if l <= 0 { return nil, fmt.Errorf("error, got empty blockRawData array (%d)", l) @@ -1112,8 +1026,8 @@ func psqlGetHashHitsIdList(blockRawData []fullBlockRawData) ([]int64, error) { block_number := make([]int64, l) block_hash := make(pq.ByteaArray, l) for i, v := range blockRawData { - block_number[i] = v.blockNumber - block_hash[i] = v.blockHash + block_number[i] = v.BlockNumber + block_hash[i] = v.BlockHash } // as there are corner cases, to be on the safe side, we will use WriterDb here @@ -1232,7 +1146,7 @@ func _rpciGetHttpResult(body []byte, nodeRequestsAtOnce int64, count int64) ([][ } // will fill only receipts_compressed based on block, used by rpciGetBulkRawReceipts function -func _rpciGetBulkRawBlockReceipts(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func _rpciGetBulkRawBlockReceipts(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check { l := int64(len(blockRawData)) @@ -1252,7 +1166,7 @@ func _rpciGetBulkRawBlockReceipts(blockRawData []fullBlockRawData, nodeRequestsA if i != 0 { bodyStr += "," } - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getBlockReceipts","params":["0x%x"],"id":%d}`, v.blockNumber, i) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getBlockReceipts","params":["0x%x"],"id":%d}`, v.BlockNumber, i) } bodyStr += "]" var err error @@ -1264,14 +1178,14 @@ func _rpciGetBulkRawBlockReceipts(blockRawData []fullBlockRawData, nodeRequestsA // get data for i, v := range rawData { - blockRawData[i].receiptsCompressed = compress(v) + blockRawData[i].Receipts = v } return nil } // will fill only receipts_compressed based on transaction, used by rpciGetBulkRawReceipts function -func _rpciGetBulkRawTransactionReceipts(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func _rpciGetBulkRawTransactionReceipts(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check { l := int64(len(blockRawData)) @@ -1289,7 +1203,7 @@ func _rpciGetBulkRawTransactionReceipts(blockRawData []fullBlockRawData, nodeReq var dataAvailable bool bodyStr := "[" for i, v := range blockRawData { - l := int64(len(v.blockTxs)) + l := int64(len(v.BlockTxs)) if l < 1 { continue // skip empty } @@ -1304,10 +1218,10 @@ func _rpciGetBulkRawTransactionReceipts(blockRawData []fullBlockRawData, nodeReq } for _, vv := range rawData { - for len(blockRawData[blockRawDataWriteIndex].blockTxs) < 1 { + for len(blockRawData[blockRawDataWriteIndex].BlockTxs) < 1 { blockRawDataWriteIndex++ } - blockRawData[blockRawDataWriteIndex].receiptsCompressed = compress(vv) + blockRawData[blockRawDataWriteIndex].Receipts = vv blockRawDataWriteIndex++ } @@ -1321,7 +1235,7 @@ func _rpciGetBulkRawTransactionReceipts(blockRawData []fullBlockRawData, nodeReq // adding txs of current block dataAvailable = true currentElementCount += l - for txIndex, txValue := range v.blockTxs { + for txIndex, txValue := range v.BlockTxs { if txIndex != 0 { bodyStr += "," } @@ -1339,10 +1253,10 @@ func _rpciGetBulkRawTransactionReceipts(blockRawData []fullBlockRawData, nodeReq } for _, vv := range rawData { - for len(blockRawData[blockRawDataWriteIndex].blockTxs) < 1 { + for len(blockRawData[blockRawDataWriteIndex].BlockTxs) < 1 { blockRawDataWriteIndex++ } - blockRawData[blockRawDataWriteIndex].receiptsCompressed = compress(vv) + blockRawData[blockRawDataWriteIndex].Receipts = vv blockRawDataWriteIndex++ } } @@ -1352,7 +1266,7 @@ func _rpciGetBulkRawTransactionReceipts(blockRawData []fullBlockRawData, nodeReq } // will fill only block_hash, block_unclesCount, block_compressed & block_txs -func rpciGetBulkBlockRawData(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func rpciGetBulkBlockRawData(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check { l := int64(len(blockRawData)) @@ -1372,7 +1286,7 @@ func rpciGetBulkBlockRawData(blockRawData []fullBlockRawData, nodeRequestsAtOnce if i != 0 { bodyStr += "," } - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x", true],"id":%d}`, v.blockNumber, i) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x", true],"id":%d}`, v.BlockNumber, i) } bodyStr += "]" var err error @@ -1387,10 +1301,10 @@ func rpciGetBulkBlockRawData(blockRawData []fullBlockRawData, nodeRequestsAtOnce for i, v := range rawData { // block { - blockRawData[i].blockCompressed = compress(v) + blockRawData[i].Block = v err := json.Unmarshal(v, blockParsed) if err != nil { - return fmt.Errorf("error decoding block '%d' response: %w", blockRawData[i].blockNumber, err) + return fmt.Errorf("error decoding block '%d' response: %w", blockRawData[i].BlockNumber, err) } } @@ -1402,29 +1316,29 @@ func rpciGetBulkBlockRawData(blockRawData []fullBlockRawData, nodeRequestsAtOnce // number { blockParsedResultNumber := int64(binary.BigEndian.Uint64(append(make([]byte, 8-len(blockParsed.Result.Number)), blockParsed.Result.Number...))) - if blockRawData[i].blockNumber != blockParsedResultNumber { - log.Error(nil, "Doesn't match", 0, map[string]interface{}{"blockRawData[i].blockNumber": blockRawData[i].blockNumber, "blockParsedResultNumber": blockParsedResultNumber}) + if blockRawData[i].BlockNumber != blockParsedResultNumber { + log.Error(nil, "Doesn't match", 0, map[string]interface{}{"blockRawData[i].BlockNumber": blockRawData[i].BlockNumber, "blockParsedResultNumber": blockParsedResultNumber}) } } // hash if blockParsed.Result.Hash == nil { - return fmt.Errorf("blockParsed.Result.Hash is nil at block '%d'", blockRawData[i].blockNumber) + return fmt.Errorf("blockParsed.Result.Hash is nil at block '%d'", blockRawData[i].BlockNumber) } - blockRawData[i].blockHash = blockParsed.Result.Hash + blockRawData[i].BlockHash = blockParsed.Result.Hash // transaction if blockParsed.Result.Transactions == nil { - return fmt.Errorf("blockParsed.Result.Transactions is nil at block '%d'", blockRawData[i].blockNumber) + return fmt.Errorf("blockParsed.Result.Transactions is nil at block '%d'", blockRawData[i].BlockNumber) } - blockRawData[i].blockTxs = make([]string, len(blockParsed.Result.Transactions)) + blockRawData[i].BlockTxs = make([]string, len(blockParsed.Result.Transactions)) for ii, tx := range blockParsed.Result.Transactions { - blockRawData[i].blockTxs[ii] = tx.Hash.String() + blockRawData[i].BlockTxs[ii] = tx.Hash.String() } // uncle count if blockParsed.Result.Uncles != nil { - blockRawData[i].blockUnclesCount = len(blockParsed.Result.Uncles) + blockRawData[i].BlockUnclesCount = len(blockParsed.Result.Uncles) } } @@ -1432,7 +1346,7 @@ func rpciGetBulkBlockRawData(blockRawData []fullBlockRawData, nodeRequestsAtOnce } // will fill only block_hash -func rpciGetBulkBlockRawHash(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func rpciGetBulkBlockRawHash(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check { l := int64(len(blockRawData)) @@ -1456,7 +1370,7 @@ func rpciGetBulkBlockRawHash(blockRawData []fullBlockRawData, nodeRequestsAtOnce if i != 0 { bodyStr += "," } - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x", true],"id":%d}`, v.blockNumber, i) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x", true],"id":%d}`, v.BlockNumber, i) } bodyStr += "]" var err error @@ -1471,28 +1385,28 @@ func rpciGetBulkBlockRawHash(blockRawData []fullBlockRawData, nodeRequestsAtOnce for i, v := range rawData { err := json.Unmarshal(v, blockParsed) if err != nil { - return fmt.Errorf("error decoding block '%d' response: %w", blockRawData[i].blockNumber, err) + return fmt.Errorf("error decoding block '%d' response: %w", blockRawData[i].BlockNumber, err) } if i != blockParsed.Id { return fmt.Errorf("impossible error, i '%d' doesn't match blockParsed.Id '%d'", i, blockParsed.Id) } { blockParsedResultNumber := int64(binary.BigEndian.Uint64(append(make([]byte, 8-len(blockParsed.Result.Number)), blockParsed.Result.Number...))) - if blockRawData[i].blockNumber != blockParsedResultNumber { - log.Error(nil, "Doesn't match", 0, map[string]interface{}{"blockRawData[i].blockNumber": blockRawData[i].blockNumber, "blockParsedResultNumber": blockParsedResultNumber}) + if blockRawData[i].BlockNumber != blockParsedResultNumber { + log.Error(nil, "Doesn't match", 0, map[string]interface{}{"blockRawData[i].BlockNumber": blockRawData[i].BlockNumber, "blockParsedResultNumber": blockParsedResultNumber}) } } if blockParsed.Result.Hash == nil { - return fmt.Errorf("blockParsed.Result.Hash is nil at block '%d'", blockRawData[i].blockNumber) + return fmt.Errorf("blockParsed.Result.Hash is nil at block '%d'", blockRawData[i].BlockNumber) } - blockRawData[i].blockHash = blockParsed.Result.Hash + blockRawData[i].BlockHash = blockParsed.Result.Hash } return nil } // will fill only uncles (if available) -func rpciGetBulkRawUncles(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func rpciGetBulkRawUncles(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check { l := int64(len(blockRawData)) @@ -1512,10 +1426,10 @@ func rpciGetBulkRawUncles(blockRawData []fullBlockRawData, nodeRequestsAtOnce in firstElement := true bodyStr := "[" for _, v := range blockRawData { - if v.blockUnclesCount > 2 || v.blockUnclesCount < 0 { + if v.BlockUnclesCount > 2 || v.BlockUnclesCount < 0 { // fatal, as this is an impossible error - log.Fatal(nil, "impossible error, found impossible uncle count, expected 0, 1 or 2", 0, map[string]interface{}{"block_unclesCount": v.blockUnclesCount, "block_number": v.blockNumber}) - } else if v.blockUnclesCount == 0 { + log.Fatal(nil, "impossible error, found impossible uncle count, expected 0, 1 or 2", 0, map[string]interface{}{"block_unclesCount": v.BlockUnclesCount, "block_number": v.BlockNumber}) + } else if v.BlockUnclesCount == 0 { continue } else { if firstElement { @@ -1523,14 +1437,14 @@ func rpciGetBulkRawUncles(blockRawData []fullBlockRawData, nodeRequestsAtOnce in } else { bodyStr += "," } - if v.blockUnclesCount == 1 { + if v.BlockUnclesCount == 1 { requestedCount++ - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x%x", "0x0"],"id":%d}`, v.blockNumber, v.blockNumber) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x%x", "0x0"],"id":%d}`, v.BlockNumber, v.BlockNumber) } else /* if v.block_unclesCount == 2 */ { requestedCount++ - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x%x", "0x0"],"id":%d},`, v.blockNumber, v.blockNumber) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x%x", "0x0"],"id":%d},`, v.BlockNumber, v.BlockNumber) requestedCount++ - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x%x", "0x1"],"id":%d}`, v.blockNumber, v.blockNumber) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_getUncleByBlockNumberAndIndex","params":["0x%x", "0x1"],"id":%d}`, v.BlockNumber, v.BlockNumber) } } } @@ -1549,8 +1463,8 @@ func rpciGetBulkRawUncles(blockRawData []fullBlockRawData, nodeRequestsAtOnce in // get data rdIndex := 0 for i, v := range blockRawData { - if v.blockUnclesCount > 0 { // Not the prettiest way, but the unmarshal would take much longer with the same result - blockRawData[i].unclesCompressed = compress(rawData[rdIndex]) + if v.BlockUnclesCount > 0 { // Not the prettiest way, but the unmarshal would take much longer with the same result + blockRawData[i].Uncles = rawData[rdIndex] rdIndex++ } } @@ -1559,7 +1473,7 @@ func rpciGetBulkRawUncles(blockRawData []fullBlockRawData, nodeRequestsAtOnce in } // will fill only receipts_compressed -func rpciGetBulkRawReceipts(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func rpciGetBulkRawReceipts(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { if utils.Config.Chain.Id == ARBITRUM_CHAINID { return _rpciGetBulkRawTransactionReceipts(blockRawData, nodeRequestsAtOnce) } @@ -1567,7 +1481,7 @@ func rpciGetBulkRawReceipts(blockRawData []fullBlockRawData, nodeRequestsAtOnce } // will fill only traces_compressed -func rpciGetBulkRawTraces(blockRawData []fullBlockRawData, nodeRequestsAtOnce int64) error { +func rpciGetBulkRawTraces(blockRawData []raw.FullBlockData, nodeRequestsAtOnce int64) error { // check { l := int64(len(blockRawData)) @@ -1587,10 +1501,10 @@ func rpciGetBulkRawTraces(blockRawData []fullBlockRawData, nodeRequestsAtOnce in if i != 0 { bodyStr += "," } - if utils.Config.Chain.Id == ARBITRUM_CHAINID && v.blockNumber < ARBITRUM_NITRO_BLOCKNUMBER { - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"arbtrace_block","params":["0x%x"],"id":%d}`, v.blockNumber, i) + if utils.Config.Chain.Id == ARBITRUM_CHAINID && v.BlockNumber < ARBITRUM_NITRO_BLOCKNUMBER { + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"arbtrace_block","params":["0x%x"],"id":%d}`, v.BlockNumber, i) } else { - bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["0x%x", {"tracer": "callTracer"}],"id":%d}`, v.blockNumber, i) + bodyStr += fmt.Sprintf(`{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["0x%x", {"tracer": "callTracer"}],"id":%d}`, v.BlockNumber, i) } } bodyStr += "]" @@ -1603,7 +1517,7 @@ func rpciGetBulkRawTraces(blockRawData []fullBlockRawData, nodeRequestsAtOnce in // get data for i, v := range rawData { - blockRawData[i].tracesCompressed = compress(v) + blockRawData[i].Traces = v } return nil diff --git a/backend/go.mod b/backend/go.mod index f0b6c4f7a..7498c8541 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,6 +1,6 @@ module github.com/gobitfly/beaconchain -go 1.23 +go 1.23.1 require ( cloud.google.com/go/bigtable v1.21.0 @@ -8,6 +8,7 @@ require ( firebase.google.com/go/v4 v4.14.1 github.com/ClickHouse/clickhouse-go/v2 v2.17.1 github.com/Gurpartap/storekit-go v0.0.0-20201205024111-36b6cd5c6a21 + github.com/Tangui-Bitfly/ethsimtracer v0.0.0-20241031103622-e76546c3d9c1 github.com/alexedwards/scs/redisstore v0.0.0-20240316134038-7e11d57e8885 github.com/alexedwards/scs/v2 v2.8.0 github.com/attestantio/go-eth2-client v0.19.10 @@ -21,23 +22,23 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/doug-martin/goqu/v9 v9.19.0 - github.com/ethereum/go-ethereum v1.14.8 + github.com/ethereum/go-ethereum v1.14.11 github.com/fergusstrange/embedded-postgres v1.29.0 github.com/gavv/httpexpect/v2 v2.16.0 github.com/go-faker/faker/v4 v4.3.0 github.com/go-openapi/spec v0.20.14 github.com/go-redis/redis/v8 v8.11.5 github.com/gobitfly/eth-rewards v0.1.2-0.20230403064929-411ddc40a5f7 - github.com/gobitfly/eth.store v0.0.0-20240312111708-b43f13990280 + github.com/gobitfly/eth.store v0.0.0-20241115163631-57eeb551a84e github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt/v4 v4.5.1 - github.com/golang/protobuf v1.5.4 github.com/gomodule/redigo v1.9.2 + github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/gorilla/csrf v1.7.2 github.com/gorilla/handlers v1.5.2 github.com/gorilla/mux v1.8.1 - github.com/gorilla/websocket v1.5.1 + github.com/gorilla/websocket v1.5.3 github.com/gtuk/discordwebhook v1.2.0 github.com/gzuidhof/tygo v0.2.13 github.com/hashicorp/go-version v1.6.0 @@ -52,20 +53,20 @@ require ( github.com/juliangruber/go-intersect v1.1.0 github.com/jung-kurt/gofpdf v1.16.2 github.com/k3a/html2text v1.2.1 - github.com/kelseyhightower/envconfig v1.4.0 - github.com/klauspost/compress v1.17.6 + github.com/klauspost/compress v1.17.9 github.com/klauspost/pgzip v1.2.6 github.com/lib/pq v1.10.9 github.com/mailgun/mailgun-go/v4 v4.12.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 github.com/pressly/goose/v3 v3.18.0 - github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_golang v1.20.0 github.com/protolambda/zrnt v0.32.2 - github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 + github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388 github.com/rocket-pool/rocketpool-go v1.8.4-0.20241009143357-7b6894d57365 github.com/rocket-pool/smartnode v1.14.1 + github.com/sethvargo/go-envconfig v1.1.0 github.com/shopspring/decimal v1.4.0 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 @@ -76,28 +77,31 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 go.uber.org/atomic v1.11.0 golang.org/x/crypto v0.31.0 - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/sync v0.10.0 golang.org/x/text v0.21.0 golang.org/x/time v0.5.0 - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d + golang.org/x/tools v0.24.0 google.golang.org/api v0.170.0 + google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 ) require ( + cel.dev/expr v0.16.0 // indirect cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute v1.24.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/firestore v1.15.0 // indirect cloud.google.com/go/iam v1.1.7 // indirect cloud.google.com/go/longrunning v0.5.5 // indirect cloud.google.com/go/storage v1.40.0 // indirect github.com/ClickHouse/ch-go v0.58.2 // indirect + github.com/DataDog/zstd v1.5.5 // indirect github.com/MicahParks/keyfunc v1.9.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect + github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/ajg/form v1.5.1 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/alessio/shellescape v1.4.1 // indirect @@ -124,19 +128,26 @@ require ( github.com/buger/jsonparser v1.1.1 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect - github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect + github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/pebble v1.1.2 // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/envoyproxy/go-control-plane v0.12.0 // indirect - github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect + github.com/envoyproxy/go-control-plane v0.13.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/fatih/color v1.16.0 // indirect @@ -145,11 +156,13 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/ferranbt/fastssz v0.1.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/glendc/go-external-ip v0.1.0 // indirect github.com/go-chi/chi/v5 v5.0.8 // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.6.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect @@ -158,19 +171,25 @@ require ( github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-yaml v1.9.5 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.0 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/securecookie v1.1.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/herumi/bls-eth-go-binary v1.31.0 // indirect + github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.1 // indirect github.com/huandu/go-clone v1.6.0 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/imkira/go-interpol v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/boxo v0.8.0 // indirect @@ -193,19 +212,24 @@ require ( github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -216,34 +240,43 @@ require ( github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-varint v0.0.7 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/paulmach/orb v0.10.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/protolambda/zssz v0.1.5 // indirect - github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44 // indirect - github.com/prysmaticlabs/gohashtree v0.0.4-beta // indirect - github.com/prysmaticlabs/prysm/v3 v3.2.2 // indirect + github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 // indirect + github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b // indirect + github.com/prysmaticlabs/prysm/v5 v5.1.2 // indirect github.com/r3labs/sse/v2 v2.10.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rs/cors v1.8.2 // indirect github.com/rs/zerolog v1.29.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sanity-io/litter v1.5.5 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect - github.com/sethvargo/go-envconfig v1.1.0 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/status-im/keycard-go v0.2.0 // indirect github.com/supranational/blst v0.3.13 // indirect github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect github.com/tklauser/numcpus v0.7.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/urfave/cli/v2 v2.26.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.34.0 // indirect + github.com/valyala/fasthttp v1.40.0 // indirect github.com/wealdtech/go-bytesutil v1.2.0 // indirect github.com/wealdtech/go-merkletree v1.0.1-0.20190605192610-2bb163c2ea2a // indirect github.com/wealdtech/go-multicodec v1.4.0 // indirect @@ -253,6 +286,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect github.com/yudai/gojsondiff v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect @@ -260,32 +294,29 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine/v2 v2.0.2 // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/grpc v1.62.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.3.0 // indirect moul.io/http2curl/v2 v2.3.0 // indirect + rsc.io/binaryregexp v0.2.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) replace github.com/wealdtech/go-merkletree v1.0.1-0.20190605192610-2bb163c2ea2a => github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd replace github.com/rocket-pool/rocketpool-go v1.8.2 => github.com/gobitfly/rocketpool-go v0.0.0-20240105082836-5bb7c83a2d08 - -replace github.com/prysmaticlabs/prysm/v3 => github.com/gobitfly/prysm/v3 v3.0.0-20230216184552-2f3f1e8190d5 diff --git a/backend/go.sum b/backend/go.sum index 2cfda3b52..ded8832d4 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,12 +1,12 @@ +cel.dev/expr v0.16.0 h1:yloc84fytn4zmJX2GU3TkXGsaieaV7dQ057Qs4sIG2Y= +cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go/bigtable v1.21.0 h1:BFN4jhkA9ULYYV2Ug7AeOtetVLnN2jKuIq5TcRc5C38= cloud.google.com/go/bigtable v1.21.0/go.mod h1:V0sYNRtk0dgAKjyRr/MyBpHpSXqh+9P39euf820EZ74= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= @@ -17,23 +17,21 @@ cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHw cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= -contrib.go.opencensus.io/exporter/jaeger v0.2.1 h1:yGBYzYMewVL0yO9qqJv3Z5+IRhPdU7e9o/2oKpX4YvI= -contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0= firebase.google.com/go/v4 v4.14.1 h1:4qiUETaFRWoFGE1XP5VbcEdtPX93Qs+8B/7KvP2825g= firebase.google.com/go/v4 v4.14.1/go.mod h1:fgk2XshgNDEKaioKco+AouiegSI9oTWVqRaBdTTGBoM= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0= github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw= github.com/ClickHouse/clickhouse-go/v2 v2.17.1 h1:ZCmAYWpu75IyEi7+Yrs/uaAjiCGY5wfW5kXo64exkX4= github.com/ClickHouse/clickhouse-go/v2 v2.17.1/go.mod h1:rkGTvFDTLqLIm0ma+13xmcCfr/08Gvs7KmFt1tgiWHQ= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Gurpartap/storekit-go v0.0.0-20201205024111-36b6cd5c6a21 h1:HcdvlzaQ4CJfH7xbfJZ3ZHN//BTEpId46iKEMuP3wHE= github.com/Gurpartap/storekit-go v0.0.0-20201205024111-36b6cd5c6a21/go.mod h1:7PODFS++oNZ6khojmPBvkrDeFO/hrc3jmvWvQAOXorw= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -43,6 +41,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/Tangui-Bitfly/ethsimtracer v0.0.0-20241031103622-e76546c3d9c1 h1:KUh8TO3q7sULPQOHX4HtRPSRwYqgPHkOkg/rItvsSkk= +github.com/Tangui-Bitfly/ethsimtracer v0.0.0-20241031103622-e76546c3d9c1/go.mod h1:2pEz2HpJ+iF8e+qIy9EU41mAUPIECMt9DBd6aD0b0Uk= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= @@ -57,6 +57,8 @@ github.com/alexedwards/scs/redisstore v0.0.0-20240316134038-7e11d57e8885 h1:UdHe github.com/alexedwards/scs/redisstore v0.0.0-20240316134038-7e11d57e8885/go.mod h1:ceKFatoD+hfHWWeHOAYue1J+XgOJjE7dw8l3JtIRTGY= github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= @@ -112,8 +114,8 @@ github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xW github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= github.com/bazelbuild/rules_go v0.23.2/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= @@ -142,6 +144,7 @@ github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -149,20 +152,19 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= -github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -188,6 +190,7 @@ github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJ github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= @@ -196,12 +199,14 @@ github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= @@ -231,15 +236,15 @@ github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les= +github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.14.8 h1:NgOWvXS+lauK+zFukEvi85UmmsS/OkV0N23UZ1VTIig= -github.com/ethereum/go-ethereum v1.14.8/go.mod h1:TJhyuDq0JDppAkFXgqjwpdlQApywnu/m10kFPxh8vvs= +github.com/ethereum/go-ethereum v1.14.11 h1:8nFDCUUE67rPc6AKxFj7JKaOa2W/W1Rse3oS6LvvxEY= +github.com/ethereum/go-ethereum v1.14.11/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= @@ -261,6 +266,10 @@ github.com/fergusstrange/embedded-postgres v1.29.0 h1:Uv8hdhoiaNMuH0w8UuGXDHr60V github.com/fergusstrange/embedded-postgres v1.29.0/go.mod h1:t/MLs0h9ukYM6FSt99R7InCHs1nW0ordoVCcnzmpTYw= github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo= github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= @@ -279,6 +288,8 @@ github.com/glendc/go-external-ip v0.1.0 h1:iX3xQ2Q26atAmLTbd++nUce2P5ht5P4uD4V7c github.com/glendc/go-external-ip v0.1.0/go.mod h1:CNx312s2FLAJoWNdJWZ2Fpf5O4oLsMFwuYviHjS4uJE= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-faker/faker/v4 v4.3.0 h1:UXOW7kn/Mwd0u6MR30JjUKVzguT20EB/hBOddAAO+DY= github.com/go-faker/faker/v4 v4.3.0/go.mod h1:F/bBy8GH9NxOxMInug5Gx4WYeG6fHJZ8Ol/dhcpRub4= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= @@ -288,8 +299,8 @@ github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -305,28 +316,29 @@ github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZC github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= +github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gobitfly/eth-rewards v0.1.2-0.20230403064929-411ddc40a5f7 h1:qAEBlj4j25sJjsj5CQraL94rY9jyPIjCZ+hlu84n5l0= github.com/gobitfly/eth-rewards v0.1.2-0.20230403064929-411ddc40a5f7/go.mod h1:JrFv2uq5i+p6yEoRSHralEV139HkPV0wBjZZHWb4he8= -github.com/gobitfly/eth.store v0.0.0-20240312111708-b43f13990280 h1:zHl4a19bwoa3ccAS3fdUEBC0TkEj5r0spPiVJAzURRc= -github.com/gobitfly/eth.store v0.0.0-20240312111708-b43f13990280/go.mod h1:1PLeTVRw8Rpmi0o/kRuoJEXOXecZRqSjoAxEMbj+usA= -github.com/gobitfly/prysm/v3 v3.0.0-20230216184552-2f3f1e8190d5 h1:8kVoXCPhDwSjaGlKzBVQeE8n49k6jZumBGiP26FHNy0= -github.com/gobitfly/prysm/v3 v3.0.0-20230216184552-2f3f1e8190d5/go.mod h1:+v+em7rOykPs93APGWCX/95/3uxU8bSVmbZ4+YNJzdA= +github.com/gobitfly/eth.store v0.0.0-20241115163631-57eeb551a84e h1:8InGSE5nnzUpuEUBdjep471Q8PSaDdYews1w0d9izfY= +github.com/gobitfly/eth.store v0.0.0-20241115163631-57eeb551a84e/go.mod h1:hQGo+8/AN+iCpqLcHJ0GeS3yb3EnJEh2IZBkHByUGnc= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -346,8 +358,8 @@ github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQg github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -398,6 +410,8 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -422,10 +436,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gtuk/discordwebhook v1.2.0 h1:7+gWPKSGyXjopu/6X9+oGbn0knTkDVXUM909+IXGZ/U= github.com/gtuk/discordwebhook v1.2.0/go.mod h1:U3LdXNJ1e0bx3MMe2a4mB1VBantPHOPly2jNd8ZWXec= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= @@ -574,6 +586,8 @@ github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFr github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -601,23 +615,21 @@ github.com/k3a/html2text v1.2.1 h1:nvnKgBvBR/myqrwfLuiqecUtaK1lB9hGziIJKatNFVY= github.com/k3a/html2text v1.2.1/go.mod h1:ieEXykM67iT8lTvEWBh6fhpH4B23kB9OMKPdIBmgUqA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= -github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= -github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -633,8 +645,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ 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/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= +github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -645,20 +657,18 @@ github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-libp2p v0.26.3 h1:6g/psubqwdaBqNNoidbRKSTBEYgaOuKBhHl8Q5tO+PM= -github.com/libp2p/go-libp2p v0.26.3/go.mod h1:x75BN32YbwuY0Awm2Uix4d4KOz+/4piInkp4Wr3yOo8= -github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= -github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= +github.com/libp2p/go-libp2p v0.36.2 h1:BbqRkDaGC3/5xfaJakLV/BrpjlAuYqSB0lRvtzL3B/U= +github.com/libp2p/go-libp2p v0.36.2/go.mod h1:XO3joasRE4Eup8yCTTP/+kX+g92mOgRaadk46LmPhHY= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= +github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= +github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 h1:6PfEMwfInASh9hkN83aR0j4W/eKaAZt/AURtXAXlas0= @@ -680,6 +690,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -687,8 +698,8 @@ github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEg github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= @@ -701,6 +712,7 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= @@ -730,8 +742,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= -github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU= -github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= +github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= +github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -740,8 +752,8 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= -github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= @@ -749,15 +761,18 @@ github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -766,11 +781,14 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= +github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= @@ -791,10 +809,47 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhM github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo= +github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.34 h1:Ic1ppYCj4tUOcPAp76U6F3fVrlSw8A9JtRXLqw6BbUM= +github.com/pion/ice/v2 v2.3.34/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/interceptor v0.1.30 h1:au5rlVHsgmxNi+v/mjOPazbW1SHzfx7/hYOEYQnUcxA= +github.com/pion/interceptor v0.1.30/go.mod h1:RQuKT5HTdkP2Fi0cuOS5G5WNymTjzXaGF75J4k7z2nc= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= +github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= +github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= +github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.3.0 h1:Rf4u6n6U5t5sUxhYPQk/samzU/oDv7jk6BA5hyO2F9I= +github.com/pion/webrtc/v3 v3.3.0/go.mod h1:hVmrDJvwhEertRWObeb1xzulzHGeVUoPlWvxdGzcfU0= github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -804,33 +859,42 @@ github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4 github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/pressly/goose/v3 v3.18.0 h1:CUQKjZ0li91GLrMekHPR0yz4UyjT21AqyhSm/ERcPTo= github.com/pressly/goose/v3 v3.18.0/go.mod h1:NTDry9taDJXEV6IqkABnZqm1MRGOSrCWrNEz1x6f4wI= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI= +github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/protolambda/zrnt v0.32.2 h1:KZ48T+3UhsPXNdtE/5QEvGc9DGjUaRI17nJaoznoIaM= github.com/protolambda/zrnt v0.32.2/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= github.com/protolambda/zssz v0.1.5 h1:7fjJjissZIIaa2QcvmhS/pZISMX21zVITt49sW1ouek= github.com/protolambda/zssz v0.1.5/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag= -github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44 h1:c3p3UzV4vFA7xaCDphnDWOjpxcadrQ26l5b+ypsvyxo= -github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44/go.mod h1:MA5zShstUwCQaE9faGHgCGvEWUbG87p4SAXINhmCkvg= -github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw= -github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= +github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 h1:xuVAdtz5ShYblG2sPyb4gw01DF8InbOI/kBCQjk7NiM= +github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516/go.mod h1:h2OlIZD/M6wFvV3YMZbW16lFgh3Rsye00G44J2cwLyU= +github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e h1:ATgOe+abbzfx9kCPeXIW4fiWyDdxlwHw07j8UGhdTd4= +github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388 h1:4bD+ujqGfY4zoDUF3q9MhdmpPXzdp03DYUIlXeQ72kk= github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc= -github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= -github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= -github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20211014160335-757fae4f38c6 h1:+jhXLjEYVW4qU2z5SOxlxN+Hv/A9FDf0HpfDurfMEz0= -github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20211014160335-757fae4f38c6/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y= +github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b h1:VK7thFOnhxAZ/5aolr5Os4beiubuD08WiuiHyRqgwks= +github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b/go.mod h1:HRuvtXLZ4WkaB1MItToVH2e8ZwKwZPY5/Rcby+CvvLY= +github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h1:q9wE0ZZRdTUAAeyFP/w0SwBEnCqlVy2+on6X2/e+eAU= +github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y= +github.com/prysmaticlabs/prysm/v5 v5.1.2 h1:ib9D7Drh7QPoetJPnYXAHaArmjIreXPZ0FboW9EMzT8= +github.com/prysmaticlabs/prysm/v5 v5.1.2/go.mod h1:ykj3Bl9dHv35cC7fRw6Cd1aCd9l+eNvInHY6gsPbEig= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/quic-go v0.46.0 h1:uuwLClEEyk1DNvchH8uCByQVjo3yKL9opKulExNDs7Y= +github.com/quic-go/quic-go v0.46.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd h1:p9KuetSKB9nte9I/MkkiM3pwKFVQgqxxPTQ0y56Ff6s= @@ -840,8 +904,9 @@ github.com/rocket-pool/rocketpool-go v1.8.4-0.20241009143357-7b6894d57365/go.mod github.com/rocket-pool/smartnode v1.14.1 h1:RjD4d29gultKIlF2aGAatCuKq7Jc4FtDWRRKxBm1unQ= github.com/rocket-pool/smartnode v1.14.1/go.mod h1:pf2rJU/ROhhwr43a1/WbOndG9womyPBBAM7JKmzhNPg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -924,18 +989,15 @@ github.com/tursodatabase/libsql-client-go v0.0.0-20231216154754-8383a53d618f h1: github.com/tursodatabase/libsql-client-go v0.0.0-20231216154754-8383a53d618f/go.mod h1:UMde0InJz9I0Le/1YIR4xsB0E2vb01MrDY6k/eNdfkg= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= -github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg= github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10/go.mod h1:x/Pa0FF5Te9kdrlZKJK82YmAkvL8+f989USgz6Jiw7M= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= +github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4= -github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= +github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= @@ -964,6 +1026,8 @@ github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= +github.com/wlynxg/anet v0.0.4 h1:0de1OFQxnNqAu+x2FAKKCVIrnfGKQbs7FQz++tB0+Uw= +github.com/wlynxg/anet v0.0.4/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= @@ -994,7 +1058,6 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= @@ -1005,14 +1068,16 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1023,6 +1088,8 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1051,14 +1118,13 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -1070,9 +1136,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1093,19 +1158,17 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1143,12 +1206,12 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1162,7 +1225,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -1185,9 +1247,8 @@ golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1210,17 +1271,17 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 h1:9IZDv+/GcI6u+a4jRFRLxQs0RUCfavGfoOgEW6jpkI0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1266,18 +1327,16 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk= -k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/client-go v0.18.3 h1:QaJzz92tsN67oorwzmoB0a9r9ZVHuD5ryjbCKP0U22k= -k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.3.0 h1:WmkrnW7fdrm0/DMClc+HIxtftvxVIPAhlVwMQo5yLco= -k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/utils v0.0.0-20200520001619-278ece378a50 h1:ZtTUW5+ZWaoqjR3zOpRa7oFJ5d4aA22l4me/xArfOIc= -k8s.io/utils v0.0.0-20200520001619-278ece378a50/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +k8s.io/apimachinery v0.30.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY= +k8s.io/apimachinery v0.30.4/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.4 h1:eculUe+HPQoPbixfwmaSZGsKcOf7D288tH6hDAdd+wY= +k8s.io/client-go v0.30.4/go.mod h1:IBS0R/Mt0LHkNHF4E6n+SUDPG7+m2po6RZU7YHeOpzc= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= @@ -1306,7 +1365,9 @@ rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/backend/internal/contracts/Context.sol b/backend/internal/contracts/Context.sol new file mode 100644 index 000000000..4c7963cf9 --- /dev/null +++ b/backend/internal/contracts/Context.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contracts is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } +} \ No newline at end of file diff --git a/backend/internal/contracts/ERC20.sol b/backend/internal/contracts/ERC20.sol new file mode 100644 index 000000000..880da32cc --- /dev/null +++ b/backend/internal/contracts/ERC20.sol @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "IERC20.sol"; +import {IERC20Metadata} from "IERC20Metadata.sol"; +import {Context} from "Context.sol"; +import {IERC20Errors} from "draft-IERC6093.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC-20 + * applications. + */ +abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { + mapping(address account => uint256) private _balances; + + mapping(address account => mapping(address spender => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `value`. + */ + function transfer(address to, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, value); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Skips emitting an {Approval} event indicating an allowance update. This is not + * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `value`. + * - the caller must have allowance for ``from``'s tokens of at least + * `value`. + */ + function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @dev Moves a `value` amount of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _transfer(address from, address to, uint256 value) internal { + if (from == address(0)) { + revert ERC20InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(from, to, value); + } + + /** + * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding + * this function. + * + * Emits a {Transfer} event. + */ + function _update(address from, address to, uint256 value) internal virtual { + if (from == address(0)) { + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply += value; + } else { + uint256 fromBalance = _balances[from]; + if (fromBalance < value) { + revert ERC20InsufficientBalance(from, fromBalance, value); + } + unchecked { + // Overflow not possible: value <= fromBalance <= totalSupply. + _balances[from] = fromBalance - value; + } + } + + if (to == address(0)) { + unchecked { + // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. + _totalSupply -= value; + } + } else { + unchecked { + // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. + _balances[to] += value; + } + } + + emit Transfer(from, to, value); + } + + /** + * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). + * Relies on the `_update` mechanism + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _mint(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(address(0), account, value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead + */ + function _burn(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidSender(address(0)); + } + _update(account, address(0), value); + } + + /** + * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address owner, address spender, uint256 value) internal { + _approve(owner, spender, value, true); + } + + /** + * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. + * + * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by + * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any + * `Approval` event during `transferFrom` operations. + * + * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to + * true using the following override: + * + * ```solidity + * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { + * super._approve(owner, spender, value, true); + * } + * ``` + * + * Requirements are the same as {_approve}. + */ + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + _allowances[owner][spender] = value; + if (emitEvent) { + emit Approval(owner, spender, value); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `value`. + * + * Does not update the allowance value in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Does not emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); + } + unchecked { + _approve(owner, spender, currentAllowance - value, false); + } + } + } +} \ No newline at end of file diff --git a/backend/internal/contracts/IERC20.sol b/backend/internal/contracts/IERC20.sol new file mode 100644 index 000000000..bcd73a9b1 --- /dev/null +++ b/backend/internal/contracts/IERC20.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC-20 standard as defined in the ERC. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the value of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the value of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 value) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 value) external returns (bool); +} \ No newline at end of file diff --git a/backend/internal/contracts/IERC20Metadata.sol b/backend/internal/contracts/IERC20Metadata.sol new file mode 100644 index 000000000..cc608c03b --- /dev/null +++ b/backend/internal/contracts/IERC20Metadata.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC-20 standard. + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} \ No newline at end of file diff --git a/backend/internal/contracts/IMulticall3.sol b/backend/internal/contracts/IMulticall3.sol new file mode 100644 index 000000000..585ba4a3e --- /dev/null +++ b/backend/internal/contracts/IMulticall3.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; +pragma experimental ABIEncoderV2; + +interface IMulticall3 { + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + function aggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes[] memory returnData); + + function aggregate3(Call3[] calldata calls) external view returns (Result[] memory returnData); + + function aggregate3Value(Call3Value[] calldata calls) + external + view + returns (Result[] memory returnData); + + function blockAndAggregate(Call[] calldata calls) + external + view + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); + + function getBasefee() external view returns (uint256 basefee); + + function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash); + + function getBlockNumber() external view returns (uint256 blockNumber); + + function getChainId() external view returns (uint256 chainid); + + function getCurrentBlockCoinbase() external view returns (address coinbase); + + function getCurrentBlockDifficulty() external view returns (uint256 difficulty); + + function getCurrentBlockGasLimit() external view returns (uint256 gaslimit); + + function getCurrentBlockTimestamp() external view returns (uint256 timestamp); + + function getEthBalance(address addr) external view returns (uint256 balance); + + function getLastBlockHash() external view returns (bytes32 blockHash); + + function tryAggregate(bool requireSuccess, Call[] calldata calls) + external + view + returns (Result[] memory returnData); + + function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) + external + view + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); +} diff --git a/backend/internal/contracts/Makefile b/backend/internal/contracts/Makefile new file mode 100644 index 000000000..b89a7cdf1 --- /dev/null +++ b/backend/internal/contracts/Makefile @@ -0,0 +1,30 @@ +############################################################################### +### Generate ABI ### +############################################################################### +generate-abi: clean ## Generate contract ABI Go code + solc --evm-version paris --optimize -o bin/contract --bin --abi --overwrite IERC20.sol + solc --evm-version paris --optimize -o bin/contract --bin --abi --overwrite Token.sol + solc --evm-version paris --optimize -o bin/contract --bin --abi --overwrite Multicall3.sol + solc --evm-version paris --optimize -o bin/contract --bin --abi --overwrite IMulticall3.sol + + abigen --abi=./bin/contract/IERC20.abi --type IERC20 --pkg=contracts --out=./ierc20.go + abigen --abi=./bin/contract/Token.abi --bin=./bin/contract/Token.bin -type Token --pkg=contracts --out=./token.go + abigen --abi=./bin/contract/Multicall3.abi --bin=./bin/contract/Multicall3.bin --type Multicall --pkg=contracts --out=./multicall.go + abigen --abi=./bin/contract/IMulticall3.abi --type IMulticall3 --pkg=contracts --out=./imulticall3.go + +############################################################################### +### Clean ### +############################################################################### +clean: + @echo "Cleaning..." + @rm -rf bin + +############################################################################### +### Help ### +############################################################################### +help: + @echo "Available commands:" + @echo " make generate-abi : Generate contract ABI Go code" + @echo " make clean : Clean the build" + @echo " make help : Print this help message" +.PHONY: help \ No newline at end of file diff --git a/backend/internal/contracts/Multicall3.sol b/backend/internal/contracts/Multicall3.sol new file mode 100644 index 000000000..a1f5e851c --- /dev/null +++ b/backend/internal/contracts/Multicall3.sol @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/// @title Multicall3 +/// @notice Aggregate results from multiple function calls +/// @dev Multicall & Multicall2 backwards-compatible +/// @dev Aggregate methods are marked `payable` to save 24 gas per call +/// @author Michael Elliot +/// @author Joshua Levine +/// @author Nick Johnson +/// @author Andreas Bigger +/// @author Matt Solomon +contract Multicall3 { + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + /// @notice Backwards-compatible call aggregation with Multicall + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return returnData An array of bytes containing the responses + function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) { + blockNumber = block.number; + uint256 length = calls.length; + returnData = new bytes[](length); + Call calldata call; + for (uint256 i = 0; i < length;) { + bool success; + call = calls[i]; + (success, returnData[i]) = call.target.call(call.callData); + require(success, "Multicall3: call failed"); + unchecked { ++i; } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls without requiring success + /// @param requireSuccess If true, require all calls to succeed + /// @param calls An array of Call structs + /// @return returnData An array of Result structs + function tryAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 length = calls.length; + returnData = new Result[](length); + Call calldata call; + for (uint256 i = 0; i < length;) { + Result memory result = returnData[i]; + call = calls[i]; + (result.success, result.returnData) = call.target.call(call.callData); + if (requireSuccess) require(result.success, "Multicall3: call failed"); + unchecked { ++i; } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { + blockNumber = block.number; + blockHash = blockhash(block.number); + returnData = tryAggregate(requireSuccess, calls); + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function blockAndAggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { + (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); + } + + /// @notice Aggregate calls, ensuring each returns success if required + /// @param calls An array of Call3 structs + /// @return returnData An array of Result structs + function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 length = calls.length; + returnData = new Result[](length); + Call3 calldata calli; + for (uint256 i = 0; i < length;) { + Result memory result = returnData[i]; + calli = calls[i]; + (result.success, result.returnData) = calli.target.call(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x64) + } + } + unchecked { ++i; } + } + } + + /// @notice Aggregate calls with a msg value + /// @notice Reverts if msg.value is less than the sum of the call values + /// @param calls An array of Call3Value structs + /// @return returnData An array of Result structs + function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData) { + uint256 valAccumulator; + uint256 length = calls.length; + returnData = new Result[](length); + Call3Value calldata calli; + for (uint256 i = 0; i < length;) { + Result memory result = returnData[i]; + calli = calls[i]; + uint256 val = calli.value; + // Humanity will be a Type V Kardashev Civilization before this overflows - andreas + // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256 + unchecked { valAccumulator += val; } + (result.success, result.returnData) = calli.target.call{value: val}(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x84) + } + } + unchecked { ++i; } + } + // Finally, make sure the msg.value = SUM(call[0...i].value) + require(msg.value == valAccumulator, "Multicall3: value mismatch"); + } + + /// @notice Returns the block hash for the given block number + /// @param blockNumber The block number + function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { + blockHash = blockhash(blockNumber); + } + + /// @notice Returns the block number + function getBlockNumber() public view returns (uint256 blockNumber) { + blockNumber = block.number; + } + + /// @notice Returns the block coinbase + function getCurrentBlockCoinbase() public view returns (address coinbase) { + coinbase = block.coinbase; + } + + /// @notice Returns the block difficulty + function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { + difficulty = block.difficulty; + } + + /// @notice Returns the block gas limit + function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { + gaslimit = block.gaslimit; + } + + /// @notice Returns the block timestamp + function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { + timestamp = block.timestamp; + } + + /// @notice Returns the (ETH) balance of a given address + function getEthBalance(address addr) public view returns (uint256 balance) { + balance = addr.balance; + } + + /// @notice Returns the block hash of the last block + function getLastBlockHash() public view returns (bytes32 blockHash) { + unchecked { + blockHash = blockhash(block.number - 1); + } + } + + /// @notice Gets the base fee of the given block + /// @notice Can revert if the BASEFEE opcode is not implemented by the given chain + function getBasefee() public view returns (uint256 basefee) { + basefee = block.basefee; + } + + /// @notice Returns the chain id + function getChainId() public view returns (uint256 chainid) { + chainid = block.chainid; + } +} \ No newline at end of file diff --git a/backend/internal/contracts/README.md b/backend/internal/contracts/README.md new file mode 100644 index 000000000..6c6b843e3 --- /dev/null +++ b/backend/internal/contracts/README.md @@ -0,0 +1,28 @@ +# Contract ABI + +To generate the ABI interface in go you will need to install `solc` and `abigen`. + +- solc is available [here](https://docs.soliditylang.org/en/latest/installing-solidity.html) + +- and `abigen` can be installed through go directly +``` +go install github.com/ethereum/go-ethereum/cmd/abigen@latest +``` + +You can then run `make generate-abi`. + +## Sources and Modification + +### ERC20, IERC20, IERC20METADATA, draft-IERC6093, Context +* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol +* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol +* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/IERC20Metadata.sol +* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/interfaces/draft-IERC6093.sol +* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol + +### Token +* original contract, simple implementation of the abstract contract `ERC20` with a `mint` function + +### Multicall3, IMulticall3 +* https://github.com/mds1/multicall/blob/main/src/Multicall3.sol +* `IMulticall3` change `payable` functions to `view` to simplify go interaction, it is only suitable for reading \ No newline at end of file diff --git a/backend/internal/contracts/Token.sol b/backend/internal/contracts/Token.sol new file mode 100644 index 000000000..f9886f578 --- /dev/null +++ b/backend/internal/contracts/Token.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import {ERC20} from "./ERC20.sol"; + +contract Token is ERC20 { + constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {} + + function mint(address account, uint256 value) public { + _mint(account, value); + } +} + diff --git a/backend/internal/contracts/draft-IERC6093.sol b/backend/internal/contracts/draft-IERC6093.sol new file mode 100644 index 000000000..0703bf3e0 --- /dev/null +++ b/backend/internal/contracts/draft-IERC6093.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) +pragma solidity ^0.8.20; + +/** + * @dev Standard ERC-20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens. + */ +interface IERC20Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC20InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC20InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. + * @param spender Address that may be allowed to operate on tokens without being their owner. + * @param allowance Amount of tokens a `spender` is allowed to operate with. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC20InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `spender` to be approved. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC20InvalidSpender(address spender); +} + +/** + * @dev Standard ERC-721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. + * Used in balance queries. + * @param owner Address of the current owner of a token. + */ + error ERC721InvalidOwner(address owner); + + /** + * @dev Indicates a `tokenId` whose `owner` is the zero address. + * @param tokenId Identifier number of a token. + */ + error ERC721NonexistentToken(uint256 tokenId); + + /** + * @dev Indicates an error related to the ownership over a particular token. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param tokenId Identifier number of a token. + * @param owner Address of the current owner of a token. + */ + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC721InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC721InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param tokenId Identifier number of a token. + */ + error ERC721InsufficientApproval(address operator, uint256 tokenId); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC721InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC721InvalidOperator(address operator); +} + +/** + * @dev Standard ERC-1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens. + */ +interface IERC1155Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. + */ + error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC1155InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1155InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param owner Address of the current owner of a token. + */ + error ERC1155MissingApprovalForAll(address operator, address owner); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC1155InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1155InvalidOperator(address operator); + + /** + * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. + * Used in batch transfers. + * @param idsLength Length of the array of token identifiers + * @param valuesLength Length of the array of token amounts + */ + error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); +} \ No newline at end of file diff --git a/backend/internal/contracts/ierc20.go b/backend/internal/contracts/ierc20.go new file mode 100644 index 000000000..af60a9d2d --- /dev/null +++ b/backend/internal/contracts/ierc20.go @@ -0,0 +1,645 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contracts + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IERC20MetaData contains all meta data concerning the IERC20 contract. +var IERC20MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// IERC20ABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC20MetaData.ABI instead. +var IERC20ABI = IERC20MetaData.ABI + +// IERC20 is an auto generated Go binding around an Ethereum contract. +type IERC20 struct { + IERC20Caller // Read-only binding to the contract + IERC20Transactor // Write-only binding to the contract + IERC20Filterer // Log filterer for contract events +} + +// IERC20Caller is an auto generated read-only Go binding around an Ethereum contract. +type IERC20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC20Session struct { + Contract *IERC20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC20CallerSession struct { + Contract *IERC20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC20TransactorSession struct { + Contract *IERC20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20Raw is an auto generated low-level Go binding around an Ethereum contract. +type IERC20Raw struct { + Contract *IERC20 // Generic contract binding to access the raw methods on +} + +// IERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC20CallerRaw struct { + Contract *IERC20Caller // Generic read-only contract binding to access the raw methods on +} + +// IERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC20TransactorRaw struct { + Contract *IERC20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC20 creates a new instance of IERC20, bound to a specific deployed contract. +func NewIERC20(address common.Address, backend bind.ContractBackend) (*IERC20, error) { + contract, err := bindIERC20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC20{IERC20Caller: IERC20Caller{contract: contract}, IERC20Transactor: IERC20Transactor{contract: contract}, IERC20Filterer: IERC20Filterer{contract: contract}}, nil +} + +// NewIERC20Caller creates a new read-only instance of IERC20, bound to a specific deployed contract. +func NewIERC20Caller(address common.Address, caller bind.ContractCaller) (*IERC20Caller, error) { + contract, err := bindIERC20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC20Caller{contract: contract}, nil +} + +// NewIERC20Transactor creates a new write-only instance of IERC20, bound to a specific deployed contract. +func NewIERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*IERC20Transactor, error) { + contract, err := bindIERC20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC20Transactor{contract: contract}, nil +} + +// NewIERC20Filterer creates a new log filterer instance of IERC20, bound to a specific deployed contract. +func NewIERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*IERC20Filterer, error) { + contract, err := bindIERC20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC20Filterer{contract: contract}, nil +} + +// bindIERC20 binds a generic wrapper to an already deployed contract. +func bindIERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20 *IERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20.Contract.IERC20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20 *IERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20.Contract.IERC20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20 *IERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20.Contract.IERC20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20 *IERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20 *IERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20 *IERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _IERC20.Contract.Allowance(&_IERC20.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _IERC20.Contract.Allowance(&_IERC20.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20Session) BalanceOf(account common.Address) (*big.Int, error) { + return _IERC20.Contract.BalanceOf(&_IERC20.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20CallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _IERC20.Contract.BalanceOf(&_IERC20.CallOpts, account) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20Session) TotalSupply() (*big.Int, error) { + return _IERC20.Contract.TotalSupply(&_IERC20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20CallerSession) TotalSupply() (*big.Int, error) { + return _IERC20.Contract.TotalSupply(&_IERC20.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "approve", spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Approve(&_IERC20.TransactOpts, spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Approve(&_IERC20.TransactOpts, spender, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "transfer", to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Transfer(&_IERC20.TransactOpts, to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Transfer(&_IERC20.TransactOpts, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "transferFrom", from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.TransferFrom(&_IERC20.TransactOpts, from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.TransferFrom(&_IERC20.TransactOpts, from, to, value) +} + +// IERC20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the IERC20 contract. +type IERC20ApprovalIterator struct { + Event *IERC20Approval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IERC20ApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IERC20ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IERC20ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IERC20Approval represents a Approval event raised by the IERC20 contract. +type IERC20Approval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*IERC20ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _IERC20.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &IERC20ApprovalIterator{contract: _IERC20.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *IERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _IERC20.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IERC20Approval) + if err := _IERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) ParseApproval(log types.Log) (*IERC20Approval, error) { + event := new(IERC20Approval) + if err := _IERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the IERC20 contract. +type IERC20TransferIterator struct { + Event *IERC20Transfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IERC20TransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IERC20TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IERC20TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IERC20Transfer represents a Transfer event raised by the IERC20 contract. +type IERC20Transfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IERC20TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IERC20.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &IERC20TransferIterator{contract: _IERC20.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *IERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IERC20.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IERC20Transfer) + if err := _IERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) ParseTransfer(log types.Log) (*IERC20Transfer, error) { + event := new(IERC20Transfer) + if err := _IERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/backend/internal/contracts/imulticall3.go b/backend/internal/contracts/imulticall3.go new file mode 100644 index 000000000..1b447910f --- /dev/null +++ b/backend/internal/contracts/imulticall3.go @@ -0,0 +1,732 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contracts + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IMulticall3Call is an auto generated low-level Go binding around an user-defined struct. +type IMulticall3Call struct { + Target common.Address + CallData []byte +} + +// IMulticall3Call3 is an auto generated low-level Go binding around an user-defined struct. +type IMulticall3Call3 struct { + Target common.Address + AllowFailure bool + CallData []byte +} + +// IMulticall3Call3Value is an auto generated low-level Go binding around an user-defined struct. +type IMulticall3Call3Value struct { + Target common.Address + AllowFailure bool + Value *big.Int + CallData []byte +} + +// IMulticall3Result is an auto generated low-level Go binding around an user-defined struct. +type IMulticall3Result struct { + Success bool + ReturnData []byte +} + +// IMulticall3MetaData contains all meta data concerning the IMulticall3 contract. +var IMulticall3MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// IMulticall3ABI is the input ABI used to generate the binding from. +// Deprecated: Use IMulticall3MetaData.ABI instead. +var IMulticall3ABI = IMulticall3MetaData.ABI + +// IMulticall3 is an auto generated Go binding around an Ethereum contract. +type IMulticall3 struct { + IMulticall3Caller // Read-only binding to the contract + IMulticall3Transactor // Write-only binding to the contract + IMulticall3Filterer // Log filterer for contract events +} + +// IMulticall3Caller is an auto generated read-only Go binding around an Ethereum contract. +type IMulticall3Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticall3Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IMulticall3Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticall3Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IMulticall3Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticall3Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IMulticall3Session struct { + Contract *IMulticall3 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IMulticall3CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IMulticall3CallerSession struct { + Contract *IMulticall3Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IMulticall3TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IMulticall3TransactorSession struct { + Contract *IMulticall3Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IMulticall3Raw is an auto generated low-level Go binding around an Ethereum contract. +type IMulticall3Raw struct { + Contract *IMulticall3 // Generic contract binding to access the raw methods on +} + +// IMulticall3CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IMulticall3CallerRaw struct { + Contract *IMulticall3Caller // Generic read-only contract binding to access the raw methods on +} + +// IMulticall3TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IMulticall3TransactorRaw struct { + Contract *IMulticall3Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIMulticall3 creates a new instance of IMulticall3, bound to a specific deployed contract. +func NewIMulticall3(address common.Address, backend bind.ContractBackend) (*IMulticall3, error) { + contract, err := bindIMulticall3(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IMulticall3{IMulticall3Caller: IMulticall3Caller{contract: contract}, IMulticall3Transactor: IMulticall3Transactor{contract: contract}, IMulticall3Filterer: IMulticall3Filterer{contract: contract}}, nil +} + +// NewIMulticall3Caller creates a new read-only instance of IMulticall3, bound to a specific deployed contract. +func NewIMulticall3Caller(address common.Address, caller bind.ContractCaller) (*IMulticall3Caller, error) { + contract, err := bindIMulticall3(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IMulticall3Caller{contract: contract}, nil +} + +// NewIMulticall3Transactor creates a new write-only instance of IMulticall3, bound to a specific deployed contract. +func NewIMulticall3Transactor(address common.Address, transactor bind.ContractTransactor) (*IMulticall3Transactor, error) { + contract, err := bindIMulticall3(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IMulticall3Transactor{contract: contract}, nil +} + +// NewIMulticall3Filterer creates a new log filterer instance of IMulticall3, bound to a specific deployed contract. +func NewIMulticall3Filterer(address common.Address, filterer bind.ContractFilterer) (*IMulticall3Filterer, error) { + contract, err := bindIMulticall3(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IMulticall3Filterer{contract: contract}, nil +} + +// bindIMulticall3 binds a generic wrapper to an already deployed contract. +func bindIMulticall3(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IMulticall3MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IMulticall3 *IMulticall3Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IMulticall3.Contract.IMulticall3Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IMulticall3 *IMulticall3Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IMulticall3.Contract.IMulticall3Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IMulticall3 *IMulticall3Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IMulticall3.Contract.IMulticall3Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IMulticall3 *IMulticall3CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IMulticall3.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IMulticall3 *IMulticall3TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IMulticall3.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IMulticall3 *IMulticall3TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IMulticall3.Contract.contract.Transact(opts, method, params...) +} + +// Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Caller) Aggregate3(opts *bind.CallOpts, calls []IMulticall3Call3) ([]IMulticall3Result, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "aggregate3", calls) + + if err != nil { + return *new([]IMulticall3Result), err + } + + out0 := *abi.ConvertType(out[0], new([]IMulticall3Result)).(*[]IMulticall3Result) + + return out0, err + +} + +// Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Session) Aggregate3(calls []IMulticall3Call3) ([]IMulticall3Result, error) { + return _IMulticall3.Contract.Aggregate3(&_IMulticall3.CallOpts, calls) +} + +// Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3CallerSession) Aggregate3(calls []IMulticall3Call3) ([]IMulticall3Result, error) { + return _IMulticall3.Contract.Aggregate3(&_IMulticall3.CallOpts, calls) +} + +// Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Caller) Aggregate3Value(opts *bind.CallOpts, calls []IMulticall3Call3Value) ([]IMulticall3Result, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "aggregate3Value", calls) + + if err != nil { + return *new([]IMulticall3Result), err + } + + out0 := *abi.ConvertType(out[0], new([]IMulticall3Result)).(*[]IMulticall3Result) + + return out0, err + +} + +// Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Session) Aggregate3Value(calls []IMulticall3Call3Value) ([]IMulticall3Result, error) { + return _IMulticall3.Contract.Aggregate3Value(&_IMulticall3.CallOpts, calls) +} + +// Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3CallerSession) Aggregate3Value(calls []IMulticall3Call3Value) ([]IMulticall3Result, error) { + return _IMulticall3.Contract.Aggregate3Value(&_IMulticall3.CallOpts, calls) +} + +// BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Caller) BlockAndAggregate(opts *bind.CallOpts, calls []IMulticall3Call) (struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result +}, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "blockAndAggregate", calls) + + outstruct := new(struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result + }) + if err != nil { + return *outstruct, err + } + + outstruct.BlockNumber = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.BlockHash = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.ReturnData = *abi.ConvertType(out[2], new([]IMulticall3Result)).(*[]IMulticall3Result) + + return *outstruct, err + +} + +// BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Session) BlockAndAggregate(calls []IMulticall3Call) (struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result +}, error) { + return _IMulticall3.Contract.BlockAndAggregate(&_IMulticall3.CallOpts, calls) +} + +// BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3CallerSession) BlockAndAggregate(calls []IMulticall3Call) (struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result +}, error) { + return _IMulticall3.Contract.BlockAndAggregate(&_IMulticall3.CallOpts, calls) +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_IMulticall3 *IMulticall3Caller) GetBasefee(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getBasefee") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_IMulticall3 *IMulticall3Session) GetBasefee() (*big.Int, error) { + return _IMulticall3.Contract.GetBasefee(&_IMulticall3.CallOpts) +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_IMulticall3 *IMulticall3CallerSession) GetBasefee() (*big.Int, error) { + return _IMulticall3.Contract.GetBasefee(&_IMulticall3.CallOpts) +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_IMulticall3 *IMulticall3Caller) GetBlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getBlockHash", blockNumber) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_IMulticall3 *IMulticall3Session) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { + return _IMulticall3.Contract.GetBlockHash(&_IMulticall3.CallOpts, blockNumber) +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_IMulticall3 *IMulticall3CallerSession) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { + return _IMulticall3.Contract.GetBlockHash(&_IMulticall3.CallOpts, blockNumber) +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_IMulticall3 *IMulticall3Caller) GetBlockNumber(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getBlockNumber") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_IMulticall3 *IMulticall3Session) GetBlockNumber() (*big.Int, error) { + return _IMulticall3.Contract.GetBlockNumber(&_IMulticall3.CallOpts) +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_IMulticall3 *IMulticall3CallerSession) GetBlockNumber() (*big.Int, error) { + return _IMulticall3.Contract.GetBlockNumber(&_IMulticall3.CallOpts) +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_IMulticall3 *IMulticall3Caller) GetChainId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getChainId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_IMulticall3 *IMulticall3Session) GetChainId() (*big.Int, error) { + return _IMulticall3.Contract.GetChainId(&_IMulticall3.CallOpts) +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_IMulticall3 *IMulticall3CallerSession) GetChainId() (*big.Int, error) { + return _IMulticall3.Contract.GetChainId(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_IMulticall3 *IMulticall3Caller) GetCurrentBlockCoinbase(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getCurrentBlockCoinbase") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_IMulticall3 *IMulticall3Session) GetCurrentBlockCoinbase() (common.Address, error) { + return _IMulticall3.Contract.GetCurrentBlockCoinbase(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_IMulticall3 *IMulticall3CallerSession) GetCurrentBlockCoinbase() (common.Address, error) { + return _IMulticall3.Contract.GetCurrentBlockCoinbase(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_IMulticall3 *IMulticall3Caller) GetCurrentBlockDifficulty(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getCurrentBlockDifficulty") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_IMulticall3 *IMulticall3Session) GetCurrentBlockDifficulty() (*big.Int, error) { + return _IMulticall3.Contract.GetCurrentBlockDifficulty(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_IMulticall3 *IMulticall3CallerSession) GetCurrentBlockDifficulty() (*big.Int, error) { + return _IMulticall3.Contract.GetCurrentBlockDifficulty(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_IMulticall3 *IMulticall3Caller) GetCurrentBlockGasLimit(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getCurrentBlockGasLimit") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_IMulticall3 *IMulticall3Session) GetCurrentBlockGasLimit() (*big.Int, error) { + return _IMulticall3.Contract.GetCurrentBlockGasLimit(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_IMulticall3 *IMulticall3CallerSession) GetCurrentBlockGasLimit() (*big.Int, error) { + return _IMulticall3.Contract.GetCurrentBlockGasLimit(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_IMulticall3 *IMulticall3Caller) GetCurrentBlockTimestamp(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getCurrentBlockTimestamp") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_IMulticall3 *IMulticall3Session) GetCurrentBlockTimestamp() (*big.Int, error) { + return _IMulticall3.Contract.GetCurrentBlockTimestamp(&_IMulticall3.CallOpts) +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_IMulticall3 *IMulticall3CallerSession) GetCurrentBlockTimestamp() (*big.Int, error) { + return _IMulticall3.Contract.GetCurrentBlockTimestamp(&_IMulticall3.CallOpts) +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_IMulticall3 *IMulticall3Caller) GetEthBalance(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getEthBalance", addr) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_IMulticall3 *IMulticall3Session) GetEthBalance(addr common.Address) (*big.Int, error) { + return _IMulticall3.Contract.GetEthBalance(&_IMulticall3.CallOpts, addr) +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_IMulticall3 *IMulticall3CallerSession) GetEthBalance(addr common.Address) (*big.Int, error) { + return _IMulticall3.Contract.GetEthBalance(&_IMulticall3.CallOpts, addr) +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_IMulticall3 *IMulticall3Caller) GetLastBlockHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "getLastBlockHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_IMulticall3 *IMulticall3Session) GetLastBlockHash() ([32]byte, error) { + return _IMulticall3.Contract.GetLastBlockHash(&_IMulticall3.CallOpts) +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_IMulticall3 *IMulticall3CallerSession) GetLastBlockHash() ([32]byte, error) { + return _IMulticall3.Contract.GetLastBlockHash(&_IMulticall3.CallOpts) +} + +// TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Caller) TryAggregate(opts *bind.CallOpts, requireSuccess bool, calls []IMulticall3Call) ([]IMulticall3Result, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "tryAggregate", requireSuccess, calls) + + if err != nil { + return *new([]IMulticall3Result), err + } + + out0 := *abi.ConvertType(out[0], new([]IMulticall3Result)).(*[]IMulticall3Result) + + return out0, err + +} + +// TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Session) TryAggregate(requireSuccess bool, calls []IMulticall3Call) ([]IMulticall3Result, error) { + return _IMulticall3.Contract.TryAggregate(&_IMulticall3.CallOpts, requireSuccess, calls) +} + +// TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3CallerSession) TryAggregate(requireSuccess bool, calls []IMulticall3Call) ([]IMulticall3Result, error) { + return _IMulticall3.Contract.TryAggregate(&_IMulticall3.CallOpts, requireSuccess, calls) +} + +// TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Caller) TryBlockAndAggregate(opts *bind.CallOpts, requireSuccess bool, calls []IMulticall3Call) (struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result +}, error) { + var out []interface{} + err := _IMulticall3.contract.Call(opts, &out, "tryBlockAndAggregate", requireSuccess, calls) + + outstruct := new(struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result + }) + if err != nil { + return *outstruct, err + } + + outstruct.BlockNumber = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.BlockHash = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.ReturnData = *abi.ConvertType(out[2], new([]IMulticall3Result)).(*[]IMulticall3Result) + + return *outstruct, err + +} + +// TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3Session) TryBlockAndAggregate(requireSuccess bool, calls []IMulticall3Call) (struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result +}, error) { + return _IMulticall3.Contract.TryBlockAndAggregate(&_IMulticall3.CallOpts, requireSuccess, calls) +} + +// TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_IMulticall3 *IMulticall3CallerSession) TryBlockAndAggregate(requireSuccess bool, calls []IMulticall3Call) (struct { + BlockNumber *big.Int + BlockHash [32]byte + ReturnData []IMulticall3Result +}, error) { + return _IMulticall3.Contract.TryBlockAndAggregate(&_IMulticall3.CallOpts, requireSuccess, calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_IMulticall3 *IMulticall3Transactor) Aggregate(opts *bind.TransactOpts, calls []IMulticall3Call) (*types.Transaction, error) { + return _IMulticall3.contract.Transact(opts, "aggregate", calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_IMulticall3 *IMulticall3Session) Aggregate(calls []IMulticall3Call) (*types.Transaction, error) { + return _IMulticall3.Contract.Aggregate(&_IMulticall3.TransactOpts, calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_IMulticall3 *IMulticall3TransactorSession) Aggregate(calls []IMulticall3Call) (*types.Transaction, error) { + return _IMulticall3.Contract.Aggregate(&_IMulticall3.TransactOpts, calls) +} diff --git a/backend/internal/contracts/multicall.go b/backend/internal/contracts/multicall.go new file mode 100644 index 000000000..0bb821cf0 --- /dev/null +++ b/backend/internal/contracts/multicall.go @@ -0,0 +1,666 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contracts + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// Multicall3Call is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Call struct { + Target common.Address + CallData []byte +} + +// Multicall3Call3 is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Call3 struct { + Target common.Address + AllowFailure bool + CallData []byte +} + +// Multicall3Call3Value is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Call3Value struct { + Target common.Address + AllowFailure bool + Value *big.Int + CallData []byte +} + +// Multicall3Result is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Result struct { + Success bool + ReturnData []byte +} + +// MulticallMetaData contains all meta data concerning the Multicall contract. +var MulticallMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Bin: "0x6080604052348015600f57600080fd5b50610cd88061001f6000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461022f578063bce38bd71461024a578063c3077fa91461025d578063ee82ac5e1461027057600080fd5b80634d2301cc146101ce57806372425d9d146101f657806382ad56cb1461020957806386d516e81461021c57600080fd5b80633408e470116100c65780633408e47014610173578063399542e9146101865780633e64a696146101a857806342cbb15c146101bb57600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d61012836600461098c565b61028f565b6040516101119190610a89565b61014d61014836600461098c565b61047d565b604051610111929190610aa3565b34801561016757600080fd5b50436000190140610107565b34801561017f57600080fd5b5046610107565b610199610194366004610b0f565b6105f1565b60405161011193929190610b69565b3480156101b457600080fd5b5048610107565b3480156101c757600080fd5b5043610107565b3480156101da57600080fd5b506101076101e9366004610b91565b6001600160a01b03163190565b34801561020257600080fd5b5044610107565b61012d61021736600461098c565b61060c565b34801561022857600080fd5b5045610107565b34801561023b57600080fd5b50604051418152602001610111565b61012d610258366004610b0f565b61078e565b61019961026b36600461098c565b610921565b34801561027c57600080fd5b5061010761028b366004610bba565b4090565b60606000828067ffffffffffffffff8111156102ad576102ad610bd3565b6040519080825280602002602001820160405280156102f357816020015b6040805180820190915260008152606060208201528152602001906001900390816102cb5790505b5092503660005b8281101561041f57600085828151811061031657610316610be9565b6020026020010151905087878381811061033257610332610be9565b90506020028101906103449190610bff565b60408101359586019590935061035d6020850185610b91565b6001600160a01b0316816103746060870187610c1f565b604051610382929190610c66565b60006040518083038185875af1925050503d80600081146103bf576040519150601f19603f3d011682016040523d82523d6000602084013e6103c4565b606091505b5060208085019190915290151580845290850135176104155762461bcd60e51b6000526020600452601760245276135d5b1d1a58d85b1b0cce8818d85b1b0819985a5b1959604a1b60445260846000fd5b50506001016102fa565b508234146104745760405162461bcd60e51b815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561049a5761049a610bd3565b6040519080825280602002602001820160405280156104cd57816020015b60608152602001906001900390816104b85790505b5091503660005b828110156105e75760008787838181106104f0576104f0610be9565b90506020028101906105029190610c76565b92506105116020840184610b91565b6001600160a01b03166105276020850185610c1f565b604051610535929190610c66565b6000604051808303816000865af19150503d8060008114610572576040519150601f19603f3d011682016040523d82523d6000602084013e610577565b606091505b5086848151811061058a5761058a610be9565b60209081029190910101529050806105de5760405162461bcd60e51b8152602060048201526017602482015276135d5b1d1a58d85b1b0cce8818d85b1b0819985a5b1959604a1b604482015260640161046b565b506001016104d4565b5050509250929050565b438040606061060186868661078e565b905093509350939050565b6060818067ffffffffffffffff81111561062857610628610bd3565b60405190808252806020026020018201604052801561066e57816020015b6040805180820190915260008152606060208201528152602001906001900390816106465790505b5091503660005b8281101561047457600084828151811061069157610691610be9565b602002602001015190508686838181106106ad576106ad610be9565b90506020028101906106bf9190610c8c565b92506106ce6020840184610b91565b6001600160a01b03166106e46040850185610c1f565b6040516106f2929190610c66565b6000604051808303816000865af19150503d806000811461072f576040519150601f19603f3d011682016040523d82523d6000602084013e610734565b606091505b5060208084019190915290151580835290840135176107855762461bcd60e51b6000526020600452601760245276135d5b1d1a58d85b1b0cce8818d85b1b0819985a5b1959604a1b60445260646000fd5b50600101610675565b6060818067ffffffffffffffff8111156107aa576107aa610bd3565b6040519080825280602002602001820160405280156107f057816020015b6040805180820190915260008152606060208201528152602001906001900390816107c85790505b5091503660005b8281101561091757600084828151811061081357610813610be9565b6020026020010151905086868381811061082f5761082f610be9565b90506020028101906108419190610c76565b92506108506020840184610b91565b6001600160a01b03166108666020850185610c1f565b604051610874929190610c66565b6000604051808303816000865af19150503d80600081146108b1576040519150601f19603f3d011682016040523d82523d6000602084013e6108b6565b606091505b50602083015215158152871561090e57805161090e5760405162461bcd60e51b8152602060048201526017602482015276135d5b1d1a58d85b1b0cce8818d85b1b0819985a5b1959604a1b604482015260640161046b565b506001016107f7565b5050509392505050565b6000806060610932600186866105f1565b919790965090945092505050565b60008083601f84011261095257600080fd5b50813567ffffffffffffffff81111561096a57600080fd5b6020830191508360208260051b850101111561098557600080fd5b9250929050565b6000806020838503121561099f57600080fd5b823567ffffffffffffffff8111156109b657600080fd5b6109c285828601610940565b90969095509350505050565b6000815180845260005b818110156109f4576020818501810151868301820152016109d8565b506000602082860101526020601f19601f83011685010191505092915050565b600082825180855260208501945060208160051b8301016020850160005b83811015610a7d57601f1985840301885281518051151584526020810151905060406020850152610a6660408501826109ce565b6020998a0199909450929092019150600101610a32565b50909695505050505050565b602081526000610a9c6020830184610a14565b9392505050565b6000604082018483526040602084015280845180835260608501915060608160051b86010192506020860160005b82811015610b0257605f19878603018452610aed8583516109ce565b94506020938401939190910190600101610ad1565b5092979650505050505050565b600080600060408486031215610b2457600080fd5b83358015158114610b3457600080fd5b9250602084013567ffffffffffffffff811115610b5057600080fd5b610b5c86828701610940565b9497909650939450505050565b838152826020820152606060408201526000610b886060830184610a14565b95945050505050565b600060208284031215610ba357600080fd5b81356001600160a01b0381168114610a9c57600080fd5b600060208284031215610bcc57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008235607e19833603018112610c1557600080fd5b9190910192915050565b6000808335601e19843603018112610c3657600080fd5b83018035915067ffffffffffffffff821115610c5157600080fd5b60200191503681900382131561098557600080fd5b8183823760009101908152919050565b60008235603e19833603018112610c1557600080fd5b60008235605e19833603018112610c1557600080fdfea2646970667358221220b68503dc0ac20ad5ddfa89a54f47d7c1052291793ed559cb82213962478f7d7364736f6c634300081b0033", +} + +// MulticallABI is the input ABI used to generate the binding from. +// Deprecated: Use MulticallMetaData.ABI instead. +var MulticallABI = MulticallMetaData.ABI + +// MulticallBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use MulticallMetaData.Bin instead. +var MulticallBin = MulticallMetaData.Bin + +// DeployMulticall deploys a new Ethereum contract, binding an instance of Multicall to it. +func DeployMulticall(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Multicall, error) { + parsed, err := MulticallMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MulticallBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Multicall{MulticallCaller: MulticallCaller{contract: contract}, MulticallTransactor: MulticallTransactor{contract: contract}, MulticallFilterer: MulticallFilterer{contract: contract}}, nil +} + +// Multicall is an auto generated Go binding around an Ethereum contract. +type Multicall struct { + MulticallCaller // Read-only binding to the contract + MulticallTransactor // Write-only binding to the contract + MulticallFilterer // Log filterer for contract events +} + +// MulticallCaller is an auto generated read-only Go binding around an Ethereum contract. +type MulticallCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MulticallTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MulticallFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MulticallSession struct { + Contract *Multicall // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MulticallCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MulticallCallerSession struct { + Contract *MulticallCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MulticallTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MulticallTransactorSession struct { + Contract *MulticallTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MulticallRaw is an auto generated low-level Go binding around an Ethereum contract. +type MulticallRaw struct { + Contract *Multicall // Generic contract binding to access the raw methods on +} + +// MulticallCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MulticallCallerRaw struct { + Contract *MulticallCaller // Generic read-only contract binding to access the raw methods on +} + +// MulticallTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MulticallTransactorRaw struct { + Contract *MulticallTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMulticall creates a new instance of Multicall, bound to a specific deployed contract. +func NewMulticall(address common.Address, backend bind.ContractBackend) (*Multicall, error) { + contract, err := bindMulticall(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Multicall{MulticallCaller: MulticallCaller{contract: contract}, MulticallTransactor: MulticallTransactor{contract: contract}, MulticallFilterer: MulticallFilterer{contract: contract}}, nil +} + +// NewMulticallCaller creates a new read-only instance of Multicall, bound to a specific deployed contract. +func NewMulticallCaller(address common.Address, caller bind.ContractCaller) (*MulticallCaller, error) { + contract, err := bindMulticall(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MulticallCaller{contract: contract}, nil +} + +// NewMulticallTransactor creates a new write-only instance of Multicall, bound to a specific deployed contract. +func NewMulticallTransactor(address common.Address, transactor bind.ContractTransactor) (*MulticallTransactor, error) { + contract, err := bindMulticall(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MulticallTransactor{contract: contract}, nil +} + +// NewMulticallFilterer creates a new log filterer instance of Multicall, bound to a specific deployed contract. +func NewMulticallFilterer(address common.Address, filterer bind.ContractFilterer) (*MulticallFilterer, error) { + contract, err := bindMulticall(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MulticallFilterer{contract: contract}, nil +} + +// bindMulticall binds a generic wrapper to an already deployed contract. +func bindMulticall(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := MulticallMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Multicall *MulticallRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Multicall.Contract.MulticallCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Multicall *MulticallRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Multicall.Contract.MulticallTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Multicall *MulticallRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Multicall.Contract.MulticallTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Multicall *MulticallCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Multicall.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Multicall *MulticallTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Multicall.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Multicall *MulticallTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Multicall.Contract.contract.Transact(opts, method, params...) +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_Multicall *MulticallCaller) GetBasefee(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getBasefee") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_Multicall *MulticallSession) GetBasefee() (*big.Int, error) { + return _Multicall.Contract.GetBasefee(&_Multicall.CallOpts) +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_Multicall *MulticallCallerSession) GetBasefee() (*big.Int, error) { + return _Multicall.Contract.GetBasefee(&_Multicall.CallOpts) +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_Multicall *MulticallCaller) GetBlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getBlockHash", blockNumber) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_Multicall *MulticallSession) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { + return _Multicall.Contract.GetBlockHash(&_Multicall.CallOpts, blockNumber) +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_Multicall *MulticallCallerSession) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { + return _Multicall.Contract.GetBlockHash(&_Multicall.CallOpts, blockNumber) +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_Multicall *MulticallCaller) GetBlockNumber(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getBlockNumber") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_Multicall *MulticallSession) GetBlockNumber() (*big.Int, error) { + return _Multicall.Contract.GetBlockNumber(&_Multicall.CallOpts) +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_Multicall *MulticallCallerSession) GetBlockNumber() (*big.Int, error) { + return _Multicall.Contract.GetBlockNumber(&_Multicall.CallOpts) +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_Multicall *MulticallCaller) GetChainId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getChainId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_Multicall *MulticallSession) GetChainId() (*big.Int, error) { + return _Multicall.Contract.GetChainId(&_Multicall.CallOpts) +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_Multicall *MulticallCallerSession) GetChainId() (*big.Int, error) { + return _Multicall.Contract.GetChainId(&_Multicall.CallOpts) +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_Multicall *MulticallCaller) GetCurrentBlockCoinbase(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getCurrentBlockCoinbase") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_Multicall *MulticallSession) GetCurrentBlockCoinbase() (common.Address, error) { + return _Multicall.Contract.GetCurrentBlockCoinbase(&_Multicall.CallOpts) +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_Multicall *MulticallCallerSession) GetCurrentBlockCoinbase() (common.Address, error) { + return _Multicall.Contract.GetCurrentBlockCoinbase(&_Multicall.CallOpts) +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_Multicall *MulticallCaller) GetCurrentBlockDifficulty(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getCurrentBlockDifficulty") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_Multicall *MulticallSession) GetCurrentBlockDifficulty() (*big.Int, error) { + return _Multicall.Contract.GetCurrentBlockDifficulty(&_Multicall.CallOpts) +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_Multicall *MulticallCallerSession) GetCurrentBlockDifficulty() (*big.Int, error) { + return _Multicall.Contract.GetCurrentBlockDifficulty(&_Multicall.CallOpts) +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_Multicall *MulticallCaller) GetCurrentBlockGasLimit(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getCurrentBlockGasLimit") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_Multicall *MulticallSession) GetCurrentBlockGasLimit() (*big.Int, error) { + return _Multicall.Contract.GetCurrentBlockGasLimit(&_Multicall.CallOpts) +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_Multicall *MulticallCallerSession) GetCurrentBlockGasLimit() (*big.Int, error) { + return _Multicall.Contract.GetCurrentBlockGasLimit(&_Multicall.CallOpts) +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_Multicall *MulticallCaller) GetCurrentBlockTimestamp(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getCurrentBlockTimestamp") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_Multicall *MulticallSession) GetCurrentBlockTimestamp() (*big.Int, error) { + return _Multicall.Contract.GetCurrentBlockTimestamp(&_Multicall.CallOpts) +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_Multicall *MulticallCallerSession) GetCurrentBlockTimestamp() (*big.Int, error) { + return _Multicall.Contract.GetCurrentBlockTimestamp(&_Multicall.CallOpts) +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_Multicall *MulticallCaller) GetEthBalance(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getEthBalance", addr) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_Multicall *MulticallSession) GetEthBalance(addr common.Address) (*big.Int, error) { + return _Multicall.Contract.GetEthBalance(&_Multicall.CallOpts, addr) +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_Multicall *MulticallCallerSession) GetEthBalance(addr common.Address) (*big.Int, error) { + return _Multicall.Contract.GetEthBalance(&_Multicall.CallOpts, addr) +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_Multicall *MulticallCaller) GetLastBlockHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Multicall.contract.Call(opts, &out, "getLastBlockHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_Multicall *MulticallSession) GetLastBlockHash() ([32]byte, error) { + return _Multicall.Contract.GetLastBlockHash(&_Multicall.CallOpts) +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_Multicall *MulticallCallerSession) GetLastBlockHash() ([32]byte, error) { + return _Multicall.Contract.GetLastBlockHash(&_Multicall.CallOpts) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_Multicall *MulticallTransactor) Aggregate(opts *bind.TransactOpts, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.contract.Transact(opts, "aggregate", calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_Multicall *MulticallSession) Aggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.Aggregate(&_Multicall.TransactOpts, calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_Multicall *MulticallTransactorSession) Aggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.Aggregate(&_Multicall.TransactOpts, calls) +} + +// Aggregate3 is a paid mutator transaction binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallTransactor) Aggregate3(opts *bind.TransactOpts, calls []Multicall3Call3) (*types.Transaction, error) { + return _Multicall.contract.Transact(opts, "aggregate3", calls) +} + +// Aggregate3 is a paid mutator transaction binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallSession) Aggregate3(calls []Multicall3Call3) (*types.Transaction, error) { + return _Multicall.Contract.Aggregate3(&_Multicall.TransactOpts, calls) +} + +// Aggregate3 is a paid mutator transaction binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallTransactorSession) Aggregate3(calls []Multicall3Call3) (*types.Transaction, error) { + return _Multicall.Contract.Aggregate3(&_Multicall.TransactOpts, calls) +} + +// Aggregate3Value is a paid mutator transaction binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallTransactor) Aggregate3Value(opts *bind.TransactOpts, calls []Multicall3Call3Value) (*types.Transaction, error) { + return _Multicall.contract.Transact(opts, "aggregate3Value", calls) +} + +// Aggregate3Value is a paid mutator transaction binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallSession) Aggregate3Value(calls []Multicall3Call3Value) (*types.Transaction, error) { + return _Multicall.Contract.Aggregate3Value(&_Multicall.TransactOpts, calls) +} + +// Aggregate3Value is a paid mutator transaction binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallTransactorSession) Aggregate3Value(calls []Multicall3Call3Value) (*types.Transaction, error) { + return _Multicall.Contract.Aggregate3Value(&_Multicall.TransactOpts, calls) +} + +// BlockAndAggregate is a paid mutator transaction binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall *MulticallTransactor) BlockAndAggregate(opts *bind.TransactOpts, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.contract.Transact(opts, "blockAndAggregate", calls) +} + +// BlockAndAggregate is a paid mutator transaction binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall *MulticallSession) BlockAndAggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.BlockAndAggregate(&_Multicall.TransactOpts, calls) +} + +// BlockAndAggregate is a paid mutator transaction binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall *MulticallTransactorSession) BlockAndAggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.BlockAndAggregate(&_Multicall.TransactOpts, calls) +} + +// TryAggregate is a paid mutator transaction binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallTransactor) TryAggregate(opts *bind.TransactOpts, requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.contract.Transact(opts, "tryAggregate", requireSuccess, calls) +} + +// TryAggregate is a paid mutator transaction binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallSession) TryAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.TryAggregate(&_Multicall.TransactOpts, requireSuccess, calls) +} + +// TryAggregate is a paid mutator transaction binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall *MulticallTransactorSession) TryAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.TryAggregate(&_Multicall.TransactOpts, requireSuccess, calls) +} + +// TryBlockAndAggregate is a paid mutator transaction binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall *MulticallTransactor) TryBlockAndAggregate(opts *bind.TransactOpts, requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.contract.Transact(opts, "tryBlockAndAggregate", requireSuccess, calls) +} + +// TryBlockAndAggregate is a paid mutator transaction binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall *MulticallSession) TryBlockAndAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.TryBlockAndAggregate(&_Multicall.TransactOpts, requireSuccess, calls) +} + +// TryBlockAndAggregate is a paid mutator transaction binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall *MulticallTransactorSession) TryBlockAndAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall.Contract.TryBlockAndAggregate(&_Multicall.TransactOpts, requireSuccess, calls) +} diff --git a/backend/internal/contracts/token.go b/backend/internal/contracts/token.go new file mode 100644 index 000000000..559205c90 --- /dev/null +++ b/backend/internal/contracts/token.go @@ -0,0 +1,781 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contracts + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// TokenMetaData contains all meta data concerning the Token contract. +var TokenMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50604051610a51380380610a5183398101604081905261002f9161010d565b8181600361003d83826101ff565b50600461004a82826101ff565b50505050506102bd565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261007b57600080fd5b81516001600160401b0381111561009457610094610054565b604051601f8201601f19908116603f011681016001600160401b03811182821017156100c2576100c2610054565b6040528181528382016020018510156100da57600080fd5b60005b828110156100f9576020818601810151838301820152016100dd565b506000918101602001919091529392505050565b6000806040838503121561012057600080fd5b82516001600160401b0381111561013657600080fd5b6101428582860161006a565b602085015190935090506001600160401b0381111561016057600080fd5b61016c8582860161006a565b9150509250929050565b600181811c9082168061018a57607f821691505b6020821081036101aa57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156101fa57806000526020600020601f840160051c810160208510156101d75750805b601f840160051c820191505b818110156101f757600081556001016101e3565b50505b505050565b81516001600160401b0381111561021857610218610054565b61022c816102268454610176565b846101b0565b6020601f82116001811461026057600083156102485750848201515b600019600385901b1c1916600184901b1784556101f7565b600084815260208120601f198516915b828110156102905787850151825560209485019460019092019101610270565b50848210156102ae5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b610785806102cc6000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806340c10f191161006657806340c10f191461011857806370a082311461012d57806395d89b4114610156578063a9059cbb1461015e578063dd62ed3e1461017157600080fd5b806306fdde03146100a3578063095ea7b3146100c157806318160ddd146100e457806323b872dd146100f6578063313ce56714610109575b600080fd5b6100ab6101aa565b6040516100b891906105ce565b60405180910390f35b6100d46100cf366004610638565b61023c565b60405190151581526020016100b8565b6002545b6040519081526020016100b8565b6100d4610104366004610662565b610256565b604051601281526020016100b8565b61012b610126366004610638565b61027a565b005b6100e861013b36600461069f565b6001600160a01b031660009081526020819052604090205490565b6100ab610288565b6100d461016c366004610638565b610297565b6100e861017f3660046106c1565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6060600380546101b9906106f4565b80601f01602080910402602001604051908101604052809291908181526020018280546101e5906106f4565b80156102325780601f1061020757610100808354040283529160200191610232565b820191906000526020600020905b81548152906001019060200180831161021557829003601f168201915b5050505050905090565b60003361024a8185856102a5565b60019150505b92915050565b6000336102648582856102b7565b61026f85858561033a565b506001949350505050565b6102848282610399565b5050565b6060600480546101b9906106f4565b60003361024a81858561033a565b6102b283838360016103cf565b505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610334578181101561032557604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b610334848484840360006103cf565b50505050565b6001600160a01b03831661036457604051634b637e8f60e11b81526000600482015260240161031c565b6001600160a01b03821661038e5760405163ec442f0560e01b81526000600482015260240161031c565b6102b28383836104a4565b6001600160a01b0382166103c35760405163ec442f0560e01b81526000600482015260240161031c565b610284600083836104a4565b6001600160a01b0384166103f95760405163e602df0560e01b81526000600482015260240161031c565b6001600160a01b03831661042357604051634a1406b160e11b81526000600482015260240161031c565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561033457826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161049691815260200190565b60405180910390a350505050565b6001600160a01b0383166104cf5780600260008282546104c4919061072e565b909155506105419050565b6001600160a01b038316600090815260208190526040902054818110156105225760405163391434e360e21b81526001600160a01b0385166004820152602481018290526044810183905260640161031c565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661055d5760028054829003905561057c565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516105c191815260200190565b60405180910390a3505050565b602081526000825180602084015260005b818110156105fc57602081860181015160408684010152016105df565b506000604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b038116811461063357600080fd5b919050565b6000806040838503121561064b57600080fd5b6106548361061c565b946020939093013593505050565b60008060006060848603121561067757600080fd5b6106808461061c565b925061068e6020850161061c565b929592945050506040919091013590565b6000602082840312156106b157600080fd5b6106ba8261061c565b9392505050565b600080604083850312156106d457600080fd5b6106dd8361061c565b91506106eb6020840161061c565b90509250929050565b600181811c9082168061070857607f821691505b60208210810361072857634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561025057634e487b7160e01b600052601160045260246000fdfea2646970667358221220f70bc1a244241ba5852ffed0bb824df84a979af391f1f5c96cad02e666c8071464736f6c634300081b0033", +} + +// TokenABI is the input ABI used to generate the binding from. +// Deprecated: Use TokenMetaData.ABI instead. +var TokenABI = TokenMetaData.ABI + +// TokenBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use TokenMetaData.Bin instead. +var TokenBin = TokenMetaData.Bin + +// DeployToken deploys a new Ethereum contract, binding an instance of Token to it. +func DeployToken(auth *bind.TransactOpts, backend bind.ContractBackend, name_ string, symbol_ string) (common.Address, *types.Transaction, *Token, error) { + parsed, err := TokenMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(TokenBin), backend, name_, symbol_) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Token{TokenCaller: TokenCaller{contract: contract}, TokenTransactor: TokenTransactor{contract: contract}, TokenFilterer: TokenFilterer{contract: contract}}, nil +} + +// Token is an auto generated Go binding around an Ethereum contract. +type Token struct { + TokenCaller // Read-only binding to the contract + TokenTransactor // Write-only binding to the contract + TokenFilterer // Log filterer for contract events +} + +// TokenCaller is an auto generated read-only Go binding around an Ethereum contract. +type TokenCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenTransactor is an auto generated write-only Go binding around an Ethereum contract. +type TokenTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type TokenFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type TokenSession struct { + Contract *Token // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type TokenCallerSession struct { + Contract *TokenCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// TokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type TokenTransactorSession struct { + Contract *TokenTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TokenRaw is an auto generated low-level Go binding around an Ethereum contract. +type TokenRaw struct { + Contract *Token // Generic contract binding to access the raw methods on +} + +// TokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type TokenCallerRaw struct { + Contract *TokenCaller // Generic read-only contract binding to access the raw methods on +} + +// TokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type TokenTransactorRaw struct { + Contract *TokenTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewToken creates a new instance of Token, bound to a specific deployed contract. +func NewToken(address common.Address, backend bind.ContractBackend) (*Token, error) { + contract, err := bindToken(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Token{TokenCaller: TokenCaller{contract: contract}, TokenTransactor: TokenTransactor{contract: contract}, TokenFilterer: TokenFilterer{contract: contract}}, nil +} + +// NewTokenCaller creates a new read-only instance of Token, bound to a specific deployed contract. +func NewTokenCaller(address common.Address, caller bind.ContractCaller) (*TokenCaller, error) { + contract, err := bindToken(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &TokenCaller{contract: contract}, nil +} + +// NewTokenTransactor creates a new write-only instance of Token, bound to a specific deployed contract. +func NewTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenTransactor, error) { + contract, err := bindToken(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &TokenTransactor{contract: contract}, nil +} + +// NewTokenFilterer creates a new log filterer instance of Token, bound to a specific deployed contract. +func NewTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenFilterer, error) { + contract, err := bindToken(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &TokenFilterer{contract: contract}, nil +} + +// bindToken binds a generic wrapper to an already deployed contract. +func bindToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := TokenMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Token *TokenRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Token.Contract.TokenCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Token *TokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Token.Contract.TokenTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Token *TokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Token.Contract.TokenTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Token *TokenCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Token.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Token *TokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Token.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Token *TokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Token.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenCaller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Token.Contract.Allowance(&_Token.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenCallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Token.Contract.Allowance(&_Token.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenCaller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Token.Contract.BalanceOf(&_Token.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenCallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Token.Contract.BalanceOf(&_Token.CallOpts, account) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenSession) Decimals() (uint8, error) { + return _Token.Contract.Decimals(&_Token.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenCallerSession) Decimals() (uint8, error) { + return _Token.Contract.Decimals(&_Token.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenSession) Name() (string, error) { + return _Token.Contract.Name(&_Token.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenCallerSession) Name() (string, error) { + return _Token.Contract.Name(&_Token.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenCaller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenSession) Symbol() (string, error) { + return _Token.Contract.Symbol(&_Token.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenCallerSession) Symbol() (string, error) { + return _Token.Contract.Symbol(&_Token.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Token *TokenCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Token *TokenSession) TotalSupply() (*big.Int, error) { + return _Token.Contract.TotalSupply(&_Token.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Token *TokenCallerSession) TotalSupply() (*big.Int, error) { + return _Token.Contract.TotalSupply(&_Token.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Token *TokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "approve", spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Token *TokenSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Approve(&_Token.TransactOpts, spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Token *TokenTransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Approve(&_Token.TransactOpts, spender, value) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address account, uint256 value) returns() +func (_Token *TokenTransactor) Mint(opts *bind.TransactOpts, account common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "mint", account, value) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address account, uint256 value) returns() +func (_Token *TokenSession) Mint(account common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Mint(&_Token.TransactOpts, account, value) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address account, uint256 value) returns() +func (_Token *TokenTransactorSession) Mint(account common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Mint(&_Token.TransactOpts, account, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Token *TokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "transfer", to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Token *TokenSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Transfer(&_Token.TransactOpts, to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Token *TokenTransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Transfer(&_Token.TransactOpts, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Token *TokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "transferFrom", from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Token *TokenSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.TransferFrom(&_Token.TransactOpts, from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Token *TokenTransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.TransferFrom(&_Token.TransactOpts, from, to, value) +} + +// TokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Token contract. +type TokenApprovalIterator struct { + Event *TokenApproval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TokenApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TokenApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TokenApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TokenApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenApproval represents a Approval event raised by the Token contract. +type TokenApproval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Token *TokenFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*TokenApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &TokenApprovalIterator{contract: _Token.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Token *TokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *TokenApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TokenApproval) + if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Token *TokenFilterer) ParseApproval(log types.Log) (*TokenApproval, error) { + event := new(TokenApproval) + if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Token contract. +type TokenTransferIterator struct { + Event *TokenTransfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TokenTransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TokenTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TokenTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TokenTransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenTransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenTransfer represents a Transfer event raised by the Token contract. +type TokenTransfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Token *TokenFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenTransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &TokenTransferIterator{contract: _Token.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Token *TokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *TokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TokenTransfer) + if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Token *TokenFilterer) ParseTransfer(log types.Log) (*TokenTransfer, error) { + event := new(TokenTransfer) + if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/backend/internal/th/ethereum.go b/backend/internal/th/ethereum.go new file mode 100644 index 000000000..a67f2a3f5 --- /dev/null +++ b/backend/internal/th/ethereum.go @@ -0,0 +1,253 @@ +package th + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "net" + "testing" + + "github.com/Tangui-Bitfly/ethsimtracer" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/gobitfly/beaconchain/internal/contracts" +) + +type EOA struct { + *bind.TransactOpts + PrivateKey *ecdsa.PrivateKey +} + +const simulatedChainID = 1337 + +var ( + OneEther = big.NewInt(params.Ether) + DefaultTokenBalance = big.NewInt(100) +) + +func CreateEOA(t *testing.T) *EOA { + t.Helper() + + priv, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + opts, err := bind.NewKeyedTransactorWithChainID(priv, big.NewInt(simulatedChainID)) + if err != nil { + t.Fatal(err) + } + return &EOA{ + PrivateKey: priv, + TransactOpts: opts, + } +} + +type BlockchainBackend struct { + *ethsimtracer.Backend + BankAccount *EOA + ChainID int + Endpoint string + + rpc *rpc.Client +} + +func NewBackend(t *testing.T, accounts ...common.Address) *BlockchainBackend { + t.Helper() + + genesis := make(map[common.Address]types.Account) + for _, account := range accounts { + genesis[account] = types.Account{Balance: OneEther} + } + bankAccount := CreateEOA(t) + genesis[bankAccount.From] = types.Account{Balance: new(big.Int).Mul(big.NewInt(1000), OneEther)} + + log.SetDefault(log.NewLogger(log.DiscardHandler())) + port := mustFreePort(t) + bk := ethsimtracer.NewBackend(genesis, func(nodeConf *node.Config, ethConf *ethconfig.Config) { + nodeConf.HTTPModules = append(nodeConf.HTTPModules, "debug", "eth") + nodeConf.HTTPHost = "127.0.0.1" + nodeConf.HTTPPort = port + }) + endpoint := fmt.Sprintf("http://127.0.0.1:%d", port) + client, err := rpc.Dial(endpoint) + if err != nil { + t.Fatal(err) + } + return &BlockchainBackend{ + Backend: bk, + BankAccount: bankAccount, + ChainID: simulatedChainID, + Endpoint: endpoint, + rpc: client, + } +} + +func (b *BlockchainBackend) Client() *ethclient.Client { + return ethclient.NewClient(b.rpc) +} + +func (b *BlockchainBackend) FundOneEther(t *testing.T, to common.Address) string { + t.Helper() + + signedTx := b.MakeTx(t, b.BankAccount, &to, OneEther, nil) + if err := b.Client().SendTransaction(context.Background(), signedTx); err != nil { + t.Fatal(err) + } + + b.Commit() + return signedTx.Hash().Hex() +} + +func (b *BlockchainBackend) Fund(t *testing.T, to common.Address, amount *big.Int) string { + t.Helper() + + signedTx := b.MakeTx(t, b.BankAccount, &to, amount, nil) + if err := b.Client().SendTransaction(context.Background(), signedTx); err != nil { + t.Fatal(err) + } + b.Commit() + return signedTx.Hash().Hex() +} + +func (b *BlockchainBackend) MakeTx(t *testing.T, sender *EOA, to *common.Address, value *big.Int, data []byte) *types.Transaction { + t.Helper() + + signedTx, err := types.SignTx(b.MakeUnsignedTx(t, sender.From, to, value, data), types.LatestSignerForChainID(big.NewInt(int64(b.ChainID))), sender.PrivateKey) + if err != nil { + t.Errorf("could not sign tx: %v", err) + } + return signedTx +} + +func (b *BlockchainBackend) MakeUnsignedTx(t *testing.T, from common.Address, to *common.Address, value *big.Int, data []byte) *types.Transaction { + t.Helper() + + head, err := b.Backend.Client().HeaderByNumber(context.Background(), nil) + if err != nil { + t.Fatal(err) + } + gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei)) + chainID, err := b.Backend.Client().ChainID(context.Background()) + if err != nil { + t.Fatal(err) + } + nonce, err := b.Backend.Client().PendingNonceAt(context.Background(), from) + if err != nil { + t.Fatal(err) + } + return types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + GasTipCap: big.NewInt(params.GWei), + GasFeeCap: gasPrice, + Gas: 100000, + To: to, + Value: value, + Data: data, + }) +} + +func (b *BlockchainBackend) DeployContract(t *testing.T, contractData []byte) common.Address { + t.Helper() + + head, err := b.Backend.Client().HeaderByNumber(context.Background(), nil) + if err != nil { + t.Fatal(err) + } + gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei)) + chainID, err := b.Backend.Client().ChainID(context.Background()) + if err != nil { + t.Fatal(err) + } + nonce, err := b.Backend.Client().PendingNonceAt(context.Background(), b.BankAccount.From) + if err != nil { + t.Fatal(err) + } + tx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + GasTipCap: big.NewInt(params.GWei), + GasFeeCap: gasPrice, + Gas: 2000000, + Data: contractData, + }) + + signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(int64(b.ChainID))), b.BankAccount.PrivateKey) + if err != nil { + t.Errorf("could not sign tx: %v", err) + } + + if err := b.Client().SendTransaction(context.Background(), signedTx); err != nil { + t.Fatal(err) + } + b.Commit() + + receipt, err := b.Client().TransactionReceipt(context.Background(), signedTx.Hash()) + if err != nil { + t.Fatal(err) + } + if receipt == nil { + t.Fatal("empty receipt") + } + if (receipt.ContractAddress == common.Address{}) { + t.Fatal("expected actual deployed contracts address") + } + + return receipt.ContractAddress +} + +func (b *BlockchainBackend) DeployToken(t *testing.T, name string, symbol string, accounts ...common.Address) (common.Address, *contracts.Token) { + t.Helper() + address, _, token, err := contracts.DeployToken(b.BankAccount.TransactOpts, b.Client(), name, symbol) + if err != nil { + t.Fatal(err) + } + b.Commit() + + for _, account := range accounts { + _, err := token.Mint(b.BankAccount.TransactOpts, account, DefaultTokenBalance) + if err != nil { + t.Fatal(err) + } + b.Commit() + } + return address, token +} + +func (b *BlockchainBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + return b.Client().CallContract(ctx, call, blockNumber) +} + +func (b *BlockchainBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { + return b.Client().SendTransaction(ctx, tx) +} + +func (b *BlockchainBackend) Commit() { + b.Backend.Commit() +} + +func mustFreePort(t *testing.T) int { + addr, err := net.ResolveTCPAddr("tcp", "localhost:0") + if err != nil { + t.Fatal(err) + } + l, err := net.ListenTCP("tcp", addr) + if err != nil { + t.Fatal(err) + } + if err := l.Close(); err != nil { + t.Fatal(err) + } + return l.Addr().(*net.TCPAddr).Port +} diff --git a/backend/pkg/commons/chain/chainID.go b/backend/pkg/commons/chain/chainID.go new file mode 100644 index 000000000..6fe78a1d0 --- /dev/null +++ b/backend/pkg/commons/chain/chainID.go @@ -0,0 +1,25 @@ +package chain + +import ( + "math/big" +) + +type IDGetter struct { + Mainnet *big.Int + Sepolia *big.Int + Gnosis *big.Int + Optimistic *big.Int + Arbitrum *big.Int +} + +var DefaultIDs = IDGetter{ + Mainnet: big.NewInt(1), + Sepolia: big.NewInt(11155111), + Gnosis: big.NewInt(100), + Optimistic: big.NewInt(10), + Arbitrum: big.NewInt(42161), +} + +// IDs is a global variable containing all the chain ids +// it can be modified in test but don't forget to reset it to DefaultIDs +var IDs = DefaultIDs diff --git a/backend/pkg/commons/db2/database/bigtable.go b/backend/pkg/commons/db2/database/bigtable.go new file mode 100644 index 000000000..686a81cea --- /dev/null +++ b/backend/pkg/commons/db2/database/bigtable.go @@ -0,0 +1,508 @@ +package database + +import ( + "context" + "fmt" + "slices" + "sort" + "time" + + "cloud.google.com/go/bigtable" + "google.golang.org/api/option" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var ErrNotFound = fmt.Errorf("not found") + +const ( + timeout = time.Minute // Timeout duration for Bigtable operations +) + +type Item struct { + Family string + Column string + Data []byte +} + +type Row struct { + Key string + Values map[string][]byte +} + +type TableWrapper struct { + *BigTable + table string +} + +func Wrap(db *BigTable, table string) TableWrapper { + return TableWrapper{ + BigTable: db, + table: table, + } +} + +func (w TableWrapper) Add(key string, item Item, allowDuplicate bool) error { + if err := w.BigTable.Add(w.table, key, item, allowDuplicate); err != nil { + return fmt.Errorf("table %s: %w", w.table, err) + } + return nil +} + +func (w TableWrapper) Read(prefix string) ([]Row, error) { + res, err := w.BigTable.Read(w.table, prefix) + if err != nil { + return nil, fmt.Errorf("table %s: %w", w.table, err) + } + return res, nil +} + +func (w TableWrapper) GetLatestValue(key string) (*Row, error) { + res, err := w.BigTable.GetLatestValue(w.table, key) + if err != nil { + return nil, fmt.Errorf("table %s: %w", w.table, err) + } + return res, nil +} + +func (w TableWrapper) GetRow(key string) (*Row, error) { + res, err := w.BigTable.GetRow(w.table, key) + if err != nil { + return nil, fmt.Errorf("table %s: %w", w.table, err) + } + return res, nil +} + +func (w TableWrapper) GetRowKeys(prefix string, opts ...Option) ([]string, error) { + res, err := w.BigTable.GetRowKeys(w.table, prefix, opts...) + if err != nil { + return nil, fmt.Errorf("table %s: %w", w.table, err) + } + return res, nil +} + +func (w TableWrapper) BulkAdd(itemsByKey map[string][]Item, opts ...Option) error { + if err := w.BigTable.BulkAdd(w.table, itemsByKey, opts...); err != nil { + return fmt.Errorf("table %s: %w", w.table, err) + } + return nil +} + +func (w TableWrapper) GetRowsRange(high, low string, opts ...Option) ([]Row, error) { + res, err := w.BigTable.GetRowsRange(w.table, high, low, opts...) + if err != nil { + return nil, fmt.Errorf("table %s: %w", w.table, err) + } + return res, nil +} + +func (w TableWrapper) GetRowsWithKeys(keys []string) ([]Row, error) { + res, err := w.BigTable.GetRowsWithKeys(w.table, keys) + if err != nil { + return nil, fmt.Errorf("table %s: %w", w.table, err) + } + return res, nil +} + +// BigTable is a wrapper around Google Cloud Bigtable for storing and retrieving data +type BigTable struct { + client *bigtable.Client + admin *bigtable.AdminClient +} + +func NewBigTableWithClient(ctx context.Context, client *bigtable.Client, adminClient *bigtable.AdminClient, tablesAndFamilies map[string][]string) (*BigTable, error) { + // Initialize the Bigtable table and column family + if err := initTable(ctx, adminClient, tablesAndFamilies); err != nil { + return nil, err + } + + return &BigTable{client: client, admin: adminClient}, nil +} + +// NewBigTable initializes a new BigTable +// It returns a BigTable and an error if any part of the setup fails +// if tablesAndFamilies is not nil it will try to create the associated tables and families if not already presents +func NewBigTable(project, instance string, tablesAndFamilies map[string][]string, options ...option.ClientOption) (*BigTable, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + // Create an admin client to manage Bigtable tables + adminClient, err := bigtable.NewAdminClient(ctx, project, instance, options...) + if err != nil { + return nil, fmt.Errorf("could not create admin client: %v", err) + } + + // Create a Bigtable client for performing data operations + client, err := bigtable.NewClient(ctx, project, instance, options...) + if err != nil { + return nil, fmt.Errorf("could not create data operations client: %v", err) + } + + return NewBigTableWithClient(ctx, client, adminClient, tablesAndFamilies) +} + +// initTable creates the tables and column family in the Bigtable +func initTable(ctx context.Context, adminClient *bigtable.AdminClient, tablesAndFamilies map[string][]string) error { + for table, families := range tablesAndFamilies { + if err := createTableAndFamilies(ctx, adminClient, table, families...); err != nil { + return err + } + } + return nil +} + +func createTableAndFamilies(ctx context.Context, admin *bigtable.AdminClient, tableName string, familyNames ...string) error { + // Get the list of existing tables + tables, err := admin.Tables(ctx) + if err != nil { + return fmt.Errorf("could not fetch table list: %w", err) + } + + // Create the table if it doesn't exist + if !slices.Contains(tables, tableName) { + if err := admin.CreateTable(ctx, tableName); err != nil { + return fmt.Errorf("could not create table %s: %w", tableName, err) + } + } + + // Retrieve information about the table + tblInfo, err := admin.TableInfo(ctx, tableName) + if err != nil { + return fmt.Errorf("could not read info for table %s: %w", tableName, err) + } + + for _, familyName := range familyNames { + // Create the column family if it doesn't exist + if !slices.Contains(tblInfo.Families, familyName) { + if err := admin.CreateColumnFamily(ctx, tableName, familyName); err != nil { + return fmt.Errorf("could not create column family %s: %w", familyName, err) + } + } + } + return nil +} + +func (b BigTable) BulkAdd(table string, itemsByKey map[string][]Item, opts ...Option) error { + options := apply(opts) + + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + var keys []string + var muts []*bigtable.Mutation + for key, items := range itemsByKey { + mut := bigtable.NewMutation() + for _, item := range items { + mut.Set(item.Family, item.Column, bigtable.Timestamp(0), item.Data) + } + keys = append(keys, key) + muts = append(muts, mut) + } + bulk := &bulkMutations{ + Keys: keys, + Muts: muts, + } + sort.Sort(bulk) + for i := int64(0); i < int64(bulk.Len()); i = i + options.BatchSize { + from, to := i, i+options.BatchSize + if to > int64(bulk.Len()) { + to = int64(bulk.Len()) + } + errs, err := tbl.ApplyBulk(ctx, bulk.Keys[from:to], bulk.Muts[from:to]) + if err != nil { + return fmt.Errorf("cannot ApplyBulk err: %w", err) + } + var bulkErrs []string + for _, err := range errs { + bulkErrs = append(bulkErrs, err.Error()) + } + if len(bulkErrs) > 0 { + return fmt.Errorf("cannot BulkAdd errors: %v", bulkErrs) + } + } + return nil +} + +// Add inserts a new row with the given key, column, and data into the Bigtable +// It applies a mutation that stores data in the receiver column family +// It returns error if the operation fails +func (b BigTable) Add(table, key string, item Item, allowDuplicate bool) error { + // Open the transfer table for data operations + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + // Create a new mutation to store data in the given column + mut := bigtable.NewMutation() + mut.Set(item.Family, item.Column, bigtable.Now(), item.Data) + + if !allowDuplicate { + mut = bigtable.NewCondMutation(bigtable.RowKeyFilter(key), nil, mut) + } + // Apply the mutation to the table using the given key + if err := tbl.Apply(ctx, key, mut); err != nil { + return fmt.Errorf("could not apply row mutation: %w", err) + } + return nil +} + +// Read retrieves all rows from the Bigtable's receiver column family +// It returns the data in the form of a 2D byte slice and an error if the operation fails +func (b BigTable) Read(table, prefix string) ([]Row, error) { + // Open the transfer table for reading + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + var rows []Row + // Read all rows from the table and collect values from the receiver column family + err := tbl.ReadRows(ctx, bigtable.PrefixRange(prefix), func(row bigtable.Row) bool { + values := make(map[string][]byte) + for _, family := range row { + for _, item := range family { + values[item.Column] = item.Value + } + } + rows = append(rows, Row{ + Key: row.Key(), + Values: values, + }) + return true + }) + if err != nil { + return nil, fmt.Errorf("could not read rows: %w", err) + } + + return rows, nil +} + +func (b BigTable) GetLatestValue(table, key string) (*Row, error) { + // Open the transfer table for reading + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + var data Row + err := tbl.ReadRows(ctx, bigtable.PrefixRange(key), func(row bigtable.Row) bool { + values := make(map[string][]byte) + for _, family := range row { + for _, item := range family { + values[item.Column] = item.Value + } + } + data = Row{ + Key: row.Key(), + Values: values, + } + return true + }) + + if err != nil { + return nil, fmt.Errorf("could not read rows: %w", err) + } + + return &data, nil +} + +func (b BigTable) GetRow(table, key string) (*Row, error) { + // Open the transfer table for reading + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + var data *Row + row, err := tbl.ReadRow(ctx, key) + if err != nil { + return nil, fmt.Errorf("could not read row: %w", err) + } + if row == nil { + return nil, ErrNotFound + } + values := make(map[string][]byte) + for _, family := range row { + for _, item := range family { + values[item.Column] = item.Value + } + } + data = &Row{ + Key: row.Key(), + Values: values, + } + + return data, nil +} + +func (b BigTable) GetRowsRange(table, high, low string, opts ...Option) ([]Row, error) { + options := apply(opts) + + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + rowRange := bigtable.NewClosedRange(low, high) + if options.OpenRange { + rowRange = bigtable.NewOpenRange(low, high) + } + if options.OpenCloseRange { + rowRange = bigtable.NewOpenClosedRange(low, high) + } + if options.ClosedOpenRange { + rowRange = bigtable.NewClosedOpenRange(low, high) + } + readOptions := bigtableReadOptions(options, rowRange) + if options.RowKeyFilter != "" { + readOptions = append(readOptions, bigtable.RowFilter(bigtable.RowKeyFilter(options.RowKeyFilter))) + } + var data []Row + err := tbl.ReadRows(ctx, rowRange, func(row bigtable.Row) bool { + values := make(map[string][]byte) + for _, family := range row { + for _, item := range family { + values[item.Column] = item.Value + } + } + data = append(data, Row{ + Key: row.Key(), + Values: values, + }) + return true + }, readOptions...) + if err != nil { + return nil, fmt.Errorf("could not read rows: %w", err) + } + if len(data) == 0 { + return nil, ErrNotFound + } + + return data, nil +} + +func (b BigTable) GetRowKeys(table, prefix string, opts ...Option) ([]string, error) { + options := apply(opts) + + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + rowRange := bigtable.PrefixRange(prefix) + readOptions := bigtableReadOptions(options, bigtable.PrefixRange(prefix)) + var data []string + err := tbl.ReadRows(ctx, rowRange, func(row bigtable.Row) bool { + data = append(data, row.Key()) + return true + }, readOptions...) + if err != nil { + return nil, fmt.Errorf("could not read rows: %w", err) + } + + return data, nil +} + +func (b BigTable) GetRowsWithKeys(table string, keys []string) ([]Row, error) { + tbl := b.client.Open(table) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + var data []Row + err := tbl.ReadRows(ctx, bigtable.RowList(keys), func(row bigtable.Row) bool { + values := make(map[string][]byte) + for _, family := range row { + for _, item := range family { + values[item.Column] = item.Value + } + } + data = append(data, Row{ + Key: row.Key(), + Values: values, + }) + return true + }) + + if err != nil { + return nil, fmt.Errorf("could not read rows: %w", err) + } + if len(data) == 0 { + return nil, ErrNotFound + } + + return data, nil +} + +func (b BigTable) Clear() error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + tables, err := b.admin.Tables(ctx) + if err != nil { + return err + } + for _, table := range tables { + if err := b.admin.DropAllRows(ctx, table); err != nil { + return fmt.Errorf("could not drop all rows: %w", err) + } + } + return nil +} + +// Close shuts down the BigTable by closing the Bigtable client connection +// It returns an error if the operation fails +func (b BigTable) Close() error { + if b.client == nil { + return fmt.Errorf("cannot close client: bigtable client is nil") + } + if err := b.client.Close(); err != nil && status.Code(err) != codes.Canceled { + return fmt.Errorf("cannot close client: %w", err) + } + if b.admin != nil { + if err := b.admin.Close(); err != nil && status.Code(err) != codes.Canceled { + return fmt.Errorf("cannot close admin client: %w", err) + } + } + return nil +} + +type bulkMutations struct { + Keys []string + Muts []*bigtable.Mutation +} + +func (bulkMutations *bulkMutations) Len() int { + return len(bulkMutations.Keys) +} + +func (bulkMutations *bulkMutations) Less(i, j int) bool { + return bulkMutations.Keys[i] < bulkMutations.Keys[j] +} + +func (bulkMutations *bulkMutations) Swap(i, j int) { + bulkMutations.Keys[i], bulkMutations.Keys[j] = bulkMutations.Keys[j], bulkMutations.Keys[i] + bulkMutations.Muts[i], bulkMutations.Muts[j] = bulkMutations.Muts[j], bulkMutations.Muts[i] +} + +const ( + KeyStatRange = "range" + KeyStatRowsSeen = "rowsSeen" + KeyStatRowsReturned = "rowsReturned" + KeyStatEfficiency = "efficiency" +) + +func bigtableReadOptions(options options, rowRange bigtable.RowRange) []bigtable.ReadOption { + readOptions := []bigtable.ReadOption{bigtable.LimitRows(options.Limit)} + if options.StatsReporter != nil { + readOptions = append(readOptions, bigtable.WithFullReadStats(func(stats *bigtable.FullReadStats) { + efficiency := int64(1) + if stats.ReadIterationStats.RowsSeenCount != 0 { + efficiency = stats.ReadIterationStats.RowsReturnedCount / stats.ReadIterationStats.RowsSeenCount + } + options.StatsReporter( + "query stats", + KeyStatRange, rowRange.String(), + KeyStatRowsSeen, stats.ReadIterationStats.RowsSeenCount, + KeyStatRowsReturned, stats.ReadIterationStats.RowsReturnedCount, + KeyStatEfficiency, efficiency, + ) + })) + } + return readOptions +} diff --git a/backend/pkg/commons/db2/database/bigtable_test.go b/backend/pkg/commons/db2/database/bigtable_test.go new file mode 100644 index 000000000..8e559b1ba --- /dev/null +++ b/backend/pkg/commons/db2/database/bigtable_test.go @@ -0,0 +1,278 @@ +package database + +import ( + "bytes" + "context" + "errors" + "fmt" + "reflect" + "slices" + "strings" + "testing" + + "cloud.google.com/go/bigtable/bttest" + "golang.org/x/exp/maps" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/database/databasetest" +) + +func TestNewBigTable(t *testing.T) { + srv, err := bttest.NewServer("localhost:0") + if err != nil { + t.Fatal(err) + } + + conn, err := grpc.NewClient(srv.Addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + t.Fatal(err) + } + + testTable, testFamily := "table", "family" + bt, err := NewBigTable("testProject", "testInstance", map[string][]string{testTable: {testFamily}}, option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + tableInfo, err := bt.admin.TableInfo(context.Background(), testTable) + if err != nil { + t.Fatal(err) + } + if got, want := tableInfo.Families, []string{testFamily}; !reflect.DeepEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestBigTable(t *testing.T) { + tests := []struct { + name string + bulk bool + items map[string][]Item + expected []string + }{ + { + name: "simple add", + items: map[string][]Item{ + "foo": { + {Column: "bar", Data: []byte("foobar")}, + }, + }, + expected: []string{"foobar"}, + }, + { + name: "bulk add", + bulk: true, + items: map[string][]Item{ + "key1": { + {Column: "col1", Data: []byte("foobar")}, + }, + "key2": { + {Column: "col2", Data: []byte("foobar")}, + }, + "key3": { + {Column: "col3", Data: []byte("foobar")}, + }, + }, + expected: []string{"foobar", "foobar", "foobar"}, + }, + { + name: "with a prefix", + items: map[string][]Item{ + "foo": {{}}, + "foofoo": {{}}, + "foofoofoo": {{}}, + "bar": {{}}, + }, + expected: []string{"", "", "", ""}, + }, + } + tables := map[string][]string{"testTable": {""}} + client, admin := databasetest.NewBigTable(t) + bt, err := NewBigTableWithClient(context.Background(), client, admin, tables) + if err != nil { + t.Fatal(err) + } + db := Wrap(bt, "testTable") + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + defer func() { + _ = db.Clear() + }() + + if err := db.BulkAdd(tt.items, WithBatchSize(2)); err != nil { + t.Error(err) + } + + t.Run("Read", func(t *testing.T) { + res, err := db.Read("") + if err != nil { + t.Error(err) + } + if got, want := len(res), len(tt.expected); got != want { + t.Errorf("got %v want %v", got, want) + } + for _, row := range res { + for _, v := range row.Values { + if !slices.Contains(tt.expected, string(v)) { + t.Errorf("wrong data %s", row) + } + } + } + }) + + t.Run("GetLatestValue", func(t *testing.T) { + for key, items := range tt.items { + v, err := db.GetLatestValue(key) + if err != nil { + t.Error(err) + } + for _, it := range items { + if got, want := string(v.Values[fmt.Sprintf("%s:%s", it.Family, it.Column)]), string(it.Data); got != want { + t.Errorf("got %v want %v", got, want) + } + } + } + }) + + t.Run("GetRowKeys", func(t *testing.T) { + for key := range tt.items { + keys, err := db.GetRowKeys(key) + if err != nil { + t.Error(err) + } + count, found := 0, false + for expectedKey := range tt.items { + if !strings.HasPrefix(expectedKey, key) { + continue + } + // don't count duplicate inputs since the add prevent duplicate keys + if expectedKey == key && found { + continue + } + found = expectedKey == key + count++ + if !slices.Contains(keys, expectedKey) { + t.Errorf("missing %v in %v", expectedKey, keys) + } + } + if got, want := len(keys), count; got != want { + t.Errorf("got %v want %v", got, want) + } + } + }) + + t.Run("GetRow", func(t *testing.T) { + for key, items := range tt.items { + row, err := db.GetRow(key) + if err != nil { + t.Error(err) + } + if got, want := row.Key, key; got != want { + t.Errorf("got %v want %v", got, want) + } + for _, it := range items { + if got, want := string(row.Values[fmt.Sprintf("%s:%s", it.Family, it.Column)]), string(it.Data); got != want { + t.Errorf("got %v want %v", got, want) + } + } + } + _, err := db.GetRow("key does not exist") + if !errors.Is(err, ErrNotFound) { + t.Errorf("expected ErrNotFound got %v", err) + } + }) + + t.Run("GetRowsWithKeys", func(t *testing.T) { + rows, err := db.GetRowsWithKeys(maps.Keys(tt.items)) + if err != nil { + t.Error(err) + } + for _, row := range rows { + expected := make(map[string][]byte) + for i := 0; i < len(tt.items[row.Key]); i++ { + it := tt.items[row.Key][i] + expected[fmt.Sprintf("%s:%s", it.Family, it.Column)] = it.Data + } + if got, want := row.Values, expected; !maps.EqualFunc(got, want, func(b1 []byte, b2 []byte) bool { return bytes.Equal(b1, b2) }) { + t.Errorf("got %v want %v", got, want) + } + } + }) + }) + } + + if err := db.Close(); err != nil { + t.Errorf("cannot close db: %v", err) + } +} + +func TestGetRowsRange(t *testing.T) { + tables := map[string][]string{"testTable": {""}} + client, admin := databasetest.NewBigTable(t) + bt, err := NewBigTableWithClient(context.Background(), client, admin, tables) + if err != nil { + t.Fatal(err) + } + db := Wrap(bt, "testTable") + + tests := []struct { + name string + txs int // must be inferior or equal to 10, otherwise padding is necessary + expected int + options []Option + }{ + { + name: "closed range", + txs: 3, + expected: 3, + }, + { + name: "open range", + txs: 3, + expected: 1, + options: []Option{WithOpenRange(true)}, + }, + { + name: "open close range", + txs: 3, + expected: 2, + options: []Option{WithOpenCloseRange(true)}, + }, + { + name: "with limit", + txs: 9, + expected: 5, + options: []Option{WithLimit(5)}, + }, + { + name: "with stats", + txs: 1, + expected: 1, + options: []Option{WithStats(func(msg string, args ...any) {})}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + high, low := "", "" + for i := 0; i < tt.txs; i++ { + key := fmt.Sprintf("%d", 9-i) + if i == 0 { + high = key + } + if i == tt.txs-1 { + low = key + } + _ = db.Add(key, Item{}, false) + } + rows, err := db.GetRowsRange(high, low, tt.options...) + if err != nil { + t.Error(err) + } + if got, want := len(rows), tt.expected; got != want { + t.Errorf("got %v want %v", got, want) + } + }) + } +} diff --git a/backend/pkg/commons/db2/database/databasetest/bigtable.go b/backend/pkg/commons/db2/database/databasetest/bigtable.go new file mode 100644 index 000000000..9ef66d88a --- /dev/null +++ b/backend/pkg/commons/db2/database/databasetest/bigtable.go @@ -0,0 +1,40 @@ +package databasetest + +import ( + "context" + "testing" + + "cloud.google.com/go/bigtable" + "cloud.google.com/go/bigtable/bttest" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func NewBigTable(t testing.TB) (*bigtable.Client, *bigtable.AdminClient) { + t.Helper() + srv, err := bttest.NewServer("localhost:0") + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + t.Cleanup(func() { srv.Close() }) + + conn, err := grpc.NewClient(srv.Addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + t.Fatal(err) + } + + project, instance := "proj", "instance" + adminClient, err := bigtable.NewAdminClient(ctx, project, instance, option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + + client, err := bigtable.NewClientWithConfig(ctx, project, instance, bigtable.ClientConfig{}, option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + + return client, adminClient +} diff --git a/backend/pkg/commons/db2/database/option.go b/backend/pkg/commons/db2/database/option.go new file mode 100644 index 000000000..cdcc64038 --- /dev/null +++ b/backend/pkg/commons/db2/database/option.go @@ -0,0 +1,108 @@ +package database + +const ( + defaultBatchSize = 10000 + defaultLimit = 100 +) + +type options struct { + OpenRange bool + OpenCloseRange bool + ClosedOpenRange bool + Limit int64 + BatchSize int64 + StatsReporter func(msg string, args ...any) + RowKeyFilter string +} + +func apply(opts []Option) options { + options := options{ + OpenRange: false, + OpenCloseRange: false, + ClosedOpenRange: false, + Limit: defaultLimit, + BatchSize: defaultBatchSize, + StatsReporter: nil, + RowKeyFilter: "", + } + for _, o := range opts { + o.apply(&options) + } + return options +} + +type Option interface { + apply(*options) +} + +type rowKeyFilterOption string + +func (r rowKeyFilterOption) apply(opts *options) { + opts.RowKeyFilter = string(r) +} + +func WithRowKeyFilter(regex string) Option { + return rowKeyFilterOption(regex) +} + +type openRangeOption bool + +func (r openRangeOption) apply(opts *options) { + opts.OpenRange = bool(r) +} + +func WithOpenRange(r bool) Option { + return openRangeOption(r) +} + +type openCloseRangeOption bool + +func (r openCloseRangeOption) apply(opts *options) { + opts.OpenCloseRange = bool(r) +} + +type closedOpenRangeOption bool + +func (r closedOpenRangeOption) apply(opts *options) { + opts.ClosedOpenRange = bool(r) +} + +func WithClosedOpenRangeOption(r bool) Option { + return closedOpenRangeOption(r) +} + +func WithOpenCloseRange(r bool) Option { + return openCloseRangeOption(r) +} + +type limitOption int64 + +func (l limitOption) apply(opts *options) { + opts.Limit = int64(l) +} + +func WithLimit(l int64) Option { + return limitOption(l) +} + +type withBatchSize int64 + +func (l withBatchSize) apply(opts *options) { + opts.BatchSize = int64(l) +} + +func WithBatchSize(l int64) Option { + return withBatchSize(l) +} + +type statsOption StatsReporter + +func (l statsOption) apply(opts *options) { + opts.StatsReporter = l +} + +func WithStats(reporter StatsReporter) Option { + return statsOption(reporter) +} + +type StatsReporter func(msg string, args ...any) diff --git a/backend/pkg/commons/db2/database/remote.go b/backend/pkg/commons/db2/database/remote.go new file mode 100644 index 000000000..6f05e9850 --- /dev/null +++ b/backend/pkg/commons/db2/database/remote.go @@ -0,0 +1,315 @@ +package database + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" +) + +const ( + routeBulkAdd = "/bulkAdd" + routeGetRowsRange = "/rowRange" + routeGetRow = "/row" + routeRead = "/read" + routeGetRowsWithKeys = "/rowsWithKeys" +) + +type RemoteServer struct { + db Database +} + +func NewRemote(db Database) RemoteServer { + return RemoteServer{db: db} +} + +func (api RemoteServer) Routes() http.Handler { + mux := http.NewServeMux() + mux.HandleFunc(routeBulkAdd, api.BulkAdd) + mux.HandleFunc(routeGetRowsRange, api.GetRowsRange) + mux.HandleFunc(routeGetRow, api.GetRow) + mux.HandleFunc(routeRead, api.Read) + mux.HandleFunc(routeGetRowsWithKeys, api.GetRowsWithKeys) + + return mux +} + +type ParamsBulkAdd struct { + Items map[string][]Item `json:"items"` +} + +func (api RemoteServer) BulkAdd(w http.ResponseWriter, r *http.Request) { + var args ParamsBulkAdd + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + respondWithErr(w, http.StatusBadRequest, err) + return + } + err := api.db.BulkAdd(args.Items) + if err != nil { + respondWithErr(w, http.StatusInternalServerError, err) + return + } + respond(w, nil) +} + +type ParamsGetRowsRange struct { + High string `json:"high"` + Low string `json:"low"` + Limit int64 `json:"limit"` + OpenRange bool `json:"open_range"` +} + +func (api RemoteServer) GetRowsRange(w http.ResponseWriter, r *http.Request) { + var args ParamsGetRowsRange + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + respondWithErr(w, http.StatusBadRequest, err) + return + } + rows, err := api.db.GetRowsRange(args.High, args.Low, WithOpenRange(args.OpenRange), WithLimit(args.Limit)) + if err != nil { + respondWithErr(w, http.StatusInternalServerError, err) + return + } + respond(w, rows) +} + +type ParamsGetRow struct { + Key string `json:"key"` +} + +func (api RemoteServer) GetRow(w http.ResponseWriter, r *http.Request) { + var args ParamsGetRow + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + respondWithErr(w, http.StatusBadRequest, err) + return + } + row, err := api.db.GetRow(args.Key) + if err != nil { + respondWithErr(w, http.StatusInternalServerError, err) + return + } + respond(w, row) +} + +type ParamsRead struct { + Prefix string `json:"prefix"` +} + +func (api RemoteServer) Read(w http.ResponseWriter, r *http.Request) { + var args ParamsRead + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + respondWithErr(w, http.StatusBadRequest, err) + return + } + rows, err := api.db.Read(args.Prefix) + if err != nil { + respondWithErr(w, http.StatusInternalServerError, err) + return + } + respond(w, rows) +} + +type ParamsGetRowsWithKeys struct { + Keys []string `json:"keys"` +} + +func (api RemoteServer) GetRowsWithKeys(w http.ResponseWriter, r *http.Request) { + var args ParamsGetRowsWithKeys + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + respondWithErr(w, http.StatusBadRequest, err) + return + } + rows, err := api.db.GetRowsWithKeys(args.Keys) + if err != nil { + respondWithErr(w, http.StatusInternalServerError, err) + return + } + respond(w, rows) +} + +func respond(w http.ResponseWriter, data any) { + b, err := json.Marshal(data) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(err.Error())) + return + } + _, _ = w.Write(b) +} + +func respondWithErr(w http.ResponseWriter, statusCode int, err error) { + w.WriteHeader(statusCode) + _, _ = w.Write([]byte(err.Error())) +} + +type RemoteClient struct { + url string +} + +func NewRemoteClient(url string) *RemoteClient { + return &RemoteClient{url: url} +} + +func (r RemoteClient) Add(key string, item Item, allowDuplicate bool) error { + //TODO implement me + panic("implement me") +} + +func (r RemoteClient) BulkAdd(itemsByKey map[string][]Item, opts ...Option) error { + b, err := json.Marshal(ParamsBulkAdd{Items: itemsByKey}) + if err != nil { + return err + } + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", r.url, routeBulkAdd), bytes.NewReader(b)) + if err != nil { + return err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + if ErrNotFound.Error() == string(b) { + return ErrNotFound + } + return fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, b) + } + return nil +} + +func (r RemoteClient) Read(prefix string) ([]Row, error) { + b, err := json.Marshal(ParamsRead{Prefix: prefix}) + if err != nil { + return nil, err + } + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", r.url, routeRead), bytes.NewReader(b)) + if err != nil { + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, b) + } + var rows []Row + if err := json.NewDecoder(resp.Body).Decode(&rows); err != nil { + return nil, err + } + return rows, nil +} + +func (r RemoteClient) GetRow(key string) (*Row, error) { + b, err := json.Marshal(ParamsGetRow{Key: key}) + if err != nil { + return nil, err + } + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", r.url, routeGetRow), bytes.NewReader(b)) + if err != nil { + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + if ErrNotFound.Error() == string(b) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, b) + } + var row Row + if err := json.NewDecoder(resp.Body).Decode(&row); err != nil { + return nil, err + } + return &row, nil +} + +func (r RemoteClient) GetRowKeys(prefix string, opts ...Option) ([]string, error) { + //TODO implement me + panic("implement me") +} + +func (r RemoteClient) GetLatestValue(key string) (*Row, error) { + //TODO implement me + panic("implement me") +} + +func (r RemoteClient) GetRowsRange(high, low string, opts ...Option) ([]Row, error) { + options := apply(opts) + b, err := json.Marshal(ParamsGetRowsRange{ + High: high, + Low: low, + Limit: options.Limit, + OpenRange: options.OpenRange, + }) + if err != nil { + return nil, err + } + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", r.url, routeGetRowsRange), bytes.NewReader(b)) + if err != nil { + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + if ErrNotFound.Error() == string(b) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, b) + } + var rows []Row + if err := json.NewDecoder(resp.Body).Decode(&rows); err != nil { + return nil, err + } + return rows, nil +} + +func (r RemoteClient) GetRowsWithKeys(keys []string) ([]Row, error) { + b, err := json.Marshal(ParamsGetRowsWithKeys{ + Keys: keys, + }) + if err != nil { + return nil, err + } + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", r.url, routeGetRowsWithKeys), bytes.NewReader(b)) + if err != nil { + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, b) + } + var rows []Row + if err := json.NewDecoder(resp.Body).Decode(&rows); err != nil { + return nil, err + } + return rows, nil +} + +func (r RemoteClient) Close() error { + //TODO implement me + panic("implement me") +} + +func (r RemoteClient) Clear() error { + //TODO implement me + panic("implement me") +} diff --git a/backend/pkg/commons/db2/database/remote_test.go b/backend/pkg/commons/db2/database/remote_test.go new file mode 100644 index 000000000..4a3a830ff --- /dev/null +++ b/backend/pkg/commons/db2/database/remote_test.go @@ -0,0 +1,83 @@ +package database + +import ( + "context" + "errors" + "net/http/httptest" + "testing" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/database/databasetest" +) + +func TestRemote(t *testing.T) { + tables := map[string][]string{"testTable": {""}} + btClient, admin := databasetest.NewBigTable(t) + bt, err := NewBigTableWithClient(context.Background(), btClient, admin, tables) + if err != nil { + t.Fatal(err) + } + db := Wrap(bt, "testTable") + + remote := NewRemote(db) + server := httptest.NewServer(remote.Routes()) + defer server.Close() + + client := NewRemoteClient(server.URL) + + itemsByKey := map[string][]Item{ + "foo": {{}}, + "bar": {{}}, + } + + if err := client.BulkAdd(itemsByKey); err != nil { + t.Fatalf("bulkAdd: %s", err) + } + + t.Run("Read", func(t *testing.T) { + res, err := client.Read("") + if err != nil { + t.Fatal(err) + } + if got, want := len(res), len(itemsByKey); got != want { + t.Fatalf("got %v, want %v", got, want) + } + }) + + t.Run("GetRow", func(t *testing.T) { + row, err := client.GetRow("foo") + if err != nil { + t.Fatal(err) + } + if row == nil { + t.Fatal("row is nil") + } + + if _, err := client.GetRow("key does not exist"); !errors.Is(err, ErrNotFound) { + t.Errorf("expected ErrNotFound got %v", err) + } + }) + + t.Run("GetRowsRange", func(t *testing.T) { + rows, err := client.GetRowsRange("foo", "bar") + if err != nil { + t.Fatal(err) + } + if rows == nil { + t.Fatal("rows is nil") + } + + if _, err := client.GetRowsRange("0", "1"); !errors.Is(err, ErrNotFound) { + t.Errorf("expected ErrNotFound got %v", err) + } + }) + + t.Run("GetRowsWithKeys", func(t *testing.T) { + rows, err := client.GetRowsWithKeys([]string{"foo", "bar"}) + if err != nil { + t.Fatal(err) + } + if rows == nil { + t.Fatal("rows is nil") + } + }) +} diff --git a/backend/pkg/commons/db2/database/store.go b/backend/pkg/commons/db2/database/store.go new file mode 100644 index 000000000..a6a8549b4 --- /dev/null +++ b/backend/pkg/commons/db2/database/store.go @@ -0,0 +1,20 @@ +package database + +type Database interface { + Add(key string, item Item, allowDuplicate bool) error + BulkAdd(itemsByKey map[string][]Item, opts ...Option) error + Read(prefix string) ([]Row, error) + GetRow(key string) (*Row, error) + GetRowsWithKeys(keys []string) ([]Row, error) + GetRowKeys(prefix string, opts ...Option) ([]string, error) + GetLatestValue(key string) (*Row, error) + GetRowsRange(high, low string, opts ...Option) ([]Row, error) + + Close() error + Clear() error +} + +var ( + _ Database = (*TableWrapper)(nil) + _ Database = (*RemoteClient)(nil) +) diff --git a/backend/pkg/commons/db2/jsonrpc/jsonrpc.go b/backend/pkg/commons/db2/jsonrpc/jsonrpc.go new file mode 100644 index 000000000..223fd209e --- /dev/null +++ b/backend/pkg/commons/db2/jsonrpc/jsonrpc.go @@ -0,0 +1,20 @@ +package jsonrpc + +import ( + "encoding/json" +) + +type Message struct { + Version string `json:"jsonrpc,omitempty"` + ID json.RawMessage `json:"id,omitempty"` + Method string `json:"method,omitempty"` + Params json.RawMessage `json:"params,omitempty"` + Error *Error `json:"error,omitempty"` + Result json.RawMessage `json:"result,omitempty"` +} + +type Error struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data,omitempty"` +} diff --git a/backend/pkg/commons/db2/raw/cache.go b/backend/pkg/commons/db2/raw/cache.go new file mode 100644 index 000000000..3e3e3b8de --- /dev/null +++ b/backend/pkg/commons/db2/raw/cache.go @@ -0,0 +1,119 @@ +package raw + +import ( + "encoding/json" + "sync" + "time" +) + +const ( + oneBlockTTL = 1 * time.Second + blocksTTL = 30 * time.Second // default ttl, if read it will be deleted sooner +) + +type MinimalBlock struct { + Result struct { + Hash string `json:"hash"` + } `json:"result"` +} + +type CachedStore struct { + store StoreReader + // sync.Map with manual delete have better perf than freecache because we can handle this way a ttl < 1s + cache sync.Map + + locks map[string]*sync.RWMutex + mapLock sync.Mutex // to make the map safe concurrently +} + +func WithCache(reader StoreReader) *CachedStore { + return &CachedStore{ + store: reader, + locks: make(map[string]*sync.RWMutex), + } +} + +func (c *CachedStore) lockBy(key string) func() { + c.mapLock.Lock() + defer c.mapLock.Unlock() + + lock, found := c.locks[key] + if !found { + lock = &sync.RWMutex{} + c.locks[key] = lock + lock.Lock() + return lock.Unlock + } + lock.RLock() + return lock.RUnlock +} + +func (c *CachedStore) ReadBlockByNumber(chainID uint64, number int64) (*FullBlockData, error) { + key := blockKey(chainID, number) + + unlock := c.lockBy(key) + defer unlock() + + v, ok := c.cache.Load(key) + if ok { + // once read ensure to delete it from the cache + go c.unCacheBlockAfter(key, "", oneBlockTTL) + return v.(*FullBlockData), nil + } + // TODO make warning not found in cache + block, err := c.store.ReadBlockByNumber(chainID, number) + if block != nil { + c.cacheBlock(block, oneBlockTTL) + } + return block, err +} + +func (c *CachedStore) cacheBlock(block *FullBlockData, ttl time.Duration) { + key := blockKey(block.ChainID, block.BlockNumber) + c.cache.Store(key, block) + + var mini MinimalBlock + if len(block.Uncles) != 0 { + // retrieve the block hash for caching but only if the block has uncle(s) + _ = json.Unmarshal(block.Block, &mini) + c.cache.Store(mini.Result.Hash, block.BlockNumber) + } + + go c.unCacheBlockAfter(key, mini.Result.Hash, ttl) +} + +func (c *CachedStore) unCacheBlockAfter(key, hash string, ttl time.Duration) { + time.Sleep(ttl) + c.cache.Delete(key) + c.mapLock.Lock() + if hash != "" { + c.cache.Delete(hash) + } + defer c.mapLock.Unlock() + delete(c.locks, key) +} + +func (c *CachedStore) ReadBlockByHash(chainID uint64, hash string) (*FullBlockData, error) { + v, ok := c.cache.Load(hash) + if !ok { + return c.store.ReadBlockByHash(chainID, hash) + } + + v, ok = c.cache.Load(blockKey(chainID, v.(int64))) + if !ok { + return c.store.ReadBlockByHash(chainID, hash) + } + + return v.(*FullBlockData), nil +} + +func (c *CachedStore) ReadBlocksByNumber(chainID uint64, start, end int64) ([]*FullBlockData, error) { + blocks, err := c.store.ReadBlocksByNumber(chainID, start, end) + if err != nil { + return nil, err + } + for _, block := range blocks { + c.cacheBlock(block, blocksTTL) + } + return blocks, nil +} diff --git a/backend/pkg/commons/db2/raw/client.go b/backend/pkg/commons/db2/raw/client.go new file mode 100644 index 000000000..56ffb3b9a --- /dev/null +++ b/backend/pkg/commons/db2/raw/client.go @@ -0,0 +1,239 @@ +package raw + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "math/big" + "net/http" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/database" + "github.com/gobitfly/beaconchain/pkg/commons/db2/jsonrpc" +) + +var ErrNotFoundInCache = fmt.Errorf("cannot find hash in cache") +var ErrMethodNotSupported = fmt.Errorf("method not supported") + +type StoreReader interface { + ReadBlockByNumber(chainID uint64, number int64) (*FullBlockData, error) + ReadBlockByHash(chainID uint64, hash string) (*FullBlockData, error) + ReadBlocksByNumber(chainID uint64, start, end int64) ([]*FullBlockData, error) +} + +type WithFallback struct { + roundTripper http.RoundTripper + fallback http.RoundTripper +} + +func NewWithFallback(roundTripper, fallback http.RoundTripper) *WithFallback { + return &WithFallback{ + roundTripper: roundTripper, + fallback: fallback, + } +} + +func (r WithFallback) RoundTrip(request *http.Request) (*http.Response, error) { + resp, err := r.roundTripper.RoundTrip(request) + if err == nil { + // no fallback needed + return resp, nil + } + + var e1 *json.SyntaxError + if !errors.As(err, &e1) && + !errors.Is(err, ErrNotFoundInCache) && + !errors.Is(err, ErrMethodNotSupported) && + !errors.Is(err, database.ErrNotFound) { + return nil, err + } + + return r.fallback.RoundTrip(request) +} + +type StoreRoundTripper struct { + store StoreReader + chainID uint64 +} + +func NewBigTableEthRaw(store StoreReader, chainID uint64) *StoreRoundTripper { + return &StoreRoundTripper{ + store: store, + chainID: chainID, + } +} + +func (r *StoreRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { + body, err := io.ReadAll(request.Body) + if err != nil { + return nil, err + } + defer func() { + request.Body = io.NopCloser(bytes.NewBuffer(body)) + }() + var messages []*jsonrpc.Message + var singleRequest bool + if err := json.NewDecoder(bytes.NewReader(body)).Decode(&messages); err != nil { + singleRequest = true + message := new(jsonrpc.Message) + if err := json.NewDecoder(bytes.NewReader(body)).Decode(message); err != nil { + return nil, err + } + messages = append(messages, message) + } + var resps []*jsonrpc.Message + for _, message := range messages { + resp, err := r.handle(request.Context(), message) + if err != nil { + return nil, err + } + resps = append(resps, resp) + } + + respBody, _ := makeBody(singleRequest, resps) + return &http.Response{ + Body: respBody, + StatusCode: http.StatusOK, + }, nil +} + +func (r *StoreRoundTripper) handle(ctx context.Context, message *jsonrpc.Message) (*jsonrpc.Message, error) { + var args []interface{} + err := json.Unmarshal(message.Params, &args) + if err != nil { + return nil, err + } + + var respBody []byte + switch message.Method { + case "eth_getBlockByNumber": + // we decode only big.Int maybe we should also handle "latest" + block, err := hexutil.DecodeBig(args[0].(string)) + if err != nil { + return nil, err + } + + respBody, err = r.BlockByNumber(ctx, block) + if err != nil { + return nil, err + } + + case "debug_traceBlockByNumber": + block, err := hexutil.DecodeBig(args[0].(string)) + if err != nil { + return nil, err + } + + respBody, err = r.TraceBlockByNumber(ctx, block) + if err != nil { + return nil, err + } + + case "eth_getBlockReceipts": + block, err := hexutil.DecodeBig(args[0].(string)) + if err != nil { + return nil, err + } + + respBody, err = r.BlockReceipts(ctx, block) + if err != nil { + return nil, err + } + + case "eth_getUncleByBlockHashAndIndex": + index, err := hexutil.DecodeBig(args[1].(string)) + if err != nil { + return nil, err + } + respBody, err = r.UncleByBlockHashAndIndex(ctx, args[0].(string), index.Int64()) + if err != nil { + return nil, err + } + default: + return nil, ErrMethodNotSupported + } + var resp jsonrpc.Message + _ = json.Unmarshal(respBody, &resp) + if len(respBody) == 0 { + resp.Version = message.Version + resp.Result = []byte("[]") + } + resp.ID = message.ID + return &resp, nil +} + +func makeBody(isSingle bool, messages []*jsonrpc.Message) (io.ReadCloser, error) { + var b []byte + var err error + if isSingle { + b, err = json.Marshal(messages[0]) + } else { + b, err = json.Marshal(messages) + } + if err != nil { + return nil, err + } + return io.NopCloser(bytes.NewReader(b)), nil +} + +func (r *StoreRoundTripper) BlockByNumber(ctx context.Context, number *big.Int) ([]byte, error) { + block, err := r.store.ReadBlockByNumber(r.chainID, number.Int64()) + if err != nil { + return nil, err + } + return block.Block, nil +} + +func (r *StoreRoundTripper) BlockReceipts(ctx context.Context, number *big.Int) ([]byte, error) { + block, err := r.store.ReadBlockByNumber(r.chainID, number.Int64()) + if err != nil { + return nil, err + } + return block.Receipts, nil +} + +func (r *StoreRoundTripper) TraceBlockByNumber(ctx context.Context, number *big.Int) ([]byte, error) { + block, err := r.store.ReadBlockByNumber(r.chainID, number.Int64()) + if err != nil { + return nil, err + } + return block.Traces, nil +} + +func (r *StoreRoundTripper) UncleByBlockNumberAndIndex(ctx context.Context, number *big.Int, index int64) ([]byte, error) { + block, err := r.store.ReadBlockByNumber(r.chainID, number.Int64()) + if err != nil { + return nil, err + } + + var uncles []*jsonrpc.Message + if err := json.Unmarshal(block.Uncles, &uncles); err != nil { + var uncle *jsonrpc.Message + if err := json.Unmarshal(block.Uncles, &uncle); err != nil { + return nil, fmt.Errorf("cannot unmarshal uncle: %w", err) + } + return json.Marshal(uncle) + } + return json.Marshal(uncles[index]) +} + +func (r *StoreRoundTripper) UncleByBlockHashAndIndex(ctx context.Context, hash string, index int64) ([]byte, error) { + block, err := r.store.ReadBlockByHash(r.chainID, hash) + if err != nil { + return nil, err + } + + var uncles []*jsonrpc.Message + if err := json.Unmarshal(block.Uncles, &uncles); err != nil { + var uncle *jsonrpc.Message + if err := json.Unmarshal(block.Uncles, &uncle); err != nil { + return nil, fmt.Errorf("cannot unmarshal uncle: %w", err) + } + return json.Marshal(uncle) + } + return json.Marshal(uncles[index]) +} diff --git a/backend/pkg/commons/db2/raw/client_test.go b/backend/pkg/commons/db2/raw/client_test.go new file mode 100644 index 000000000..c47c2336b --- /dev/null +++ b/backend/pkg/commons/db2/raw/client_test.go @@ -0,0 +1,307 @@ +package raw + +import ( + "context" + "math/big" + "net/http" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/database" + "github.com/gobitfly/beaconchain/pkg/commons/db2/database/databasetest" +) + +const ( + chainID uint64 = 1 +) + +func TestBigTableClientRealCondition(t *testing.T) { + project := os.Getenv("BIGTABLE_PROJECT") + instance := os.Getenv("BIGTABLE_INSTANCE") + if project == "" || instance == "" { + t.Skip("skipping test, set BIGTABLE_PROJECT and BIGTABLE_INSTANCE") + } + + tests := []struct { + name string + block int64 + }{ + { + name: "test block", + block: testBlockNumber, + }, + { + name: "test block two uncles", + block: testTwoUnclesBlockNumber, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bt, err := database.NewBigTable(project, instance, nil) + if err != nil { + t.Fatal(err) + } + + rawStore := NewStore(database.Wrap(bt, Table)) + rpcClient, err := rpc.DialOptions(context.Background(), "https://foo.bar", rpc.WithHTTPClient(&http.Client{ + Transport: NewBigTableEthRaw(rawStore, chainID), + })) + if err != nil { + t.Fatal(err) + } + ethClient := ethclient.NewClient(rpcClient) + + block, err := ethClient.BlockByNumber(context.Background(), big.NewInt(tt.block)) + if err != nil { + t.Fatalf("BlockByNumber() error = %v", err) + } + if got, want := block.Number().Int64(), tt.block; got != want { + t.Errorf("got %v, want %v", got, want) + } + + receipts, err := ethClient.BlockReceipts(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(tt.block))) + if err != nil { + t.Fatalf("BlockReceipts() error = %v", err) + } + if len(block.Transactions()) != 0 && len(receipts) == 0 { + t.Errorf("receipts should not be empty") + } + + var traces []GethTraceCallResultWrapper + if err := rpcClient.Call(&traces, "debug_traceBlockByNumber", hexutil.EncodeBig(block.Number()), gethTracerArg); err != nil { + t.Fatalf("debug_traceBlockByNumber() error = %v", err) + } + if len(block.Transactions()) != 0 && len(traces) == 0 { + t.Errorf("traces should not be empty") + } + }) + } +} + +func benchmarkBlockRetrieval(b *testing.B, ethClient *ethclient.Client, rpcClient *rpc.Client) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + blockTestNumber := int64(20978000 + b.N) + _, err := ethClient.BlockByNumber(context.Background(), big.NewInt(blockTestNumber)) + if err != nil { + b.Fatalf("BlockByNumber() error = %v", err) + } + + if _, err := ethClient.BlockReceipts(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(blockTestNumber))); err != nil { + b.Fatalf("BlockReceipts() error = %v", err) + } + + var traces []GethTraceCallResultWrapper + if err := rpcClient.Call(&traces, "debug_traceBlockByNumber", hexutil.EncodeBig(big.NewInt(blockTestNumber)), gethTracerArg); err != nil { + b.Fatalf("debug_traceBlockByNumber() error = %v", err) + } + } +} + +func BenchmarkErigonNode(b *testing.B) { + node := os.Getenv("ETH1_ERIGON_ENDPOINT") + if node == "" { + b.Skip("skipping test, please set ETH1_ERIGON_ENDPOINT") + } + + rpcClient, err := rpc.DialOptions(context.Background(), node) + if err != nil { + b.Fatal(err) + } + + benchmarkBlockRetrieval(b, ethclient.NewClient(rpcClient), rpcClient) +} + +func BenchmarkRawBigTable(b *testing.B) { + project := os.Getenv("BIGTABLE_PROJECT") + instance := os.Getenv("BIGTABLE_INSTANCE") + if project == "" || instance == "" { + b.Skip("skipping test, set BIGTABLE_PROJECT and BIGTABLE_INSTANCE") + } + + bt, err := database.NewBigTable(project, instance, nil) + if err != nil { + b.Fatal(err) + } + + rawStore := WithCache(NewStore(database.Wrap(bt, Table))) + rpcClient, err := rpc.DialOptions(context.Background(), "https://foo.bar", rpc.WithHTTPClient(&http.Client{ + Transport: NewBigTableEthRaw(rawStore, chainID), + })) + if err != nil { + b.Fatal(err) + } + + benchmarkBlockRetrieval(b, ethclient.NewClient(rpcClient), rpcClient) +} + +func BenchmarkAll(b *testing.B) { + b.Run("BenchmarkErigonNode", func(b *testing.B) { + BenchmarkErigonNode(b) + }) + b.Run("BenchmarkRawBigTable", func(b *testing.B) { + BenchmarkRawBigTable(b) + }) +} + +func TestBigTableClient(t *testing.T) { + tests := []struct { + name string + block FullBlockData + }{ + { + name: "test block", + block: testFullBlock, + }, + { + name: "two uncles", + block: testTwoUnclesFullBlock, + }, + } + + client, admin := databasetest.NewBigTable(t) + bt, err := database.NewBigTableWithClient(context.Background(), client, admin, Schema) + if err != nil { + t.Fatal(err) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rawStore := NewStore(database.Wrap(bt, Table)) + if err := rawStore.AddBlocks([]FullBlockData{tt.block}); err != nil { + t.Fatal(err) + } + + rpcClient, err := rpc.DialOptions(context.Background(), "https://foo.bar", rpc.WithHTTPClient(&http.Client{ + Transport: NewBigTableEthRaw(WithCache(rawStore), tt.block.ChainID), + })) + if err != nil { + t.Fatal(err) + } + ethClient := ethclient.NewClient(rpcClient) + + block, err := ethClient.BlockByNumber(context.Background(), big.NewInt(tt.block.BlockNumber)) + if err != nil { + t.Fatalf("BlockByNumber() error = %v", err) + } + if got, want := block.Number().Int64(), tt.block.BlockNumber; got != want { + t.Errorf("got %v, want %v", got, want) + } + + receipts, err := ethClient.BlockReceipts(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(tt.block.BlockNumber))) + if err != nil { + t.Fatalf("BlockReceipts() error = %v", err) + } + if len(block.Transactions()) != 0 && len(receipts) == 0 { + t.Errorf("receipts should not be empty") + } + + var traces []GethTraceCallResultWrapper + if err := rpcClient.Call(&traces, "debug_traceBlockByNumber", hexutil.EncodeBig(block.Number()), gethTracerArg); err != nil { + t.Fatalf("debug_traceBlockByNumber() error = %v", err) + } + if len(block.Transactions()) != 0 && len(traces) == 0 { + t.Errorf("traces should not be empty") + } + }) + } +} + +func TestBigTableClientWithFallback(t *testing.T) { + node := os.Getenv("ETH1_ERIGON_ENDPOINT") + if node == "" { + t.Skip("skipping test, set ETH1_ERIGON_ENDPOINT") + } + + tests := []struct { + name string + block FullBlockData + }{ + { + name: "test block", + block: testFullBlock, + }, + } + + client, admin := databasetest.NewBigTable(t) + bt, err := database.NewBigTableWithClient(context.Background(), client, admin, Schema) + if err != nil { + t.Fatal(err) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rawStore := NewStore(database.Wrap(bt, Table)) + + rpcClient, err := rpc.DialOptions(context.Background(), node, rpc.WithHTTPClient(&http.Client{ + Transport: NewWithFallback(NewBigTableEthRaw(rawStore, tt.block.ChainID), http.DefaultTransport), + })) + if err != nil { + t.Fatal(err) + } + ethClient := ethclient.NewClient(rpcClient) + + balance, err := ethClient.BalanceAt(context.Background(), common.Address{}, big.NewInt(tt.block.BlockNumber)) + if err != nil { + t.Fatal(err) + } + if balance == nil { + t.Errorf("empty balance") + } + + block, err := ethClient.BlockByNumber(context.Background(), big.NewInt(tt.block.BlockNumber)) + if err != nil { + t.Fatalf("BlockByNumber() error = %v", err) + } + if got, want := block.Number().Int64(), tt.block.BlockNumber; got != want { + t.Errorf("got %v, want %v", got, want) + } + + receipts, err := ethClient.BlockReceipts(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(tt.block.BlockNumber))) + if err != nil { + t.Fatalf("BlockReceipts() error = %v", err) + } + if len(block.Transactions()) != 0 && len(receipts) == 0 { + t.Errorf("receipts should not be empty") + } + + var traces []GethTraceCallResultWrapper + if err := rpcClient.Call(&traces, "debug_traceBlockByNumber", hexutil.EncodeBig(block.Number()), gethTracerArg); err != nil { + t.Fatalf("debug_traceBlockByNumber() error = %v", err) + } + if len(block.Transactions()) != 0 && len(traces) == 0 { + t.Errorf("traces should not be empty") + } + }) + } +} + +// TODO import those 3 from somewhere +var gethTracerArg = map[string]string{ + "tracer": "callTracer", +} + +type GethTraceCallResultWrapper struct { + Result *GethTraceCallResult `json:"result,omitempty"` +} + +type GethTraceCallResult struct { + TransactionPosition int `json:"transaction_position,omitempty"` + Time string `json:"time,omitempty"` + GasUsed string `json:"gas_used,omitempty"` + From common.Address `json:"from,omitempty"` + To common.Address `json:"to,omitempty"` + Value string `json:"value,omitempty"` + Gas string `json:"gas,omitempty"` + Input string `json:"input,omitempty"` + Output string `json:"output,omitempty"` + Error string `json:"error,omitempty"` + Type string `json:"type,omitempty"` + Calls []*GethTraceCallResult `json:"calls,omitempty"` +} diff --git a/backend/pkg/commons/db2/raw/compress.go b/backend/pkg/commons/db2/raw/compress.go new file mode 100644 index 000000000..b5010bdb7 --- /dev/null +++ b/backend/pkg/commons/db2/raw/compress.go @@ -0,0 +1,48 @@ +package raw + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" +) + +type gzipCompressor struct { +} + +func (gzipCompressor) compress(src []byte) ([]byte, error) { + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + if _, err := zw.Write(src); err != nil { + return nil, fmt.Errorf("gzip cannot compress data: %w", err) + } + if err := zw.Close(); err != nil { + return nil, fmt.Errorf("gzip cannot close writer: %w", err) + } + return buf.Bytes(), nil +} + +func (gzipCompressor) decompress(src []byte) ([]byte, error) { + if len(src) == 0 { + return nil, nil + } + zr, err := gzip.NewReader(bytes.NewReader(src)) + if err != nil { + return nil, fmt.Errorf("gzip cannot create reader: %w", err) + } + data, err := io.ReadAll(zr) + if err != nil { + return nil, fmt.Errorf("gzip cannot read: %w", err) + } + return data, nil +} + +type noOpCompressor struct{} + +func (n noOpCompressor) compress(src []byte) ([]byte, error) { + return src, nil +} + +func (n noOpCompressor) decompress(src []byte) ([]byte, error) { + return src, nil +} diff --git a/backend/pkg/commons/db2/raw/parser.go b/backend/pkg/commons/db2/raw/parser.go new file mode 100644 index 000000000..be45ad463 --- /dev/null +++ b/backend/pkg/commons/db2/raw/parser.go @@ -0,0 +1,144 @@ +package raw + +import ( + "encoding/json" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/jsonrpc" + "github.com/gobitfly/beaconchain/pkg/commons/types/geth" +) + +var GethParse = func(rawBlock *FullBlockData) (*types.Block, []*types.Receipt, []*geth.Trace, error) { + var blockResp, receiptsResp, tracesResp jsonrpc.Message + _ = json.Unmarshal(rawBlock.Receipts, &receiptsResp) + _ = json.Unmarshal(rawBlock.Block, &blockResp) + _ = json.Unmarshal(rawBlock.Traces, &tracesResp) + + var unclesResp []jsonrpc.Message + _ = json.Unmarshal(rawBlock.Uncles, &unclesResp) + + block, err := parseEthBlock(big.NewInt(int64(rawBlock.ChainID)), blockResp.Result, unclesResp) + if err != nil { + return nil, nil, nil, err + } + + var receipts []*types.Receipt + var traces []*geth.Trace + if len(block.Transactions()) != 0 { + if err := json.Unmarshal(receiptsResp.Result, &receipts); err != nil { + return nil, nil, nil, err + } + + if err := json.Unmarshal(tracesResp.Result, &traces); err != nil { + return nil, nil, nil, err + } + + for i := 0; i < len(block.Transactions()); i++ { + if traces[i].TxHash != "" { + break + } + // manually insert the hash in case it is missing + // ie: old block traces don't include the hash + traces[i].TxHash = receipts[i].TxHash.Hex() + } + // manually insert the transaction position + for i := 0; i < len(traces); i++ { + calls := []*geth.TraceCall{traces[i].Result} + for len(calls) != 0 { + calls[0].TransactionPosition = i + calls = append(calls[1:], calls[0].Calls...) + } + } + } + + return block, receipts, traces, nil +} + +type rpcBlock struct { + Hash common.Hash `json:"hash"` + Transactions []rpcTransaction `json:"transactions"` + UncleHashes []common.Hash `json:"uncles"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + Requests []*types.Request `json:"requests,omitempty"` +} + +type rpcTransaction struct { + tx *types.Transaction + txExtraInfo +} + +func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error { + if err := json.Unmarshal(msg, &tx.tx); err != nil { + return err + } + return json.Unmarshal(msg, &tx.txExtraInfo) +} + +type txExtraInfo struct { + BlockNumber *string `json:"blockNumber,omitempty"` + BlockHash *common.Hash `json:"blockHash,omitempty"` + From *common.Address `json:"from,omitempty"` +} + +// parseEthBlock is a copy of ethclient.Client.getBlock +// modified to work the with raw db +// https://github.com/ethereum/go-ethereum/blob/v1.14.11/ethclient/ethclient.go#L129 +// receive the chainID because it cannot be extracted for sure from the transaction on certain chain (optimism) +func parseEthBlock(chainID *big.Int, raw json.RawMessage, rawUncles []jsonrpc.Message) (*types.Block, error) { + // Decode header and transactions. + var head *types.Header + if err := json.Unmarshal(raw, &head); err != nil { + return nil, err + } + + // When the block is not found, the API returns JSON null. + if head == nil { + return nil, ethereum.NotFound + } + + var body rpcBlock + if err := json.Unmarshal(raw, &body); err != nil { + return nil, err + } + // Quick-verify transaction and uncle lists. This mostly helps with debugging the server. + if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { + return nil, errors.New("server returned non-empty uncle list but block header indicates no uncles") + } + if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { + return nil, errors.New("server returned empty uncle list but block header indicates uncles") + } + if head.TxHash == types.EmptyTxsHash && len(body.Transactions) > 0 { + return nil, errors.New("server returned non-empty transaction list but block header indicates no transactions") + } + if head.TxHash != types.EmptyTxsHash && len(body.Transactions) == 0 { + return nil, errors.New("server returned empty transaction list but block header indicates transactions") + } + // Load uncles because they are not included in the block response. + uncles := make([]*types.Header, len(body.UncleHashes)) + for i := 0; i < len(body.UncleHashes); i++ { + err := json.Unmarshal(rawUncles[i].Result, &uncles[i]) + if err != nil { + return nil, err + } + } + // Fill the sender cache of transactions in the block. + txs := make([]*types.Transaction, len(body.Transactions)) + for i, tx := range body.Transactions { + if tx.From != nil { + setSender(chainID, tx.tx, *tx.From, body.Hash) + } + txs[i] = tx.tx + } + return types.NewBlockWithHeader(head).WithBody( + types.Body{ + Transactions: txs, + Uncles: uncles, + Withdrawals: body.Withdrawals, + Requests: body.Requests, + }), nil +} diff --git a/backend/pkg/commons/db2/raw/parser_test.go b/backend/pkg/commons/db2/raw/parser_test.go new file mode 100644 index 000000000..1a21074c9 --- /dev/null +++ b/backend/pkg/commons/db2/raw/parser_test.go @@ -0,0 +1,155 @@ +package raw + +import ( + "context" + "fmt" + "io" + "math/big" + "net/http" + "os" + "reflect" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/rpc" + + "github.com/gobitfly/beaconchain/internal/th" + "github.com/gobitfly/beaconchain/pkg/commons/db2/database" + "github.com/gobitfly/beaconchain/pkg/commons/db2/database/databasetest" +) + +func TestRawWithBackend(t *testing.T) { + raw, backend := newRandSeededStore(t) + blocks, err := raw.ReadBlocksByNumber(uint64(backend.ChainID), 0, 10) + if err != nil { + t.Fatal(err) + } + for _, b := range blocks { + expectedBlock, err := backend.Client().BlockByNumber(context.Background(), big.NewInt(b.BlockNumber)) + if err != nil { + t.Fatal(err) + } + expectedReceipts, err := backend.Client().BlockReceipts(context.Background(), rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(b.BlockNumber))) + if err != nil { + t.Fatal(err) + } + block, receipts, _, err := GethParse(b) + if err != nil { + t.Fatal(err) + } + if got, want := block.Number().String(), expectedBlock.Number().String(); got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := block.Hash().String(), expectedBlock.Hash().String(); got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := block.TxHash().String(), expectedBlock.TxHash().String(); got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := block.UncleHash().String(), expectedBlock.UncleHash().String(); got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := block.ReceiptHash().String(), expectedBlock.ReceiptHash().String(); got != want { + t.Errorf("got %v, want %v", got, want) + } + if len(expectedReceipts) != 0 { + if got, want := receipts, expectedReceipts; !reflect.DeepEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } + } + } +} + +func TestRawRemoteRealCondition(t *testing.T) { + remote := os.Getenv("REMOTE_URL") + if remote == "" { + t.Skip("skipping test, set REMOTE_URL") + } + + client := database.NewRemoteClient(remote) + db := NewStore(client) + block, err := db.ReadBlockByNumber(1, 6008149) + if err != nil { + panic(err) + } + + ethBlock, receipts, traces, err := GethParse(block) + if err != nil { + t.Errorf("failed to parse block: %v", err) + } + for i, transaction := range ethBlock.Transactions() { + if got, want := receipts[i].TxHash, transaction.Hash(); got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := traces[i].TxHash, transaction.Hash().Hex(); got != want { + t.Errorf("got %v, want %v", got, want) + } + } +} + +func newRandSeededStore(t *testing.T) (Store, *th.BlockchainBackend) { + t.Helper() + client, admin := databasetest.NewBigTable(t) + bt, err := database.NewBigTableWithClient(context.Background(), client, admin, Schema) + if err != nil { + t.Fatal(err) + } + + db := NewStore(database.Wrap(bt, Table)) + + backend := th.NewBackend(t) + for i := 0; i < 10; i++ { + temp := th.CreateEOA(t) + backend.FundOneEther(t, temp.From) + } + lastBlock, err := backend.Client().BlockNumber(context.Background()) + if err != nil { + t.Fatal(err) + } + var blocks []FullBlockData + for i := uint64(0); i <= lastBlock; i++ { + blocks = append(blocks, makeRawBlock(t, backend.Endpoint, uint64(backend.ChainID), i)) + } + if err := db.AddBlocks(blocks); err != nil { + t.Fatal(err) + } + + return db, backend +} + +func makeRawBlock(t *testing.T, endpoint string, chainID uint64, block uint64) FullBlockData { + getReceipts := `{"jsonrpc":"2.0","method":"eth_getBlockReceipts","params":["0x%x"],"id":%d}` + getBlock := `{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x", true],"id":%d}` + getTraces := `{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["0x%x", {"tracer": "callTracer"}],"id":%d}` + id := 1 + + return FullBlockData{ + ChainID: chainID, + BlockNumber: int64(block), + BlockHash: nil, + BlockUnclesCount: 0, + BlockTxs: nil, + Block: httpCall(t, endpoint, fmt.Sprintf(getBlock, block, id)), + Receipts: httpCall(t, endpoint, fmt.Sprintf(getReceipts, block, id)), + Traces: httpCall(t, endpoint, fmt.Sprintf(getTraces, block, id)), + Uncles: nil, + } +} + +func httpCall(t *testing.T, endpoint string, body string) []byte { + req, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(body)) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err != nil { + panic(err) + } + return b +} diff --git a/backend/pkg/commons/db2/raw/raw.go b/backend/pkg/commons/db2/raw/raw.go new file mode 100644 index 000000000..ef14effa4 --- /dev/null +++ b/backend/pkg/commons/db2/raw/raw.go @@ -0,0 +1,174 @@ +package raw + +import ( + "fmt" + "math/big" + "strings" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/database" + "github.com/gobitfly/beaconchain/pkg/commons/hexutil" +) + +type compressor interface { + compress(src []byte) ([]byte, error) + decompress(src []byte) ([]byte, error) +} + +type Store struct { + db database.Database + compressor compressor +} + +func NewStore(store database.Database) Store { + return Store{ + db: store, + compressor: gzipCompressor{}, + } +} + +func (store Store) AddBlocks(blocks []FullBlockData) error { + itemsByKey := make(map[string][]database.Item) + for _, fullBlock := range blocks { + if err := validateBlock(fullBlock); err != nil { + return fmt.Errorf("block %d: %w", fullBlock.BlockNumber, err) + } + if len(fullBlock.Block) == 0 || len(fullBlock.BlockTxs) != 0 && len(fullBlock.Traces) == 0 { + return fmt.Errorf("block %d: empty data", fullBlock.BlockNumber) + } + key := blockKey(fullBlock.ChainID, fullBlock.BlockNumber) + + block, err := store.compressor.compress(fullBlock.Block) + if err != nil { + return fmt.Errorf("cannot compress block %d: %w", fullBlock.BlockNumber, err) + } + receipts, err := store.compressor.compress(fullBlock.Receipts) + if err != nil { + return fmt.Errorf("cannot compress receipts %d: %w", fullBlock.BlockNumber, err) + } + traces, err := store.compressor.compress(fullBlock.Traces) + if err != nil { + return fmt.Errorf("cannot compress traces %d: %w", fullBlock.BlockNumber, err) + } + itemsByKey[key] = []database.Item{ + { + Family: BT_COLUMNFAMILY_BLOCK, + Column: BT_COLUMN_BLOCK, + Data: block, + }, + { + Family: BT_COLUMNFAMILY_RECEIPTS, + Column: BT_COLUMN_RECEIPTS, + Data: receipts, + }, + { + Family: BT_COLUMNFAMILY_TRACES, + Column: BT_COLUMN_TRACES, + Data: traces, + }, + } + if fullBlock.BlockUnclesCount > 0 { + uncles, err := store.compressor.compress(fullBlock.Uncles) + if err != nil { + return fmt.Errorf("cannot compress block %d: %w", fullBlock.BlockNumber, err) + } + itemsByKey[key] = append(itemsByKey[key], database.Item{ + Family: BT_COLUMNFAMILY_UNCLES, + Column: BT_COLUMN_UNCLES, + Data: uncles, + }) + } + } + if err := store.db.BulkAdd(itemsByKey); err != nil { + return fmt.Errorf("cannot add blocks [%d-%d] to database: %w", blocks[0].BlockNumber, blocks[len(blocks)-1].BlockNumber, err) + } + return nil +} + +func (store Store) ReadBlockByNumber(chainID uint64, number int64) (*FullBlockData, error) { + return store.readBlock(chainID, number) +} + +func (store Store) ReadBlockByHash(chainID uint64, hash string) (*FullBlockData, error) { + // todo use sql store to retrieve hash + return nil, fmt.Errorf("ReadBlockByHash not implemented") +} + +func (store Store) readBlock(chainID uint64, number int64) (*FullBlockData, error) { + key := blockKey(chainID, number) + row, err := store.db.GetRow(key) + if err != nil { + return nil, err + } + return store.parseRow(chainID, number, row.Values) +} + +func (store Store) parseRow(chainID uint64, number int64, data map[string][]byte) (*FullBlockData, error) { + block, err := store.compressor.decompress(data[fmt.Sprintf("%s:%s", BT_COLUMNFAMILY_BLOCK, BT_COLUMN_BLOCK)]) + if err != nil { + return nil, fmt.Errorf("cannot decompress block %d: %w", number, err) + } + receipts, err := store.compressor.decompress(data[fmt.Sprintf("%s:%s", BT_COLUMNFAMILY_RECEIPTS, BT_COLUMN_RECEIPTS)]) + if err != nil { + return nil, fmt.Errorf("cannot decompress receipts %d: %w", number, err) + } + traces, err := store.compressor.decompress(data[fmt.Sprintf("%s:%s", BT_COLUMNFAMILY_TRACES, BT_COLUMN_TRACES)]) + if err != nil { + return nil, fmt.Errorf("cannot decompress traces %d: %w", number, err) + } + uncles, err := store.compressor.decompress(data[fmt.Sprintf("%s:%s", BT_COLUMNFAMILY_UNCLES, BT_COLUMN_UNCLES)]) + if err != nil { + return nil, fmt.Errorf("cannot decompress uncles %d: %w", number, err) + } + return &FullBlockData{ + ChainID: chainID, + BlockNumber: number, + BlockHash: nil, + BlockUnclesCount: 0, + BlockTxs: nil, + Block: block, + Receipts: receipts, + Traces: traces, + Uncles: uncles, + }, nil +} + +func (store Store) ReadBlocksByNumber(chainID uint64, start, end int64) ([]*FullBlockData, error) { + rows, err := store.db.GetRowsRange(blockKey(chainID, start), blockKey(chainID, end)) + if err != nil { + return nil, err + } + blocks := make([]*FullBlockData, 0, end-start+1) + for _, row := range rows { + block, err := store.parseRow(chainID, blockKeyToNumber(chainID, row.Key), row.Values) + if err != nil { + return nil, err + } + blocks = append(blocks, block) + } + return blocks, nil +} + +func blockKey(chainID uint64, number int64) string { + return fmt.Sprintf("%d:%12d", chainID, MAX_EL_BLOCK_NUMBER-number) +} + +func blockKeyToNumber(chainID uint64, key string) int64 { + key = strings.TrimPrefix(key, fmt.Sprintf("%d:", chainID)) + reversed, _ := new(big.Int).SetString(key, 10) + + return MAX_EL_BLOCK_NUMBER - reversed.Int64() +} + +type FullBlockData struct { + ChainID uint64 + + BlockNumber int64 + BlockHash hexutil.Bytes + BlockUnclesCount int + BlockTxs []string + + Block hexutil.Bytes + Receipts hexutil.Bytes + Traces hexutil.Bytes + Uncles hexutil.Bytes +} diff --git a/backend/pkg/commons/db2/raw/raw_test.go b/backend/pkg/commons/db2/raw/raw_test.go new file mode 100644 index 000000000..3d66b1b00 --- /dev/null +++ b/backend/pkg/commons/db2/raw/raw_test.go @@ -0,0 +1,470 @@ +package raw + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/google/go-cmp/cmp" + + "github.com/gobitfly/beaconchain/pkg/commons/db2/database" + "github.com/gobitfly/beaconchain/pkg/commons/db2/database/databasetest" +) + +func TestRaw(t *testing.T) { + client, admin := databasetest.NewBigTable(t) + + s, err := database.NewBigTableWithClient(context.Background(), client, admin, Schema) + if err != nil { + t.Fatal(err) + } + + store := Store{ + db: database.Wrap(s, Table), + compressor: noOpCompressor{}, + } + + tests := []struct { + name string + block FullBlockData + }{ + { + name: "test block", + block: testFullBlock, + }, + { + name: "two uncles", + block: testTwoUnclesFullBlock, + }, + { + name: "arbitrum", + block: testArbFullBlock, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := store.AddBlocks([]FullBlockData{tt.block}); err != nil { + t.Fatal(err) + } + + res, err := store.ReadBlockByNumber(tt.block.ChainID, tt.block.BlockNumber) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(string(res.Block), string(tt.block.Block)); diff != "" { + t.Errorf("block mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(string(res.Receipts), string(tt.block.Receipts)); diff != "" { + t.Errorf("receipts mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(string(res.Traces), string(tt.block.Traces)); diff != "" { + t.Errorf("traces mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(string(res.Uncles), string(tt.block.Uncles)); diff != "" { + t.Errorf("uncles mismatch (-want +got):\n%s", diff) + } + }) + } +} + +var testFullBlock = FullBlockData{ + ChainID: 1, + BlockNumber: testBlockNumber, + BlockHash: common.HexToHash(testBlockHash).Bytes(), + BlockUnclesCount: 1, + Block: []byte(testBlock), + Receipts: []byte(testReceipts), + Traces: []byte(testTraces), + Uncles: []byte(testUncles), +} + +var testTwoUnclesFullBlock = FullBlockData{ + ChainID: 1, + BlockNumber: testTwoUnclesBlockNumber, + BlockUnclesCount: 2, + Block: []byte(testTwoUnclesBlock), + Receipts: nil, + Traces: nil, + Uncles: []byte(testTwoUnclesBlockUncles), +} + +const ( + testBlockNumber = 6008149 + testBlockHash = "0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35" + testBlock = `{ + "jsonrpc":"2.0", + "id":1, + "result":{ + "difficulty":"0xbfabcdbd93dda", + "extraData":"0x737061726b706f6f6c2d636e2d6e6f64652d3132", + "gasLimit":"0x79f39e", + "gasUsed":"0x79ccd3", + "hash":"0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35", + "logsBloom":"0x4848112002a2020aaa0812180045840210020005281600c80104264300080008000491220144461026015300100000128005018401002090a824a4150015410020140400d808440106689b29d0280b1005200007480ca950b15b010908814e01911000054202a020b05880b914642a0000300003010044044082075290283516be82504082003008c4d8d14462a8800c2990c88002a030140180036c220205201860402001014040180002006860810ec0a1100a14144148408118608200060461821802c081000042d0810104a8004510020211c088200420822a082040e10104c00d010064004c122692020c408a1aa2348020445403814002c800888208b1", + "miner":"0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c", + "mixHash":"0x3d1fdd16f15aeab72e7db1013b9f034ee33641d92f71c0736beab4e67d34c7a7", + "nonce":"0x4db7a1c01d8a8072", + "number":"0x5bad55", + "parentHash":"0x61a8ad530a8a43e3583f8ec163f773ad370329b2375d66433eb82f005e1d6202", + "receiptsRoot":"0x5eced534b3d84d3d732ddbc714f5fd51d98a941b28182b6efe6df3a0fe90004b", + "sha3Uncles":"0x8a562e7634774d3e3a36698ac4915e37fc84a2cd0044cb84fa5d80263d2af4f6", + "size":"0x41c7", + "stateRoot":"0xf5208fffa2ba5a3f3a2f64ebd5ca3d098978bedd75f335f56b705d8715ee2305", + "timestamp":"0x5b541449", + "totalDifficulty":"0x12ac11391a2f3872fcd", + "transactions":[ + { + "blockHash":"0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35", + "blockNumber":"0x5bad55", + "from":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "gas":"0x249f0", + "gasPrice":"0x174876e800", + "hash":"0x8784d99762bccd03b2086eabccee0d77f14d05463281e121a62abfebcf0d2d5f", + "input":"0x6ea056a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd8d7fa6f8cc00", + "nonce":"0x5e4724", + "to":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "transactionIndex":"0x0", + "value":"0x0", + "type":"0x0", + "chainId":"0x1", + "v":"0x25", + "r":"0xd1556332df97e3bd911068651cfad6f975a30381f4ff3a55df7ab3512c78b9ec", + "s":"0x66b51cbb10cd1b2a09aaff137d9f6d4255bf73cb7702b666ebd5af502ffa4410" + }, + { + "blockHash":"0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35", + "blockNumber":"0x5bad55", + "from":"0xc837f51a0efa33f8eca03570e3d01a4b2cf97ffd", + "gas":"0x15f90", + "gasPrice":"0x14b8d03a00", + "hash":"0x311be6a9b58748717ac0f70eb801d29973661aaf1365960d159e4ec4f4aa2d7f", + "input":"0x", + "nonce":"0x4241", + "to":"0xf49bd0367d830850456d2259da366a054038dc46", + "transactionIndex":"0x1", + "value":"0x1bafa9ee16e78000", + "type":"0x0", + "chainId":"0x1", + "v":"0x25", + "r":"0xe9ef2f6fcff76e45fac6c2e8080094370082cfb47e8fde0709312f9aa3ec06ad", + "s":"0x421ebc4ebe187c173f13b1479986dcbff5c4997c0dfeb1fd149a982ad4bcdfe7" + } + ], + "transactionsRoot":"0xf98631e290e88f58a46b7032f025969039aa9b5696498efc76baf436fa69b262", + "uncles":[ + "0x824cce7c7c2ec6874b9fa9a9a898eb5f27cbaf3991dfa81084c3af60d1db618c" + ] + } +}` + testTraces = `{ + "jsonrpc":"2.0", + "id":1, + "result":[ + { + "result":{ + "from":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "gas":"0x249f0", + "gasUsed":"0xc349", + "to":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "input":"0x6ea056a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd8d7fa6f8cc00", + "output":"0x0000000000000000000000000000000000000000000000000000000000000001", + "calls":[ + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1e530", + "gasUsed":"0x41b", + "to":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "input":"0x3c18d3180000000000000000000000000000000000000000000000000000000000000000", + "output":"0x000000000000000000000000b2233fcec42c588ee71a594d9a25aa695345426c", + "value":"0x0", + "type":"CALL" + }, + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1ddd2", + "gasUsed":"0x5e56", + "to":"0xb2233fcec42c588ee71a594d9a25aa695345426c", + "input":"0x6ea056a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd8d7fa6f8cc00", + "output":"0x0000000000000000000000000000000000000000000000000000000000000001", + "calls":[ + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1cdaf", + "gasUsed":"0x2be", + "to":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "input":"0x97dc97cb", + "output":"0x0000000000000000000000006cace0528324a8afc2b157ceba3cdd2a27c4e21f", + "value":"0x0", + "type":"CALL" + }, + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1c2d7", + "gasUsed":"0x2a8", + "to":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "input":"0x8da5cb5b", + "output":"0x000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "value":"0x0", + "type":"CALL" + }, + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1b7d0", + "gasUsed":"0x294", + "to":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "input":"0xb9b8af0b", + "output":"0x0000000000000000000000000000000000000000000000000000000000000000", + "value":"0x0", + "type":"CALL" + }, + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1ae06", + "gasUsed":"0x300", + "to":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "input":"0xb269681d", + "output":"0x000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "value":"0x0", + "type":"CALL" + }, + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x8fc", + "gasUsed":"0x0", + "to":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "input":"0x", + "value":"0xbd8d7fa6f8cc00", + "type":"CALL" + }, + { + "from":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "gas":"0x1844a", + "gasUsed":"0xa85", + "to":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "input":"0x28090abb0000000000000000000000004b9c25ca0224aef6a7522cabdbc3b2e125b7ca50000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd8d7fa6f8cc00", + "value":"0x0", + "type":"CALL" + } + ], + "type":"DELEGATECALL" + } + ], + "value":"0x0", + "type":"CALL" + } + }, + { + "result":{ + "from":"0xc837f51a0efa33f8eca03570e3d01a4b2cf97ffd", + "gas":"0x15f90", + "gasUsed":"0x5208", + "to":"0xf49bd0367d830850456d2259da366a054038dc46", + "input":"0x", + "value":"0x1bafa9ee16e78000", + "type":"CALL" + } + } + ] +}` + testReceipts = `{ + "jsonrpc":"2.0", + "id":1, + "result":[ + { + "blockHash":"0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35", + "blockNumber":"0x5bad55", + "contractAddress":null, + "cumulativeGasUsed":"0xc349", + "effectiveGasPrice":"0x174876e800", + "from":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "gasUsed":"0xc349", + "logs":[ + { + "address":"0xa3c1e324ca1ce40db73ed6026c4a177f099b5770", + "topics":[ + "0xa64da754fccf55aa65a1f0128a648633fade3884b236e879ee9f64c78df5d5d7", + "0x0000000000000000000000004b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "0x000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data":"0x00000000000000000000000000000000000000000000000000bd8d7fa6f8cc00", + "blockNumber":"0x5bad55", + "transactionHash":"0x8784d99762bccd03b2086eabccee0d77f14d05463281e121a62abfebcf0d2d5f", + "transactionIndex":"0x0", + "blockHash":"0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35", + "logIndex":"0x0", + "removed":false + } + ], + "logsBloom":"0x00000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000800040004000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000100000000000000000000000000800000000000000000000000008000000000000000000000000000000000004000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000020000000000000000000000000000000000000000000000000000000000000000000", + "status":"0x1", + "to":"0x4b9c25ca0224aef6a7522cabdbc3b2e125b7ca50", + "transactionHash":"0x8784d99762bccd03b2086eabccee0d77f14d05463281e121a62abfebcf0d2d5f", + "transactionIndex":"0x0", + "type":"0x0" + }, + { + "blockHash":"0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35", + "blockNumber":"0x5bad55", + "contractAddress":null, + "cumulativeGasUsed":"0x11551", + "effectiveGasPrice":"0x14b8d03a00", + "from":"0xc837f51a0efa33f8eca03570e3d01a4b2cf97ffd", + "gasUsed":"0x5208", + "logs":[ + + ], + "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status":"0x1", + "to":"0xf49bd0367d830850456d2259da366a054038dc46", + "transactionHash":"0x311be6a9b58748717ac0f70eb801d29973661aaf1365960d159e4ec4f4aa2d7f", + "transactionIndex":"0x1", + "type":"0x0" + } + ] +}` + testUncles = `[ + { + "jsonrpc":"2.0", + "id":1, + "result":{ + "difficulty":"0xbf93da424b943", + "extraData":"0x65746865726d696e652d657539", + "gasLimit":"0x7a121d", + "gasUsed":"0x79ea62", + "hash":"0x824cce7c7c2ec6874b9fa9a9a898eb5f27cbaf3991dfa81084c3af60d1db618c", + "logsBloom":"0x0948432021200401804810002000000000381001001202440000010020000080a016262050e44850268052000400100505022305a64000054004200b0c04110000080c1055c42001054b804940a0401401008a00112d80082113400c10006580140005011a40220020000010001c0a00082300434002000050840010102082801c2000148540201004491814020480080111a0300600000003800640024200109c00202010044000880000106810a1a010000028a0100000422000140011000050a2a44b3080001060800000540c108102102600d000004730404a880100600021080100403000180000062642408b440060590400080101e046f08000000430", + "miner":"0xea674fdde714fd979de3edf0f56aa9716b898ec8", + "mixHash":"0x0b15fe0a9aa789c167b0f5ade7b72969d9f2193014cb4e98382254f60ffb2f4a", + "nonce":"0xa212d6400b89b3f6", + "number":"0x5bad54", + "parentHash":"0x05e19fb68d9ec798073808e8b3170875cb327d4b6cde7d6f60fe194677bb26fd", + "receiptsRoot":"0x90807b32c4aa4610c57289de57fa68ba50ed53f14dd2c25f1862aa049029dcd6", + "sha3Uncles":"0xf763576c1ea6a8c61a206e16b1a2451bec5cba1c7545d7ff733a1e8c78715569", + "size":"0x216", + "stateRoot":"0xebc7a1603bfffe0a14bdb89f898e2f2824abb40f04579beb7b920c56d6e273c9", + "timestamp":"0x5b54143f", + "totalDifficulty":"0x12ac11391a2f3872fcd", + "transactions":[ + + ], + "transactionsRoot":"0x7562cba41e067b364b933e7b566fb2444f6954fef3964a5a487d4cd79d97a56c", + "uncles":[ + + ] + } + } +]` + + testTwoUnclesBlockNumber = 141 + testTwoUnclesBlock = `{ + "jsonrpc":"2.0", + "id":0, + "result":{ + "difficulty":"0x4417decf7", + "extraData":"0x426974636f696e2069732054484520426c6f636b636861696e2e", + "gasLimit":"0x1388", + "gasUsed":"0x0", + "hash":"0xeafbe76fdcadc1b69ba248589eb2a674b60b00c84374c149c9deaf5596183932", + "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "miner":"0x1b7047b4338acf65be94c1a3e8c5c9338ad7d67c", + "mixHash":"0x21eabda67c3151855389a5a968e50daa7b356b3046e2f119ef46c97d204a541e", + "nonce":"0x85378a3fc5e608e1", + "number":"0x8d", + "parentHash":"0xe2c1e8200ef2e9fba09979f0b504dc52c068719623c7064904c7bd3e9365acc1", + "receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "sha3Uncles":"0x393f5f01182846b91386f8b00759fd54f83998a6a1064b8ac72fc8eca1bcf81b", + "size":"0x653", + "stateRoot":"0x3e1eea9a01178945535230b6f5839201f594d9be20618bb4edaa383f4f0c850f", + "timestamp":"0x55ba4444", + "totalDifficulty":"0x24826e73469", + "transactions":[ + + ], + "transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles":[ + "0x61beeeb3e11e89d19fed2e988c8017b55c3ddb8895f531072363ce2abaf56b95", + "0xf84d9d74415364c3a7569f315ff831b910968c7dd637fffaab51278c9e7f9306" + ] + } +}` + testTwoUnclesBlockUncles = `[ + { + "jsonrpc":"2.0", + "id":141, + "result":{ + "difficulty":"0x4406dc086", + "extraData":"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32", + "gasLimit":"0x1388", + "gasUsed":"0x0", + "hash":"0x61beeeb3e11e89d19fed2e988c8017b55c3ddb8895f531072363ce2abaf56b95", + "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "miner":"0xbb7b8287f3f0a933474a79eae42cbca977791171", + "mixHash":"0x87547a998fe63f18b36180ca918131b6b20fc5d67390e2ac2f66be3fee8fb7d2", + "nonce":"0x1dc5b79704350bee", + "number":"0x8b", + "parentHash":"0x2253b8f79c23b6ff67cb2ef6fabd9ec59e1edf2d07c16d98a19378041f96624d", + "receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size":"0x21f", + "stateRoot":"0x940131b162b07452ea31b5335c4dedfdddc13338142f71f261d51dea664033b4", + "timestamp":"0x55ba4441", + "totalDifficulty":"0x24826e73469", + "transactions":[ + + ], + "transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles":[ + + ] + } + }, + { + "jsonrpc":"2.0", + "id":141, + "result":{ + "difficulty":"0x4406dc086", + "extraData":"0x476574682f6b6c6f737572652f76312e302e302d66633739643332642f6c696e", + "gasLimit":"0x1388", + "gasUsed":"0x0", + "hash":"0xf84d9d74415364c3a7569f315ff831b910968c7dd637fffaab51278c9e7f9306", + "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "miner":"0xd7e30ae310c1d1800f5b641baa7af95b2e1fd98c", + "mixHash":"0x6039f236ebb70ec71091df5770aef0f0faa13ef334c4c68daaffbfdf7961a3d3", + "nonce":"0x7d8ec05d330e6e99", + "number":"0x8b", + "parentHash":"0x2253b8f79c23b6ff67cb2ef6fabd9ec59e1edf2d07c16d98a19378041f96624d", + "receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size":"0x221", + "stateRoot":"0x302bb7708752013f46f009dec61cad586c35dc185d20cdde0071b7487f7c2008", + "timestamp":"0x55ba4440", + "totalDifficulty":"0x24826e73469", + "transactions":[ + + ], + "transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles":[ + + ] + } + } +]` + + testArbBlock = `{"jsonrpc":"2.0","id":16,"result":{"baseFeePerGas":"0x989680","difficulty":"0x1","extraData":"0x23269065093cbccefb21eb2151d032fdec1bfbf0ed16f28fd52310c429895f51","gasLimit":"0x4000000000000","gasUsed":"0x9d057e","hash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","l1BlockNumber":"0x149f366","logsBloom":"0x00104000000004200010000040000000000000000000000000003040000000010000004000000000000100000002000000004001000020000000000000200000000010010100000a0002080900000000084000000000000001000000002008000000002004000024800000140080000000008020000000000000001000080000000000000800000000000040000004000000000600200002000000003040040022020000000000000000020000000000000000000020001080000008000000000000a002080010000000000000000000000000010000000000000020001002000010000200080000000004000000200011001000000202100000000000000000","miner":"0xa4b000000000000000000073657175656e636572","mixHash":"0x0000000000021c08000000000149f36600000000000000200000000000000000","nonce":"0x00000000001bfe7f","number":"0x119b1fd3","parentHash":"0xd77c3a94447a37a2a2d818ecc1177db9323d9be855002f770edaa0438d83cb25","receiptsRoot":"0x819f4d7f55ea783eb980567a28b6d69e1ca9837297c1e4cdf1806b81e49cdb4a","sendCount":"0x21c08","sendRoot":"0x23269065093cbccefb21eb2151d032fdec1bfbf0ed16f28fd52310c429895f51","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0xb03","stateRoot":"0x9bd81dc4d8f70c654e96266be2ce6fd8d15da2ed92fc11c37ac35adf5695febd","timestamp":"0x67868408","totalDifficulty":"0x1048428b","transactions":[{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x00000000000000000000000000000000000a4b05","gas":"0x0","gasPrice":"0x0","hash":"0x58cd6dc4c642eb0f96e0cf01f8e34e64f22a9d14581c043a9a23c6028c674052","input":"0x6bf6a42d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000149f36600000000000000000000000000000000000000000000000000000000119b1fd30000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","to":"0x00000000000000000000000000000000000a4b05","transactionIndex":"0x0","value":"0x0","type":"0x6a","chainId":"0xa4b1","v":"0x0","r":"0x0","s":"0x0"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x619e6175e65e8511c9f91b4e0f87cb2e75321651","gas":"0x30e4fa","gasPrice":"0x989680","hash":"0x334cbe7b01106ca506d239887ef7a471158372cca23a2d758916090283c10294","input":"0x5d9be1060000000000000000000000002495ca17f576e67242ecd171f01ad54791bfb710000000000000000000000000000000000000000000000000000095a43b2d4e0000000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000006786845c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041898d17f65dfbed1b3f2b0e52705b0e45373af6a48d9ebea2c726c91fc67fe1bc33a6068034c641b20c1aae679a5b10e5fd4bddcd62f033bd6fed2196fbc1b2fc1b00000000000000000000000000000000000000000000000000000000000000","nonce":"0x2","to":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","transactionIndex":"0x1","value":"0x95a43b2d4e00","type":"0x0","chainId":"0xa4b1","v":"0x14986","r":"0x265cb88034488e27801b95e62017498073d46c0d1f286443d08a37f713e8efa1","s":"0x2033532649c48eccacef100897dcbfdbaf5703bddb6518a0a4434adc2d5d4bb1"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x16fb1259a1fb59d3cabc6b1ad169762dcf0f8638","gas":"0x171060","gasPrice":"0x4c4b400","hash":"0x677ae449aea214ae1f60875330531d9e9c63dba18d01015ef7379007867e622f","input":"0x0b1a740e411301","nonce":"0xc5e2","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","transactionIndex":"0x2","value":"0x0","type":"0x0","chainId":"0xa4b1","v":"0x14986","r":"0xce45f4b68d3ee9beb93b7a9f2780a045a65b8332d25cc56393b82bb6a6d2cae","s":"0x7be86d8e60802e8a1bc0547c9a7571d3bab8e5bcea98a9ce503e352ef466f150"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0xe3c81b8221bcebccf5eac414cf52156c3c3b38ed","gas":"0x171060","gasPrice":"0x4c4b400","hash":"0x85c2d0969c7423a46197febc93ef19be5ef15108e0451c4d4f673c6cb2798e61","input":"0x08dbd00b5f6301","nonce":"0xc65a","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","transactionIndex":"0x3","value":"0x0","type":"0x0","chainId":"0xa4b1","v":"0x14986","r":"0x40c0e789faf29c2a1b576c4a7d0c454ba241577ded11b5e99bcee66f23fcbe1d","s":"0x19aa823c7cb5d9862a2f5363728b9dff5252e4b24061bdc4b9f9de8eefa8e31c"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0xf7ffaad1569d8c9626b6e90636793f072a95d259","gas":"0x232b0e","gasPrice":"0x989681","maxFeePerGas":"0xcdfe61","maxPriorityFeePerGas":"0x1","hash":"0x14617bb93ae8e7a349affa430390abd482bdb4d6658f20854ecf07895f7c621b","input":"0x095ea7b3000000000000000000000000b45c42fbf8af8df5a1fa080a351e9b2f8e0a56d100000000000000000000000000000000000000000000000000000000004e6566","nonce":"0x18","to":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","transactionIndex":"0x4","value":"0x0","type":"0x2","accessList":[],"chainId":"0xa4b1","v":"0x1","r":"0xc7ebff49ff328cff3d6b7f0ba6119b427a9916d7e8aee2ad2e22a46d337275f4","s":"0x7ed1881be854c7ddee336cf7091e32e4b43d80f1dae10b0f244741bd346f1165","yParity":"0x1"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x5096fb354daca9b11ce0d5884fad532b056e05dd","gas":"0xf4240","gasPrice":"0x989680","maxFeePerGas":"0xe4e1c0","maxPriorityFeePerGas":"0x0","hash":"0x9a43b119e0247d39e498de5c0f4bc49702354d2368b796591352ed2a9bd55b3b","input":"0x00040000ff0503b54a8379","nonce":"0x2dcaad","to":"0xcd934b818ddd7da4a82cd3e73c014569024c26f8","transactionIndex":"0x5","value":"0x0","type":"0x2","accessList":[],"chainId":"0xa4b1","v":"0x1","r":"0x346096d438091fbe3e4c4fdd88679c913312abc3ab95ce3da564988ff87f34d2","s":"0x29cefca91ee1616bb20cada117ab49dd1b9d468636f71d0558562c3cf4a515be","yParity":"0x1"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0xb38e8c17e38363af6ebdcb3dae12e0243582891d","gas":"0x185130","gasPrice":"0x47868c00","maxFeePerGas":"0x47868c00","maxPriorityFeePerGas":"0x77359400","hash":"0x2eb017df8f91c0038177ad0cedd4713dab6f6f3cf775d1753f5773ed7890b5bd","input":"0x","nonce":"0x50935b","to":"0xf39cf285e20bffe688e542fce3ecbb3c5064aa5e","transactionIndex":"0x6","value":"0xadc3bfe9d2800","type":"0x2","accessList":[],"chainId":"0xa4b1","v":"0x1","r":"0xfec3760862c438687a3a8d139a336f3fd4410122196dee3d60658bd10cf02d5c","s":"0x20885d0cf282e48d2d12b669dd2e365d7c86af0bde6efa1a8033c4540e1eab5e","yParity":"0x1"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x3931dab967c3e2dbb492fe12460a66d0fe4cc857","gas":"0x236c38","gasPrice":"0x47868c00","maxFeePerGas":"0x47868c00","maxPriorityFeePerGas":"0x77359400","hash":"0x533d4df22dabdfc80b090c7a69af5f38d80b5878d33b398273329f552d666d15","input":"0xa9059cbb000000000000000000000000f7e8ec11bd1c22643c2a2879192c818340242d1a00000000000000000000000000000000000000000000000000000000014d1970","nonce":"0xeaf67","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","transactionIndex":"0x7","value":"0x0","type":"0x2","accessList":[],"chainId":"0xa4b1","v":"0x0","r":"0x9b856e0b6e7d12eb9891192cd4f13463da8e197403e1d4f35f8951061d092e3a","s":"0x76d7789f981eb924541a04e127216e0970dffa98d5420eed6f460a7dc146824d","yParity":"0x0"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x26feadf80ee3c6a13172a9324a00879f994563f7","gas":"0x927c0","gasPrice":"0x989680","hash":"0xa6e7a77e8462adcd7d60a4dca9208c2e8cac34380a7df53f22b21345427d76a6","input":"0x","nonce":"0x1","to":"0x2166f18a7dbdf7c4d4b6a8f4fbec537967939928","transactionIndex":"0x8","value":"0x45f9685b7f000","type":"0x0","chainId":"0xa4b1","v":"0x14985","r":"0xb2c0aada240b1b239de41a460b6bd4b4a9e0af39e21d5cdeed30c11db494d0d2","s":"0x7a843423b7054d7a7b7e83975c9552ed69066cbeaef669e2bf7ce1b1a32cdcc8"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0x25681ab599b4e2ceea31f8b498052c53fc2d74db","gas":"0x22dc94","gasPrice":"0x47868c00","maxFeePerGas":"0x47868c00","maxPriorityFeePerGas":"0x77359400","hash":"0x2a47a12b226d557bc1f3fafc54ab53531bfdeddc42f10e8b0104266f7613bb5e","input":"0xa9059cbb000000000000000000000000fdc77e8188735b1d889ce0f189c472ecd0eadd520000000000000000000000000000000000000000000000000000000000384e10","nonce":"0xf33b6","to":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","transactionIndex":"0x9","value":"0x0","type":"0x2","accessList":[],"chainId":"0xa4b1","v":"0x0","r":"0xe712c2a116e38383fced44ddf53e98a1aa52ffc0c544fcc4066e8035baffc4a","s":"0x2ef65b38770f5582ccdfeeda632eb22d05dc234b213a491af18ee3d433f5c7b0","yParity":"0x0"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0xa0084b9e25d9fcaf83a4ee5bd7ca2bb708c56c19","gas":"0x2f9563","gasPrice":"0x989680","hash":"0xb8aea70764d5dc3e14d6991dc1de4bebea18fa31b82f2ccca2f96578aba2d6a0","input":"0x5d9be106000000000000000000000000cb75db6b8e8268ea5053c85eb8606a3a65a5b10a000000000000000000000000000000000000000000000000000096b37a96900000000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000006786845f00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041924cc2a7d7843a536cc63d7f599379d5bad2735caa791e496ac77c6df7e93ea638dcf6abf80b5425d3c818d5955709d5881321c7d9dfa9d5cb845783b023788e1c00000000000000000000000000000000000000000000000000000000000000","nonce":"0xd","to":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","transactionIndex":"0xa","value":"0x96b37a969000","type":"0x0","chainId":"0xa4b1","v":"0x14986","r":"0x840ed232eb930aafcddd8fbc939f971a29e134eface9f6588f2398b8518402ac","s":"0x65fda3edcba4426e4ad2c75c7cde491f6313d559c2a6a620dfdffa3e18bb101a"},{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","from":"0xa4c3e98e0ab7967ceb81d829bc6a038d9e114b87","gas":"0x1b56e4","gasPrice":"0x1312d00","hash":"0xf846e2254370f09b4538900cbb97403739ddab69da5e1e69326b7f90abbe2c27","input":"0xa9059cbb00000000000000000000000019fd9164a7f9544de573d8e27747c50c90f1bc390000000000000000000000000000000000000000000000000000000000001c76","nonce":"0x2","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","transactionIndex":"0xb","value":"0x0","type":"0x0","chainId":"0xa4b1","v":"0x14986","r":"0x46c55104612e9a38402b767879febf7e63e05d1605c22b51037032c28918bae1","s":"0x275c3214a730eb6a9b5beb777aee761ffd9e6951497af2c1d6a507d17e224ad6"}],"transactionsRoot":"0x80a5756e6fafb2be7b87718e8111762db7ca98c04c932d323bb1e9ef5bc6f825","uncles":[]}}` + testArbReceipts = `[{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x0","effectiveGasPrice":"0x989680","from":"0x00000000000000000000000000000000000a4b05","gasUsed":"0x0","gasUsedForL1":"0x0","l1BlockNumber":"0x149f366","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":"0x00000000000000000000000000000000000a4b05","transactionHash":"0x58cd6dc4c642eb0f96e0cf01f8e34e64f22a9d14581c043a9a23c6028c674052","transactionIndex":"0x0","type":"0x6a"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x1a94a9","effectiveGasPrice":"0x989680","from":"0x619e6175e65e8511c9f91b4e0f87cb2e75321651","gasUsed":"0x1a94a9","gasUsedForL1":"0x1981c1","l1BlockNumber":"0x149f366","logs":[{"address":"0x1baa28178bec3127cfdcb0e11f874c263f502462","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000005c718762feac73fa9003d0c1f98c74ef8d5a6a26","0x000000000000000000000000619e6175e65e8511c9f91b4e0f87cb2e75321651"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000","blockNumber":"0x119b1fd3","transactionHash":"0x334cbe7b01106ca506d239887ef7a471158372cca23a2d758916090283c10294","transactionIndex":"0x1","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x0","removed":false},{"address":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","topics":["0x76c3da0779d2bcebe57c00bd8fc4cf03dfead2becd6568e7287bfe788ab3fa6f","0x000000000000000000000000619e6175e65e8511c9f91b4e0f87cb2e75321651","0x000000000000000000000000000000000000000000000000000095a43b2d4e00","0x0000000000000000000000002495ca17f576e67242ecd171f01ad54791bfb710"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000","blockNumber":"0x119b1fd3","transactionHash":"0x334cbe7b01106ca506d239887ef7a471158372cca23a2d758916090283c10294","transactionIndex":"0x1","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x1","removed":false}],"logsBloom":"0x00104000000000000000000000000000000000000000000000000040000000010000000000000000000000000000000000000000000000000000000000000000000000000100000200020008000000000800000000000000010000000020000000000000000000040000001000000000000000000000000000000010000000000000000008000000000000000000000000000000000000000000000000000000000200000000000000000200000000000000000000000000800000000000000000000002000010000000000000000000000000000000000000000000000002000000000200000000000004000000000000000000000002000000000000000000","status":"0x1","to":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","transactionHash":"0x334cbe7b01106ca506d239887ef7a471158372cca23a2d758916090283c10294","transactionIndex":"0x1","type":"0x0"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x2564e4","effectiveGasPrice":"0x989680","from":"0x16fb1259a1fb59d3cabc6b1ad169762dcf0f8638","gasUsed":"0xad03b","gasUsedForL1":"0x85c4f","l1BlockNumber":"0x149f366","logs":[{"address":"0x82af49447d8a07e3bd95bd0d56f35241523fbab1","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","0x000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76"],"data":"0x000000000000000000000000000000000000000000000000194ba12387825e1b","blockNumber":"0x119b1fd3","transactionHash":"0x677ae449aea214ae1f60875330531d9e9c63dba18d01015ef7379007867e622f","transactionIndex":"0x2","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x2","removed":false},{"address":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76","0x000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0"],"data":"0x000000000000000000000000000000000000000000000000000000015c0070a0","blockNumber":"0x119b1fd3","transactionHash":"0x677ae449aea214ae1f60875330531d9e9c63dba18d01015ef7379007867e622f","transactionIndex":"0x2","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x3","removed":false},{"address":"0xc6962004f452be9203591991d15f6b388e09e8d0","topics":["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67","0x000000000000000000000000e3be1402bdc62d1e4ff4d5658129c5f82745fbad","0x000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffe6b45edc787da1e5000000000000000000000000000000000000000000000000000000015c0070a000000000000000000000000000000000000000000003b54d668d6c2f53c0754c000000000000000000000000000000000000000000000000589cdb85f042223cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd03ea","blockNumber":"0x119b1fd3","transactionHash":"0x677ae449aea214ae1f60875330531d9e9c63dba18d01015ef7379007867e622f","transactionIndex":"0x2","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x4","removed":false}],"logsBloom":"0x00000000000004000010000040000000000000000000000000000000000000000000004000000000000000000000000000004001000020000000000000000000000000010000000800000009000000000040000000000000000000000000000000000000000000000000000400000000000080000000000000000010000800000000000000000000000000400000000000000000002000000000000000000000200000000000000000000000000000000000000000000000000000080000000000002002000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000","status":"0x1","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","transactionHash":"0x677ae449aea214ae1f60875330531d9e9c63dba18d01015ef7379007867e622f","transactionIndex":"0x2","type":"0x0"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x30133f","effectiveGasPrice":"0x989680","from":"0xe3c81b8221bcebccf5eac414cf52156c3c3b38ed","gasUsed":"0xaae5b","gasUsedForL1":"0x85c4f","l1BlockNumber":"0x149f366","logs":[{"address":"0x82af49447d8a07e3bd95bd0d56f35241523fbab1","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","0x000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76"],"data":"0x000000000000000000000000000000000000000000000000142e60e8ac88e194","blockNumber":"0x119b1fd3","transactionHash":"0x85c2d0969c7423a46197febc93ef19be5ef15108e0451c4d4f673c6cb2798e61","transactionIndex":"0x3","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x5","removed":false},{"address":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76","0x000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0"],"data":"0x0000000000000000000000000000000000000000000000000000000115a67dc0","blockNumber":"0x119b1fd3","transactionHash":"0x85c2d0969c7423a46197febc93ef19be5ef15108e0451c4d4f673c6cb2798e61","transactionIndex":"0x3","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x6","removed":false},{"address":"0xc6962004f452be9203591991d15f6b388e09e8d0","topics":["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67","0x000000000000000000000000e3be1402bdc62d1e4ff4d5658129c5f82745fbad","0x000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76"],"data":"0xffffffffffffffffffffffffffffffffffffffffffffffffebd19f1753771e6c0000000000000000000000000000000000000000000000000000000115a67dc000000000000000000000000000000000000000000003b5508846c72263561808000000000000000000000000000000000000000000000000589cdb85f042223cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd03ea","blockNumber":"0x119b1fd3","transactionHash":"0x85c2d0969c7423a46197febc93ef19be5ef15108e0451c4d4f673c6cb2798e61","transactionIndex":"0x3","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x7","removed":false}],"logsBloom":"0x00000000000004000010000040000000000000000000000000000000000000000000004000000000000000000000000000004001000020000000000000000000000000010000000800000009000000000040000000000000000000000000000000000000000000000000000400000000000080000000000000000010000800000000000000000000000000400000000000000000002000000000000000000000200000000000000000000000000000000000000000000000000000080000000000002002000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000","status":"0x1","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","transactionHash":"0x85c2d0969c7423a46197febc93ef19be5ef15108e0451c4d4f673c6cb2798e61","transactionIndex":"0x3","type":"0x0"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x3da54b","effectiveGasPrice":"0x989680","from":"0xf7ffaad1569d8c9626b6e90636793f072a95d259","gasUsed":"0xd920c","gasUsedForL1":"0xcc0e0","l1BlockNumber":"0x149f366","logs":[{"address":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000f7ffaad1569d8c9626b6e90636793f072a95d259","0x000000000000000000000000b45c42fbf8af8df5a1fa080a351e9b2f8e0a56d1"],"data":"0x00000000000000000000000000000000000000000000000000000000004e6566","blockNumber":"0x119b1fd3","transactionHash":"0x14617bb93ae8e7a349affa430390abd482bdb4d6658f20854ecf07895f7c621b","transactionIndex":"0x4","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x8","removed":false}],"logsBloom":"0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000010000000000000000000008000000000000000000000000000000000000000000000000000001000000010000000000000000000000000000011001000000000000000000000000000","status":"0x1","to":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","transactionHash":"0x14617bb93ae8e7a349affa430390abd482bdb4d6658f20854ecf07895f7c621b","transactionIndex":"0x4","type":"0x2"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x471eb4","effectiveGasPrice":"0x989680","from":"0x5096fb354daca9b11ce0d5884fad532b056e05dd","gasUsed":"0x97969","gasUsedForL1":"0x8db46","l1BlockNumber":"0x149f366","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":"0xcd934b818ddd7da4a82cd3e73c014569024c26f8","transactionHash":"0x9a43b119e0247d39e498de5c0f4bc49702354d2368b796591352ed2a9bd55b3b","transactionIndex":"0x5","type":"0x2"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x505e26","effectiveGasPrice":"0x989680","from":"0xb38e8c17e38363af6ebdcb3dae12e0243582891d","gasUsed":"0x93f72","gasUsedForL1":"0x8ed6a","l1BlockNumber":"0x149f366","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":"0xf39cf285e20bffe688e542fce3ecbb3c5064aa5e","transactionHash":"0x2eb017df8f91c0038177ad0cedd4713dab6f6f3cf775d1753f5773ed7890b5bd","transactionIndex":"0x6","type":"0x2"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x5ea2fc","effectiveGasPrice":"0x989680","from":"0x3931dab967c3e2dbb492fe12460a66d0fe4cc857","gasUsed":"0xe44d6","gasUsedForL1":"0xd51fb","l1BlockNumber":"0x149f366","logs":[{"address":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000003931dab967c3e2dbb492fe12460a66d0fe4cc857","0x000000000000000000000000f7e8ec11bd1c22643c2a2879192c818340242d1a"],"data":"0x00000000000000000000000000000000000000000000000000000000014d1970","blockNumber":"0x119b1fd3","transactionHash":"0x533d4df22dabdfc80b090c7a69af5f38d80b5878d33b398273329f552d666d15","transactionIndex":"0x7","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0x9","removed":false}],"logsBloom":"0x00000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000808000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000200000000000000000000000002002080000000000000000000000000000000000000000000020000000000000000000000000000000000000200000000000000000000000000000000000","status":"0x1","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","transactionHash":"0x533d4df22dabdfc80b090c7a69af5f38d80b5878d33b398273329f552d666d15","transactionIndex":"0x7","type":"0x2"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x671ae9","effectiveGasPrice":"0x989680","from":"0x26feadf80ee3c6a13172a9324a00879f994563f7","gasUsed":"0x877ed","gasUsedForL1":"0x825e5","l1BlockNumber":"0x149f366","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":"0x2166f18a7dbdf7c4d4b6a8f4fbec537967939928","transactionHash":"0xa6e7a77e8462adcd7d60a4dca9208c2e8cac34380a7df53f22b21345427d76a6","transactionIndex":"0x8","type":"0x0"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x75187e","effectiveGasPrice":"0x989680","from":"0x25681ab599b4e2ceea31f8b498052c53fc2d74db","gasUsed":"0xdfd95","gasUsedForL1":"0xd51fb","l1BlockNumber":"0x149f366","logs":[{"address":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000025681ab599b4e2ceea31f8b498052c53fc2d74db","0x000000000000000000000000fdc77e8188735b1d889ce0f189c472ecd0eadd52"],"data":"0x0000000000000000000000000000000000000000000000000000000000384e10","blockNumber":"0x119b1fd3","transactionHash":"0x2a47a12b226d557bc1f3fafc54ab53531bfdeddc42f10e8b0104266f7613bb5e","transactionIndex":"0x9","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0xa","removed":false}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000000080000000000000000008000000000800000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008002000000000000000000000000000000010000000000000000000000000000000000000000000000000000000010000000000000000000000000000000","status":"0x1","to":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","transactionHash":"0x2a47a12b226d557bc1f3fafc54ab53531bfdeddc42f10e8b0104266f7613bb5e","transactionIndex":"0x9","type":"0x2"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x8f88e1","effectiveGasPrice":"0x989680","from":"0xa0084b9e25d9fcaf83a4ee5bd7ca2bb708c56c19","gasUsed":"0x1a7063","gasUsedForL1":"0x195d7b","l1BlockNumber":"0x149f366","logs":[{"address":"0x1baa28178bec3127cfdcb0e11f874c263f502462","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000005c718762feac73fa9003d0c1f98c74ef8d5a6a26","0x000000000000000000000000a0084b9e25d9fcaf83a4ee5bd7ca2bb708c56c19"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000","blockNumber":"0x119b1fd3","transactionHash":"0xb8aea70764d5dc3e14d6991dc1de4bebea18fa31b82f2ccca2f96578aba2d6a0","transactionIndex":"0xa","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0xb","removed":false},{"address":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","topics":["0x76c3da0779d2bcebe57c00bd8fc4cf03dfead2becd6568e7287bfe788ab3fa6f","0x000000000000000000000000a0084b9e25d9fcaf83a4ee5bd7ca2bb708c56c19","0x000000000000000000000000000000000000000000000000000096b37a969000","0x000000000000000000000000cb75db6b8e8268ea5053c85eb8606a3a65a5b10a"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000","blockNumber":"0x119b1fd3","transactionHash":"0xb8aea70764d5dc3e14d6991dc1de4bebea18fa31b82f2ccca2f96578aba2d6a0","transactionIndex":"0xa","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0xc","removed":false}],"logsBloom":"0x00100000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000100000200020008000000000800000000000000010000000000000000000020040000200000000000000000000000000000000000000010000000000000000000000000000000000000040000000002000000000000000000400000000000000000000000000200000000000000000000000000000000000000000000002002000010000000000000000000000000000000000000000000000002000000000200000000000000000000000000000000000202100000000000000000","status":"0x1","to":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","transactionHash":"0xb8aea70764d5dc3e14d6991dc1de4bebea18fa31b82f2ccca2f96578aba2d6a0","transactionIndex":"0xa","type":"0x0"}},{"jsonrpc":"2.0","id":16,"result":{"blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","blockNumber":"0x119b1fd3","contractAddress":null,"cumulativeGasUsed":"0x9d057e","effectiveGasPrice":"0x989680","from":"0xa4c3e98e0ab7967ceb81d829bc6a038d9e114b87","gasUsed":"0xd7c9d","gasUsedForL1":"0xc9c9a","l1BlockNumber":"0x149f366","logs":[{"address":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a4c3e98e0ab7967ceb81d829bc6a038d9e114b87","0x00000000000000000000000019fd9164a7f9544de573d8e27747c50c90f1bc39"],"data":"0x0000000000000000000000000000000000000000000000000000000000001c76","blockNumber":"0x119b1fd3","transactionHash":"0xf846e2254370f09b4538900cbb97403739ddab69da5e1e69326b7f90abbe2c27","transactionIndex":"0xb","blockHash":"0x11caca47575fa6aa131858c777279b9174a74733dc75b07cd74992fc4be33eba","logIndex":"0xd","removed":false}],"logsBloom":"0x00000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000004000000020000000020000400000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000000000000080000000000000000200000000000000000000000000000000000","status":"0x1","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","transactionHash":"0xf846e2254370f09b4538900cbb97403739ddab69da5e1e69326b7f90abbe2c27","transactionIndex":"0xb","type":"0x0"}}]` + testArbTraces = `{"jsonrpc":"2.0","id":16,"result":[{"txHash":"0x58cd6dc4c642eb0f96e0cf01f8e34e64f22a9d14581c043a9a23c6028c674052","result":{"beforeEVMTransfers":[],"afterEVMTransfers":[],"from":"0x00000000000000000000000000000000000a4b05","gas":"0x0","gasUsed":"0x0","to":"0x00000000000000000000000000000000000a4b05","input":"0x6bf6a42d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000149f36600000000000000000000000000000000000000000000000000000000119b1fd30000000000000000000000000000000000000000000000000000000000000000","value":"0x0","type":"CALL"}},{"txHash":"0x334cbe7b01106ca506d239887ef7a471158372cca23a2d758916090283c10294","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0x619E6175E65E8511c9F91B4e0F87CB2E75321651","to":null,"value":"0x1d24b30cf900"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0x619E6175E65E8511c9F91B4e0F87CB2E75321651","value":"0xd4cce4f9e80"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0xa3db5d6400"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0xf34095ff680"}],"from":"0x619e6175e65e8511c9f91b4e0f87cb2e75321651","gas":"0x30e4fa","gasUsed":"0x1a94a9","to":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","input":"0x5d9be1060000000000000000000000002495ca17f576e67242ecd171f01ad54791bfb710000000000000000000000000000000000000000000000000000095a43b2d4e0000000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000006786845c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041898d17f65dfbed1b3f2b0e52705b0e45373af6a48d9ebea2c726c91fc67fe1bc33a6068034c641b20c1aae679a5b10e5fd4bddcd62f033bd6fed2196fbc1b2fc1b00000000000000000000000000000000000000000000000000000000000000","calls":[{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x16984e","gasUsed":"0xa3a8","to":"0xd8299bc94141f4c4655ef1ce001755649ec0f1c4","input":"0x5d9be1060000000000000000000000002495ca17f576e67242ecd171f01ad54791bfb710000000000000000000000000000000000000000000000000000095a43b2d4e0000000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000006786845c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041898d17f65dfbed1b3f2b0e52705b0e45373af6a48d9ebea2c726c91fc67fe1bc33a6068034c641b20c1aae679a5b10e5fd4bddcd62f033bd6fed2196fbc1b2fc1b00000000000000000000000000000000000000000000000000000000000000","calls":[{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x162700","gasUsed":"0xbb8","to":"0x0000000000000000000000000000000000000001","input":"0x2b27ad79a636224c46eddc17003ccbbb3a1876bcf91eda79dce4e94cdf226766000000000000000000000000000000000000000000000000000000000000001b898d17f65dfbed1b3f2b0e52705b0e45373af6a48d9ebea2c726c91fc67fe1bc33a6068034c641b20c1aae679a5b10e5fd4bddcd62f033bd6fed2196fbc1b2fc","output":"0x000000000000000000000000f5367e0e5a490491aca8575554b072839567dd19","type":"STATICCALL"},{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x15f5b1","gasUsed":"0x0","to":"0x2495ca17f576e67242ecd171f01ad54791bfb710","input":"0x","value":"0x95a43b2d4e00","type":"CALL"},{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x15e191","gasUsed":"0x3b5e","to":"0x1baa28178bec3127cfdcb0e11f874c263f502462","input":"0xa9059cbb000000000000000000000000619e6175e65e8511c9f91b4e0f87cb2e7532165100000000000000000000000000000000000000000000021e19e0c9bab2400000","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"CALL"}],"value":"0x95a43b2d4e00","type":"DELEGATECALL"}],"value":"0x95a43b2d4e00","type":"CALL"}},{"txHash":"0x677ae449aea214ae1f60875330531d9e9c63dba18d01015ef7379007867e622f","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0x16Fb1259A1FB59D3CaBC6B1Ad169762dCF0F8638","to":null,"value":"0xdbf48207000"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0x16Fb1259A1FB59D3CaBC6B1Ad169762dCF0F8638","value":"0x74d49adc080"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x17645463e00"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x4fbb92c7180"}],"from":"0x16fb1259a1fb59d3cabc6b1ad169762dcf0f8638","gas":"0x171060","gasUsed":"0xad03b","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","input":"0x0b1a740e411301","calls":[{"from":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","gas":"0xd8037","gasUsed":"0x1c10c","to":"0xc6962004f452be9203591991d15f6b388e09e8d0","input":"0x128acb08000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f760000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015c0070a0000000000000000000000000fffd8963efd1fc6a506488495d951d5263988d2500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000000000000000002baf88d065e77c8cc2239327c5edb3a432268e58310001f482af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000","output":"0xffffffffffffffffffffffffffffffffffffffffffffffffe6b45edc787da1e5000000000000000000000000000000000000000000000000000000015c0070a0","calls":[{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xcbb05","gasUsed":"0x4f4c","to":"0x82af49447d8a07e3bd95bd0d56f35241523fbab1","input":"0xa9059cbb000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000194ba12387825e1b","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0x82af49447d8a07e3bd95bd0d56f35241523fbab1","gas":"0xc6c65","gasUsed":"0x32fe","to":"0x8b194beae1d3e0788a1a35173978001acdfba668","input":"0xa9059cbb000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000194ba12387825e1b","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"},{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xc5ff4","gasUsed":"0x2616","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c066b4c2111","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xc12f0","gasUsed":"0x9f9","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c066b4c2111","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"},{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xc375f","gasUsed":"0x9406","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","input":"0xfa461e33ffffffffffffffffffffffffffffffffffffffffffffffffe6b45edc787da1e5000000000000000000000000000000000000000000000000000000015c0070a0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000000000000000002baf88d065e77c8cc2239327c5edb3a432268e58310001f482af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000","calls":[{"from":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","gas":"0xbe26c","gasUsed":"0xa6a","to":"0x1f98431c8ad98523631ae4a59f267346ea31f984","input":"0x1698ee82000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000001f4","output":"0x000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","type":"STATICCALL"},{"from":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","gas":"0xbcf6b","gasUsed":"0x592c","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x23b872dd000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0000000000000000000000000000000000000000000000000000000015c0070a0","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xb9dbf","gasUsed":"0x568a","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x23b872dd000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0000000000000000000000000000000000000000000000000000000015c0070a0","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"},{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xba332","gasUsed":"0x4e2","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c07c74c91b1","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xb7220","gasUsed":"0x229","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c07c74c91b1","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"}],"value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}},{"txHash":"0x85c2d0969c7423a46197febc93ef19be5ef15108e0451c4d4f673c6cb2798e61","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0xE3C81b8221bceBCCf5EAc414Cf52156C3c3b38ed","to":null,"value":"0xdbf48207000"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0xE3C81b8221bceBCCf5EAc414Cf52156C3c3b38ed","value":"0x7617a97f080"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x162145c0e00"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x4fbb92c7180"}],"from":"0xe3c81b8221bcebccf5eac414cf52156c3c3b38ed","gas":"0x171060","gasUsed":"0xaae5b","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","input":"0x08dbd00b5f6301","calls":[{"from":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","gas":"0xd8037","gasUsed":"0x19f2c","to":"0xc6962004f452be9203591991d15f6b388e09e8d0","input":"0x128acb08000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f7600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000115a67dc0000000000000000000000000fffd8963efd1fc6a506488495d951d5263988d2500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000000000000000002baf88d065e77c8cc2239327c5edb3a432268e58310001f482af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000","output":"0xffffffffffffffffffffffffffffffffffffffffffffffffebd19f1753771e6c0000000000000000000000000000000000000000000000000000000115a67dc0","calls":[{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xcdc5d","gasUsed":"0x4f4c","to":"0x82af49447d8a07e3bd95bd0d56f35241523fbab1","input":"0xa9059cbb000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000142e60e8ac88e194","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0x82af49447d8a07e3bd95bd0d56f35241523fbab1","gas":"0xc8d38","gasUsed":"0x32fe","to":"0x8b194beae1d3e0788a1a35173978001acdfba668","input":"0xa9059cbb000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000142e60e8ac88e194","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"},{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xc814b","gasUsed":"0x2616","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c07c74c91b1","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xc33c2","gasUsed":"0x9f9","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c07c74c91b1","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"},{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xc58b8","gasUsed":"0x9406","to":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","input":"0xfa461e33ffffffffffffffffffffffffffffffffffffffffffffffffebd19f1753771e6c0000000000000000000000000000000000000000000000000000000115a67dc0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000000000000000000000000000000000000000002baf88d065e77c8cc2239327c5edb3a432268e58310001f482af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000","calls":[{"from":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","gas":"0xc033f","gasUsed":"0xa6a","to":"0x1f98431c8ad98523631ae4a59f267346ea31f984","input":"0x1698ee82000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000001f4","output":"0x000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","type":"STATICCALL"},{"from":"0xe3be1402bdc62d1e4ff4d5658129c5f82745fbad","gas":"0xbf03e","gasUsed":"0x592c","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x23b872dd000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d00000000000000000000000000000000000000000000000000000000115a67dc0","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xbbe0e","gasUsed":"0x568a","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x23b872dd000000000000000000000000975580eb2b1473ac0b9fdf9f5eec9c26c04a3f76000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d00000000000000000000000000000000000000000000000000000000115a67dc0","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"},{"from":"0xc6962004f452be9203591991d15f6b388e09e8d0","gas":"0xbc48a","gasUsed":"0x4e2","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c08dcf30f71","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xb92f3","gasUsed":"0x229","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x70a08231000000000000000000000000c6962004f452be9203591991d15f6b388e09e8d0","output":"0x00000000000000000000000000000000000000000000000000000c08dcf30f71","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"}],"value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}},{"txHash":"0x14617bb93ae8e7a349affa430390abd482bdb4d6658f20854ecf07895f7c621b","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0xf7ffaAd1569D8C9626b6E90636793f072A95d259","to":null,"value":"0x14f63d1fbb00"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0xf7ffaAd1569D8C9626b6E90636793f072A95d259","value":"0xcdf8ba3ad00"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x7cad185e00"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x79a0463b000"}],"from":"0xf7ffaad1569d8c9626b6e90636793f072a95d259","gas":"0x232b0e","gasUsed":"0xd920c","to":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","input":"0x095ea7b3000000000000000000000000b45c42fbf8af8df5a1fa080a351e9b2f8e0a56d100000000000000000000000000000000000000000000000000000000004e6566","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","gas":"0x15a170","gasUsed":"0x602a","to":"0xf31e1ae27e7cd057c1d6795a5a083e0453d39b50","input":"0x095ea7b3000000000000000000000000b45c42fbf8af8df5a1fa080a351e9b2f8e0a56d100000000000000000000000000000000000000000000000000000000004e6566","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}},{"txHash":"0x9a43b119e0247d39e498de5c0f4bc49702354d2368b796591352ed2a9bd55b3b","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0x5096fB354daca9B11cE0d5884fad532b056E05dd","to":null,"value":"0x9184e72a000"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0x5096fB354daca9B11cE0d5884fad532b056E05dd","value":"0x372a63a6580"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x5e41bf9380"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x5476678a700"}],"from":"0x5096fb354daca9b11ce0d5884fad532b056e05dd","gas":"0xf4240","gasUsed":"0x97969","to":"0xcd934b818ddd7da4a82cd3e73c014569024c26f8","input":"0x00040000ff0503b54a8379","calls":[{"from":"0xcd934b818ddd7da4a82cd3e73c014569024c26f8","gas":"0x5ed37","gasUsed":"0x2616","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0x70a08231000000000000000000000000cd934b818ddd7da4a82cd3e73c014569024c26f8","output":"0x00000000000000000000000000000000000000000000000000000000ca3c284a","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0x5b9fe","gasUsed":"0x9f9","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0x70a08231000000000000000000000000cd934b818ddd7da4a82cd3e73c014569024c26f8","output":"0x00000000000000000000000000000000000000000000000000000000ca3c284a","value":"0x0","type":"DELEGATECALL"}],"type":"STATICCALL"},{"from":"0xcd934b818ddd7da4a82cd3e73c014569024c26f8","gas":"0x5bd15","gasUsed":"0xa88","to":"0xc6962004f452be9203591991d15f6b388e09e8d0","input":"0x3850c7bd","output":"0x00000000000000000000000000000000000000000003b5508846c72263561808fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd03ea00000000000000000000000000000000000000000000000000000000000017a10000000000000000000000000000000000000000000000000000000000002328000000000000000000000000000000000000000000000000000000000000232800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001","type":"STATICCALL"}],"value":"0x0","type":"CALL"}},{"txHash":"0x2eb017df8f91c0038177ad0cedd4713dab6f6f3cf775d1753f5773ed7890b5bd","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0xB38e8c17e38363aF6EbdCb3dAE12e0243582891D","to":null,"value":"0xe7e803ab800"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0xB38e8c17e38363aF6EbdCb3dAE12e0243582891D","value":"0x8fb64be3300"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x30e4f9b400"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x5523682d100"}],"from":"0xb38e8c17e38363af6ebdcb3dae12e0243582891d","gas":"0x185130","gasUsed":"0x93f72","to":"0xf39cf285e20bffe688e542fce3ecbb3c5064aa5e","input":"0x","value":"0xadc3bfe9d2800","type":"CALL"}},{"txHash":"0x533d4df22dabdfc80b090c7a69af5f38d80b5878d33b398273329f552d666d15","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0x3931dAb967C3E2dbb492FE12460a66d0fe4cC857","to":null,"value":"0x151d145eec00"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0x3931dAb967C3E2dbb492FE12460a66d0fe4cC857","value":"0xc9bd1d71d00"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x90c0cdbf80"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x7f081ba0f80"}],"from":"0x3931dab967c3e2dbb492fe12460a66d0fe4cc857","gas":"0x236c38","gasUsed":"0xe44d6","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0xa9059cbb000000000000000000000000f7e8ec11bd1c22643c2a2879192c818340242d1a00000000000000000000000000000000000000000000000000000000014d1970","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0x155337","gasUsed":"0x8253","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0xa9059cbb000000000000000000000000f7e8ec11bd1c22643c2a2879192c818340242d1a00000000000000000000000000000000000000000000000000000000014d1970","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}},{"txHash":"0xa6e7a77e8462adcd7d60a4dca9208c2e8cac34380a7df53f22b21345427d76a6","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0x26FEadf80EE3c6a13172A9324A00879F994563f7","to":null,"value":"0x574fbde6000"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0x26FEadf80EE3c6a13172A9324A00879F994563f7","value":"0x68cca58b80"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x30e4f9b400"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x4db4a3f2080"}],"from":"0x26feadf80ee3c6a13172a9324a00879f994563f7","gas":"0x927c0","gasUsed":"0x877ed","to":"0x2166f18a7dbdf7c4d4b6a8f4fbec537967939928","input":"0x","value":"0x45f9685b7f000","type":"CALL"}},{"txHash":"0x2a47a12b226d557bc1f3fafc54ab53531bfdeddc42f10e8b0104266f7613bb5e","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0x25681Ab599B4E2CEea31F8B498052c53FC2D74db","to":null,"value":"0x14c7768d0200"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0x25681Ab599B4E2CEea31F8B498052c53FC2D74db","value":"0xc70ac80e980"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x6648520900"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x7f081ba0f80"}],"from":"0x25681ab599b4e2ceea31f8b498052c53fc2d74db","gas":"0x22dc94","gasUsed":"0xdfd95","to":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","input":"0xa9059cbb000000000000000000000000fdc77e8188735b1d889ce0f189c472ecd0eadd520000000000000000000000000000000000000000000000000000000000384e10","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9","gas":"0x14c559","gasUsed":"0x3a98","to":"0xf31e1ae27e7cd057c1d6795a5a083e0453d39b50","input":"0xa9059cbb000000000000000000000000fdc77e8188735b1d889ce0f189c472ecd0eadd520000000000000000000000000000000000000000000000000000000000384e10","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}},{"txHash":"0xb8aea70764d5dc3e14d6991dc1de4bebea18fa31b82f2ccca2f96578aba2d6a0","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0xA0084B9E25D9FcAF83A4eE5BD7Ca2Bb708c56c19","to":null,"value":"0x1c5cac1ab380"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0xA0084B9E25D9FcAF83A4eE5BD7Ca2Bb708c56c19","value":"0xc9a66408000"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0xa3db5d6400"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0xf1e6a7ccf80"}],"from":"0xa0084b9e25d9fcaf83a4ee5bd7ca2bb708c56c19","gas":"0x2f9563","gasUsed":"0x1a7063","to":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","input":"0x5d9be106000000000000000000000000cb75db6b8e8268ea5053c85eb8606a3a65a5b10a000000000000000000000000000000000000000000000000000096b37a96900000000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000006786845f00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041924cc2a7d7843a536cc63d7f599379d5bad2735caa791e496ac77c6df7e93ea638dcf6abf80b5425d3c818d5955709d5881321c7d9dfa9d5cb845783b023788e1c00000000000000000000000000000000000000000000000000000000000000","calls":[{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x1571aa","gasUsed":"0xa3a8","to":"0xd8299bc94141f4c4655ef1ce001755649ec0f1c4","input":"0x5d9be106000000000000000000000000cb75db6b8e8268ea5053c85eb8606a3a65a5b10a000000000000000000000000000000000000000000000000000096b37a96900000000000000000000000000000000000000000000000021e19e0c9bab2400000000000000000000000000000000000000000000000000000000000006786845f00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041924cc2a7d7843a536cc63d7f599379d5bad2735caa791e496ac77c6df7e93ea638dcf6abf80b5425d3c818d5955709d5881321c7d9dfa9d5cb845783b023788e1c00000000000000000000000000000000000000000000000000000000000000","calls":[{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x1504f7","gasUsed":"0xbb8","to":"0x0000000000000000000000000000000000000001","input":"0xc7ef40ba1abad2f0864f9cfef525dca255d4d5c5c8478a7d7f5a067a5e348198000000000000000000000000000000000000000000000000000000000000001c924cc2a7d7843a536cc63d7f599379d5bad2735caa791e496ac77c6df7e93ea638dcf6abf80b5425d3c818d5955709d5881321c7d9dfa9d5cb845783b023788e","output":"0x000000000000000000000000f5367e0e5a490491aca8575554b072839567dd19","type":"STATICCALL"},{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x14d3a8","gasUsed":"0x0","to":"0xcb75db6b8e8268ea5053c85eb8606a3a65a5b10a","input":"0x","value":"0x96b37a969000","type":"CALL"},{"from":"0x5c718762feac73fa9003d0c1f98c74ef8d5a6a26","gas":"0x14bf87","gasUsed":"0x3b5e","to":"0x1baa28178bec3127cfdcb0e11f874c263f502462","input":"0xa9059cbb000000000000000000000000a0084b9e25d9fcaf83a4ee5bd7ca2bb708c56c1900000000000000000000000000000000000000000000021e19e0c9bab2400000","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"CALL"}],"value":"0x96b37a969000","type":"DELEGATECALL"}],"value":"0x96b37a969000","type":"CALL"}},{"txHash":"0xf846e2254370f09b4538900cbb97403739ddab69da5e1e69326b7f90abbe2c27","result":{"beforeEVMTransfers":[{"purpose":"feePayment","from":"0xa4c3e98E0AB7967Ceb81D829BC6a038d9E114b87","to":null,"value":"0x104ba9f50a00"}],"afterEVMTransfers":[{"purpose":"gasRefund","from":null,"to":"0xa4c3e98E0AB7967Ceb81D829BC6a038d9E114b87","value":"0x841befabd80"},{"purpose":"feeCollection","from":null,"to":"0xbF5041Fc07E1c866D15c749156657B8eEd0fb649","value":"0x858579c380"},{"purpose":"feeCollection","from":null,"to":"0xa4B00000000000000000000000000000000000F6","value":"0x78465808900"}],"from":"0xa4c3e98e0ab7967ceb81d829bc6a038d9e114b87","gas":"0x1b56e4","gasUsed":"0xd7c9d","to":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","input":"0xa9059cbb00000000000000000000000019fd9164a7f9544de573d8e27747c50c90f1bc390000000000000000000000000000000000000000000000000000000000001c76","output":"0x0000000000000000000000000000000000000000000000000000000000000001","calls":[{"from":"0xaf88d065e77c8cc2239327c5edb3a432268e5831","gas":"0xe10db","gasUsed":"0x8253","to":"0x86e721b43d4ecfa71119dd38c0f938a75fdb57b3","input":"0xa9059cbb00000000000000000000000019fd9164a7f9544de573d8e27747c50c90f1bc390000000000000000000000000000000000000000000000000000000000001c76","output":"0x0000000000000000000000000000000000000000000000000000000000000001","value":"0x0","type":"DELEGATECALL"}],"value":"0x0","type":"CALL"}}]}` +) + +var testArbFullBlock = FullBlockData{ + ChainID: 42161, + BlockNumber: 295378899, + BlockHash: nil, + BlockUnclesCount: 0, + BlockTxs: nil, + Block: []byte(testArbBlock), + Receipts: []byte(testArbReceipts), + Traces: []byte(testArbTraces), + Uncles: nil, +} diff --git a/backend/pkg/commons/db2/raw/signer.go b/backend/pkg/commons/db2/raw/signer.go new file mode 100644 index 000000000..a2c669ec6 --- /dev/null +++ b/backend/pkg/commons/db2/raw/signer.go @@ -0,0 +1,99 @@ +package raw + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/gobitfly/beaconchain/pkg/commons/chain" +) + +type noOpSigner struct{} + +func (s noOpSigner) Equal(other types.Signer) bool { + panic("can't compare with noOpSigner") +} +func (s noOpSigner) Sender(tx *types.Transaction) (common.Address, error) { + panic("can't get sender with noOpSigner") +} +func (s noOpSigner) ChainID() *big.Int { + panic("can't sign with noOpSigner") +} +func (s noOpSigner) Hash(tx *types.Transaction) common.Hash { + panic("can't sign with noOpSigner") +} +func (s noOpSigner) SignatureValues(tx *types.Transaction, sig []byte) (R, S, V *big.Int, err error) { + panic("can't sign with noOpSigner") +} + +// SenderFromDBSigner is a types.Signer that remembers the sender address returned by the RPC +// server. It is stored in the transaction's sender address cache to avoid an additional +// request in TransactionSender. +// inspired by senderFromServer from go-ethereum +// https://github.com/ethereum/go-ethereum/blob/v1.14.11/ethclient/signer.go#L30 +type SenderFromDBSigner struct { + addr common.Address + blockHash common.Hash + noOpSigner +} + +var errNotCached = errors.New("sender not cached") + +func (s *SenderFromDBSigner) Equal(other types.Signer) bool { + os, ok := other.(*SenderFromDBSigner) + return ok && os.blockHash == s.blockHash +} + +func (s *SenderFromDBSigner) Sender(tx *types.Transaction) (common.Address, error) { + if s.addr == (common.Address{}) { + return common.Address{}, errNotCached + } + return s.addr, nil +} + +// setSender doesn't rely on tx.ChainId() because it introduces problems for testing +// tx.ChainId() come from the signature, and we cannot sign for some sender for certain chain ID +// see tests for examples +func setSender(chainID *big.Int, tx *types.Transaction, addr common.Address, block common.Hash) { + switch { + case chainID.Cmp(chain.IDs.Optimistic) == 0: + _, _ = types.Sender(&OptimisticSigner{addr: &addr, blockHash: block}, tx) + default: + _, _ = types.Sender(&SenderFromDBSigner{addr: addr, blockHash: block}, tx) + } +} + +func SignerForChainID(chainID *big.Int, blockHash common.Hash) types.Signer { + switch { + case chainID.Cmp(chain.IDs.Optimistic) == 0: + return &OptimisticSigner{ + blockHash: blockHash, + } + default: + return &SenderFromDBSigner{ + blockHash: blockHash, + } + } +} + +type OptimisticSigner struct { + addr *common.Address + blockHash common.Hash + noOpSigner +} + +func (s *OptimisticSigner) Equal(other types.Signer) bool { + os, ok := other.(*OptimisticSigner) + return ok && os.blockHash == s.blockHash +} + +func (s *OptimisticSigner) Sender(tx *types.Transaction) (common.Address, error) { + // optimism can have transaction from address 0 + // https://docs.optimism.io/stack/transactions/deposit-flow#l1-processing + if s.addr == nil { + return common.Address{}, errNotCached + } + return *s.addr, nil +} diff --git a/backend/pkg/commons/db2/raw/signer_test.go b/backend/pkg/commons/db2/raw/signer_test.go new file mode 100644 index 000000000..f03906c54 --- /dev/null +++ b/backend/pkg/commons/db2/raw/signer_test.go @@ -0,0 +1,116 @@ +package raw + +import ( + "context" + "math/big" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + + "github.com/gobitfly/beaconchain/pkg/commons/chain" +) + +func TestSigner(t *testing.T) { + tests := []struct { + name string + chainID *big.Int + tx *types.Transaction + sender common.Address + wantErr bool + }{ + { + name: "default", + chainID: chain.IDs.Mainnet, + sender: common.HexToAddress("0x1234000000000000000000000000000000000000"), + }, + { + name: "default ok with chain ID = 0 (pre EIP-155)", + chainID: big.NewInt(0), + sender: common.HexToAddress("0x1234000000000000000000000000000000000000"), + }, + { + name: "default error with address 0", + chainID: chain.IDs.Mainnet, + sender: common.Address{}, + wantErr: true, + }, + { + name: "op ok with address 0", + chainID: chain.IDs.Optimistic, + sender: common.Address{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tx := types.NewTx(&types.LegacyTx{}) + setSender(tt.chainID, tx, tt.sender, common.Hash{1}) + sender, err := types.Sender(SignerForChainID(tt.chainID, common.Hash{1}), tx) + if err != nil { + if !tt.wantErr { + t.Fatalf("failed to get tx sender: %v", err) + } + return + } + if got, want := sender, tt.sender; got.Cmp(want) != 0 { + t.Errorf("got sender %v, want %v", got, want) + } + }) + } +} + +func mustGetEnv(key string) func(t *testing.T) string { + return func(t *testing.T) string { + val := os.Getenv(key) + if val == "" { + t.Skipf("skipping test, set %s", key) + } + return val + } +} + +func TestSignerRealCondition(t *testing.T) { + tests := []struct { + name string + chainID *big.Int + txHash common.Hash + blockHash common.Hash + txIndex uint + getUrl func(t *testing.T) string + }{ + { + name: "op without signer", + chainID: chain.IDs.Optimistic, + txHash: common.HexToHash("0xfdb23a026aebea63fb0e56d82bc27d61cc1a4e49c34f88928b371a38742d3bb9"), + blockHash: common.HexToHash("0x239ca8170b66e63659800f92079a30838d52dc90cf71b901cedf394226e87856"), + txIndex: 0, + getUrl: mustGetEnv("NODE_URL_OP"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := ethclient.Dial(tt.getUrl(t)) + if err != nil { + t.Fatal(err) + } + tx, _, err := c.TransactionByHash(context.Background(), tt.txHash) + if err != nil { + t.Fatal(err) + } + sender, err := c.TransactionSender(context.Background(), tx, tt.blockHash, tt.txIndex) + if err != nil { + t.Fatal(err) + } + setSender(tt.chainID, tx, sender, tt.blockHash) + got, err := types.Sender(SignerForChainID(tt.chainID, tt.blockHash), tx) + if err != nil { + t.Fatal(err) + } + if got, want := got, sender; got.Cmp(want) != 0 { + t.Errorf("got sender %v, want %v", got, want) + } + }) + } +} diff --git a/backend/pkg/commons/db2/raw/tables.go b/backend/pkg/commons/db2/raw/tables.go new file mode 100644 index 000000000..bf37198d4 --- /dev/null +++ b/backend/pkg/commons/db2/raw/tables.go @@ -0,0 +1,23 @@ +package raw + +const Table = "blocks-raw" + +const BT_COLUMNFAMILY_BLOCK = "b" +const BT_COLUMN_BLOCK = "b" +const BT_COLUMNFAMILY_RECEIPTS = "r" +const BT_COLUMN_RECEIPTS = "r" +const BT_COLUMNFAMILY_TRACES = "t" +const BT_COLUMN_TRACES = "t" +const BT_COLUMNFAMILY_UNCLES = "u" +const BT_COLUMN_UNCLES = "u" + +const MAX_EL_BLOCK_NUMBER = int64(1_000_000_000_000 - 1) + +var Schema = map[string][]string{ + Table: { + BT_COLUMNFAMILY_BLOCK, + BT_COLUMNFAMILY_RECEIPTS, + BT_COLUMNFAMILY_TRACES, + BT_COLUMNFAMILY_UNCLES, + }, +} diff --git a/backend/pkg/commons/db2/raw/validation.go b/backend/pkg/commons/db2/raw/validation.go new file mode 100644 index 000000000..6fbe247bd --- /dev/null +++ b/backend/pkg/commons/db2/raw/validation.go @@ -0,0 +1,87 @@ +package raw + +import ( + "encoding/json" + "fmt" + + "github.com/gobitfly/beaconchain/pkg/commons/chain" + "github.com/gobitfly/beaconchain/pkg/commons/hexutil" +) + +type minimalBlock struct { + Result struct { + Hash string `json:"hash"` + Transactions []struct { + Hash string `json:"hash"` + } `json:"transactions"` + } `json:"result"` +} +type minimalReceipts struct { + Result []minimalReceipt `json:"result"` +} +type minimalReceiptResp struct { + Result minimalReceipt `json:"result"` +} +type minimalReceipt struct { + BlockHash string `json:"blockHash"` + Hash string `json:"transactionHash"` +} +type minimalTraces struct { + Result []struct { + TxHash string `json:"txHash"` + } `json:"result"` +} + +func validateBlock(fullBlock FullBlockData) error { + if len(fullBlock.Block) == 0 || len(fullBlock.BlockTxs) != 0 && len(fullBlock.Receipts) == 0 || len(fullBlock.BlockTxs) != 0 && len(fullBlock.Traces) == 0 { + return fmt.Errorf("empty data block=%d receipts=%d traces=%d", len(fullBlock.Block), len(fullBlock.Receipts), len(fullBlock.Traces)) + } + var block minimalBlock + _ = json.Unmarshal(fullBlock.Block, &block) + + var receipts minimalReceipts + _ = json.Unmarshal(fullBlock.Receipts, &receipts) + // Arbitrum did not support eth_getBlockReceipts at one point + // so the receipt data is the list of all eth_getTransactionReceipt responses + if fullBlock.ChainID == chain.IDs.Arbitrum.Uint64() { + receipts = normalizeReceipts(fullBlock.Receipts) + } + + var traces minimalTraces + _ = json.Unmarshal(fullBlock.Traces, &traces) + + if len(block.Result.Transactions) != len(receipts.Result) || len(block.Result.Transactions) != len(traces.Result) { + return fmt.Errorf("mismatch transaction count block=%d receipt=%d trace=%d", len(block.Result.Transactions), len(receipts.Result), len(traces.Result)) + } + + if len(block.Result.Transactions) == 0 { + return nil + } + + if block.Result.Hash != receipts.Result[0].BlockHash { + return fmt.Errorf("mismatch block hash block=%s receipt=%s", block.Result.Hash, receipts.Result[0].BlockHash) + } + + for i := 0; i < len(block.Result.Transactions); i++ { + tx, receipt, trace := block.Result.Transactions[i].Hash, block.Result.Transactions[i].Hash, traces.Result[i].TxHash + if tx != receipt || (trace != "" && tx != trace) { + return fmt.Errorf("mismatch transaction hash at index=%d block=%s receipt=%s trace=%s", i, tx, receipt, trace) + } + } + + return nil +} + +// normalizeReceipts parse a list of eth_getTransactionReceipt response and transform it to something similar to +// eth_getBlockReceipts response +func normalizeReceipts(rawReceipts hexutil.Bytes) minimalReceipts { + var receipts []minimalReceiptResp + _ = json.Unmarshal(rawReceipts, &receipts) + var normalizedReceipts []minimalReceipt + for _, receipt := range receipts { + normalizedReceipts = append(normalizedReceipts, receipt.Result) + } + return minimalReceipts{ + Result: normalizedReceipts, + } +} diff --git a/backend/pkg/commons/types/config.go b/backend/pkg/commons/types/config.go index 3629ba370..4aa0e0d3b 100644 --- a/backend/pkg/commons/types/config.go +++ b/backend/pkg/commons/types/config.go @@ -7,6 +7,16 @@ import ( "github.com/ethereum/go-ethereum/params" ) +type Bigtable struct { + Project string `yaml:"project" env:"PROJECT"` + Instance string `yaml:"instance" env:"INSTANCE"` + Emulator bool `yaml:"emulator" env:"EMULATOR"` + EmulatorPort int `yaml:"emulatorPort" env:"EMULATOR_PORT"` + EmulatorHost string `yaml:"emulatorHost" env:"EMULATOR_HOST"` + V2SchemaCutOffEpoch uint64 `yaml:"v2SchemaCutOffEpoch" env:"V2_SCHEMA_CUTT_OFF_EPOCH"` + Remote string `yaml:"remote"` +} + // Config is a struct to hold the configuration data type Config struct { JustV2 bool `yaml:"justV2" env:"JUST_V2"` // temp, remove at some point @@ -15,15 +25,9 @@ type Config struct { WriterDatabase DatabaseConfig `yaml:"writerDatabase" env:", prefix=WRITER_"` AlloyReader DatabaseConfig `yaml:"alloyReader" env:", prefix=ALLOY_READER_"` AlloyWriter DatabaseConfig `yaml:"alloyWriter" env:", prefix=ALLOY_WRITER_"` - Bigtable struct { - Project string `yaml:"project" env:"PROJECT"` - Instance string `yaml:"instance" env:"INSTANCE"` - Emulator bool `yaml:"emulator" env:"EMULATOR"` - EmulatorPort int `yaml:"emulatorPort" env:"EMULATOR_PORT"` - EmulatorHost string `yaml:"emulatorHost" env:"EMULATOR_HOST"` - V2SchemaCutOffEpoch uint64 `yaml:"v2SchemaCutOffEpoch" env:"V2_SCHEMA_CUTT_OFF_EPOCH"` - } `yaml:"bigtable" env:", prefix=BIGTABLE_"` - BlobIndexer struct { + Bigtable Bigtable `yaml:"bigtable" env:", prefix=BIGTABLE_"` + RawBigtable Bigtable `yaml:"rawBigtable" env:", prefix=RAW_BIGTABLE_"` + BlobIndexer struct { S3 struct { Endpoint string `yaml:"endpoint" env:"ENDPOINT"` // s3 endpoint Bucket string `yaml:"bucket" env:"BUCKET"` // s3 bucket diff --git a/backend/pkg/commons/types/eth1.pb.go b/backend/pkg/commons/types/eth1.pb.go index 8275684c1..803743344 100644 --- a/backend/pkg/commons/types/eth1.pb.go +++ b/backend/pkg/commons/types/eth1.pb.go @@ -1,15 +1,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.1 -// protoc v3.12.4 +// protoc v5.28.2 // source: eth1.proto package types import ( - timestamp "github.com/golang/protobuf/ptypes/timestamp" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -21,31 +21,80 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type StatusType int32 + +const ( + StatusType_FAILED StatusType = 0 + StatusType_SUCCESS StatusType = 1 + StatusType_PARTIAL StatusType = 2 +) + +// Enum value maps for StatusType. +var ( + StatusType_name = map[int32]string{ + 0: "FAILED", + 1: "SUCCESS", + 2: "PARTIAL", + } + StatusType_value = map[string]int32{ + "FAILED": 0, + "SUCCESS": 1, + "PARTIAL": 2, + } +) + +func (x StatusType) Enum() *StatusType { + p := new(StatusType) + *p = x + return p +} + +func (x StatusType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (StatusType) Descriptor() protoreflect.EnumDescriptor { + return file_eth1_proto_enumTypes[0].Descriptor() +} + +func (StatusType) Type() protoreflect.EnumType { + return &file_eth1_proto_enumTypes[0] +} + +func (x StatusType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use StatusType.Descriptor instead. +func (StatusType) EnumDescriptor() ([]byte, []int) { + return file_eth1_proto_rawDescGZIP(), []int{0} +} + // Eth1Block is stored in the blocks table under : type Eth1Block struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - ParentHash []byte `protobuf:"bytes,2,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` - UncleHash []byte `protobuf:"bytes,3,opt,name=uncle_hash,json=uncleHash,proto3" json:"uncle_hash,omitempty"` - Coinbase []byte `protobuf:"bytes,4,opt,name=coinbase,proto3" json:"coinbase,omitempty"` - Root []byte `protobuf:"bytes,5,opt,name=root,proto3" json:"root,omitempty"` - TxHash []byte `protobuf:"bytes,6,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` - ReceiptHash []byte `protobuf:"bytes,7,opt,name=receipt_hash,json=receiptHash,proto3" json:"receipt_hash,omitempty"` - Difficulty []byte `protobuf:"bytes,8,opt,name=difficulty,proto3" json:"difficulty,omitempty"` - Number uint64 `protobuf:"varint,9,opt,name=number,proto3" json:"number,omitempty"` - GasLimit uint64 `protobuf:"varint,10,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` - GasUsed uint64 `protobuf:"varint,11,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,12,opt,name=time,proto3" json:"time,omitempty"` - Extra []byte `protobuf:"bytes,13,opt,name=extra,proto3" json:"extra,omitempty"` - MixDigest []byte `protobuf:"bytes,14,opt,name=mix_digest,json=mixDigest,proto3" json:"mix_digest,omitempty"` - Bloom []byte `protobuf:"bytes,17,opt,name=bloom,proto3" json:"bloom,omitempty"` - BaseFee []byte `protobuf:"bytes,18,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` - Uncles []*Eth1Block `protobuf:"bytes,20,rep,name=uncles,proto3" json:"uncles,omitempty"` - Transactions []*Eth1Transaction `protobuf:"bytes,21,rep,name=transactions,proto3" json:"transactions,omitempty"` - Withdrawals []*Eth1Withdrawal `protobuf:"bytes,22,rep,name=withdrawals,proto3" json:"withdrawals,omitempty"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + ParentHash []byte `protobuf:"bytes,2,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` + UncleHash []byte `protobuf:"bytes,3,opt,name=uncle_hash,json=uncleHash,proto3" json:"uncle_hash,omitempty"` + Coinbase []byte `protobuf:"bytes,4,opt,name=coinbase,proto3" json:"coinbase,omitempty"` + Root []byte `protobuf:"bytes,5,opt,name=root,proto3" json:"root,omitempty"` + TxHash []byte `protobuf:"bytes,6,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + ReceiptHash []byte `protobuf:"bytes,7,opt,name=receipt_hash,json=receiptHash,proto3" json:"receipt_hash,omitempty"` + Difficulty []byte `protobuf:"bytes,8,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + Number uint64 `protobuf:"varint,9,opt,name=number,proto3" json:"number,omitempty"` + GasLimit uint64 `protobuf:"varint,10,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + GasUsed uint64 `protobuf:"varint,11,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=time,proto3" json:"time,omitempty"` + Extra []byte `protobuf:"bytes,13,opt,name=extra,proto3" json:"extra,omitempty"` + MixDigest []byte `protobuf:"bytes,14,opt,name=mix_digest,json=mixDigest,proto3" json:"mix_digest,omitempty"` + Bloom []byte `protobuf:"bytes,17,opt,name=bloom,proto3" json:"bloom,omitempty"` + BaseFee []byte `protobuf:"bytes,18,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` + Uncles []*Eth1Block `protobuf:"bytes,20,rep,name=uncles,proto3" json:"uncles,omitempty"` + Transactions []*Eth1Transaction `protobuf:"bytes,21,rep,name=transactions,proto3" json:"transactions,omitempty"` + Withdrawals []*Eth1Withdrawal `protobuf:"bytes,22,rep,name=withdrawals,proto3" json:"withdrawals,omitempty"` // EIP 4844 BlobGasUsed uint64 `protobuf:"varint,23,opt,name=blob_gas_used,json=blobGasUsed,proto3" json:"blob_gas_used,omitempty"` ExcessBlobGas uint64 `protobuf:"varint,24,opt,name=excess_blob_gas,json=excessBlobGas,proto3" json:"excess_blob_gas,omitempty"` @@ -160,7 +209,7 @@ func (x *Eth1Block) GetGasUsed() uint64 { return 0 } -func (x *Eth1Block) GetTime() *timestamp.Timestamp { +func (x *Eth1Block) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -320,13 +369,14 @@ type Eth1Transaction struct { AccessList []*AccessList `protobuf:"bytes,15,rep,name=access_list,json=accessList,proto3" json:"access_list,omitempty"` Hash []byte `protobuf:"bytes,16,opt,name=hash,proto3" json:"hash,omitempty"` // Receipt fields - ContractAddress []byte `protobuf:"bytes,17,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` - CommulativeGasUsed uint64 `protobuf:"varint,18,opt,name=commulative_gas_used,json=commulativeGasUsed,proto3" json:"commulative_gas_used,omitempty"` - GasUsed uint64 `protobuf:"varint,19,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` - LogsBloom []byte `protobuf:"bytes,20,opt,name=logs_bloom,json=logsBloom,proto3" json:"logs_bloom,omitempty"` - Status uint64 `protobuf:"varint,21,opt,name=status,proto3" json:"status,omitempty"` - ErrorMsg string `protobuf:"bytes,22,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` - Logs []*Eth1Log `protobuf:"bytes,23,rep,name=logs,proto3" json:"logs,omitempty"` + ContractAddress []byte `protobuf:"bytes,17,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + CommulativeGasUsed uint64 `protobuf:"varint,18,opt,name=commulative_gas_used,json=commulativeGasUsed,proto3" json:"commulative_gas_used,omitempty"` + GasUsed uint64 `protobuf:"varint,19,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + LogsBloom []byte `protobuf:"bytes,20,opt,name=logs_bloom,json=logsBloom,proto3" json:"logs_bloom,omitempty"` + Status uint64 `protobuf:"varint,21,opt,name=status,proto3" json:"status,omitempty"` + // reserved 22; // string error_msg = 22; + ErrorMsg string `protobuf:"bytes,22,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` + Logs []*Eth1Log `protobuf:"bytes,23,rep,name=logs,proto3" json:"logs,omitempty"` // Internal transactions Itx []*Eth1InternalTransaction `protobuf:"bytes,24,rep,name=itx,proto3" json:"itx,omitempty"` // EIP 4844 transaction @@ -817,21 +867,21 @@ type Eth1BlockIndexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - ParentHash []byte `protobuf:"bytes,2,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` - UncleHash []byte `protobuf:"bytes,3,opt,name=uncle_hash,json=uncleHash,proto3" json:"uncle_hash,omitempty"` - Coinbase []byte `protobuf:"bytes,4,opt,name=coinbase,proto3" json:"coinbase,omitempty"` - Difficulty []byte `protobuf:"bytes,8,opt,name=difficulty,proto3" json:"difficulty,omitempty"` - Number uint64 `protobuf:"varint,9,opt,name=number,proto3" json:"number,omitempty"` - GasLimit uint64 `protobuf:"varint,10,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` - GasUsed uint64 `protobuf:"varint,11,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,12,opt,name=time,proto3" json:"time,omitempty"` - BaseFee []byte `protobuf:"bytes,18,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` - UncleCount uint64 `protobuf:"varint,19,opt,name=uncle_count,json=uncleCount,proto3" json:"uncle_count,omitempty"` - TransactionCount uint64 `protobuf:"varint,20,opt,name=transaction_count,json=transactionCount,proto3" json:"transaction_count,omitempty"` - Mev []byte `protobuf:"bytes,21,opt,name=mev,proto3" json:"mev,omitempty"` - LowestGasPrice []byte `protobuf:"bytes,22,opt,name=lowest_gas_price,json=lowestGasPrice,proto3" json:"lowest_gas_price,omitempty"` - HighestGasPrice []byte `protobuf:"bytes,23,opt,name=highest_gas_price,json=highestGasPrice,proto3" json:"highest_gas_price,omitempty"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + ParentHash []byte `protobuf:"bytes,2,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` + UncleHash []byte `protobuf:"bytes,3,opt,name=uncle_hash,json=uncleHash,proto3" json:"uncle_hash,omitempty"` + Coinbase []byte `protobuf:"bytes,4,opt,name=coinbase,proto3" json:"coinbase,omitempty"` + Difficulty []byte `protobuf:"bytes,8,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + Number uint64 `protobuf:"varint,9,opt,name=number,proto3" json:"number,omitempty"` + GasLimit uint64 `protobuf:"varint,10,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + GasUsed uint64 `protobuf:"varint,11,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=time,proto3" json:"time,omitempty"` + BaseFee []byte `protobuf:"bytes,18,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` + UncleCount uint64 `protobuf:"varint,19,opt,name=uncle_count,json=uncleCount,proto3" json:"uncle_count,omitempty"` + TransactionCount uint64 `protobuf:"varint,20,opt,name=transaction_count,json=transactionCount,proto3" json:"transaction_count,omitempty"` + Mev []byte `protobuf:"bytes,21,opt,name=mev,proto3" json:"mev,omitempty"` + LowestGasPrice []byte `protobuf:"bytes,22,opt,name=lowest_gas_price,json=lowestGasPrice,proto3" json:"lowest_gas_price,omitempty"` + HighestGasPrice []byte `protobuf:"bytes,23,opt,name=highest_gas_price,json=highestGasPrice,proto3" json:"highest_gas_price,omitempty"` // uint64 duration = 24; TxReward []byte `protobuf:"bytes,25,opt,name=tx_reward,json=txReward,proto3" json:"tx_reward,omitempty"` UncleReward []byte `protobuf:"bytes,26,opt,name=uncle_reward,json=uncleReward,proto3" json:"uncle_reward,omitempty"` @@ -932,7 +982,7 @@ func (x *Eth1BlockIndexed) GetGasUsed() uint64 { return 0 } -func (x *Eth1BlockIndexed) GetTime() *timestamp.Timestamp { +func (x *Eth1BlockIndexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1028,14 +1078,14 @@ type Eth1UncleIndexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - Number uint64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"` - GasLimit uint64 `protobuf:"varint,3,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` - GasUsed uint64 `protobuf:"varint,4,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` - BaseFee []byte `protobuf:"bytes,5,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` - Difficulty []byte `protobuf:"bytes,6,opt,name=difficulty,proto3" json:"difficulty,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,7,opt,name=time,proto3" json:"time,omitempty"` - Reward []byte `protobuf:"bytes,8,opt,name=reward,proto3" json:"reward,omitempty"` + BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Number uint64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"` + GasLimit uint64 `protobuf:"varint,3,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + GasUsed uint64 `protobuf:"varint,4,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + BaseFee []byte `protobuf:"bytes,5,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` + Difficulty []byte `protobuf:"bytes,6,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=time,proto3" json:"time,omitempty"` + Reward []byte `protobuf:"bytes,8,opt,name=reward,proto3" json:"reward,omitempty"` } func (x *Eth1UncleIndexed) Reset() { @@ -1112,7 +1162,7 @@ func (x *Eth1UncleIndexed) GetDifficulty() []byte { return nil } -func (x *Eth1UncleIndexed) GetTime() *timestamp.Timestamp { +func (x *Eth1UncleIndexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1131,12 +1181,12 @@ type Eth1WithdrawalIndexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - Index uint64 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` - ValidatorIndex uint64 `protobuf:"varint,3,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty"` - Address []byte `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` - Amount []byte `protobuf:"bytes,5,opt,name=amount,proto3" json:"amount,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,6,opt,name=time,proto3" json:"time,omitempty"` + BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Index uint64 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + ValidatorIndex uint64 `protobuf:"varint,3,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty"` + Address []byte `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` + Amount []byte `protobuf:"bytes,5,opt,name=amount,proto3" json:"amount,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=time,proto3" json:"time,omitempty"` } func (x *Eth1WithdrawalIndexed) Reset() { @@ -1206,7 +1256,7 @@ func (x *Eth1WithdrawalIndexed) GetAmount() []byte { return nil } -func (x *Eth1WithdrawalIndexed) GetTime() *timestamp.Timestamp { +func (x *Eth1WithdrawalIndexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1218,22 +1268,23 @@ type Eth1TransactionIndexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,3,opt,name=time,proto3" json:"time,omitempty"` - MethodId []byte `protobuf:"bytes,4,opt,name=method_id,json=methodId,proto3" json:"method_id,omitempty"` - From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` - Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"` - TxFee []byte `protobuf:"bytes,8,opt,name=tx_fee,json=txFee,proto3" json:"tx_fee,omitempty"` - GasPrice []byte `protobuf:"bytes,9,opt,name=gas_price,json=gasPrice,proto3" json:"gas_price,omitempty"` - IsContractCreation bool `protobuf:"varint,10,opt,name=is_contract_creation,json=isContractCreation,proto3" json:"is_contract_creation,omitempty"` - // invokes_contract is unused, should mark reserved! + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time,proto3" json:"time,omitempty"` + MethodId []byte `protobuf:"bytes,4,opt,name=method_id,json=methodId,proto3" json:"method_id,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` + To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"` + TxFee []byte `protobuf:"bytes,8,opt,name=tx_fee,json=txFee,proto3" json:"tx_fee,omitempty"` + GasPrice []byte `protobuf:"bytes,9,opt,name=gas_price,json=gasPrice,proto3" json:"gas_price,omitempty"` + IsContractCreation bool `protobuf:"varint,10,opt,name=is_contract_creation,json=isContractCreation,proto3" json:"is_contract_creation,omitempty"` + // reserved 11; // bool invokes_contract = 11; InvokesContract bool `protobuf:"varint,11,opt,name=invokes_contract,json=invokesContract,proto3" json:"invokes_contract,omitempty"` ErrorMsg string `protobuf:"bytes,12,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` // EIP 4844 - BlobTxFee []byte `protobuf:"bytes,13,opt,name=blob_tx_fee,json=blobTxFee,proto3" json:"blob_tx_fee,omitempty"` - BlobGasPrice []byte `protobuf:"bytes,14,opt,name=blob_gas_price,json=blobGasPrice,proto3" json:"blob_gas_price,omitempty"` + BlobTxFee []byte `protobuf:"bytes,13,opt,name=blob_tx_fee,json=blobTxFee,proto3" json:"blob_tx_fee,omitempty"` + BlobGasPrice []byte `protobuf:"bytes,14,opt,name=blob_gas_price,json=blobGasPrice,proto3" json:"blob_gas_price,omitempty"` + Status StatusType `protobuf:"varint,15,opt,name=status,proto3,enum=types.StatusType" json:"status,omitempty"` } func (x *Eth1TransactionIndexed) Reset() { @@ -1282,7 +1333,7 @@ func (x *Eth1TransactionIndexed) GetBlockNumber() uint64 { return 0 } -func (x *Eth1TransactionIndexed) GetTime() *timestamp.Timestamp { +func (x *Eth1TransactionIndexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1366,18 +1417,26 @@ func (x *Eth1TransactionIndexed) GetBlobGasPrice() []byte { return nil } +func (x *Eth1TransactionIndexed) GetStatus() StatusType { + if x != nil { + return x.Status + } + return StatusType_FAILED +} + type Eth1InternalTransactionIndexed struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` - BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` - From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` - Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"` + ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` + To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"` + Reverted bool `protobuf:"varint,8,opt,name=reverted,proto3" json:"reverted,omitempty"` } func (x *Eth1InternalTransactionIndexed) Reset() { @@ -1433,7 +1492,7 @@ func (x *Eth1InternalTransactionIndexed) GetType() string { return "" } -func (x *Eth1InternalTransactionIndexed) GetTime() *timestamp.Timestamp { +func (x *Eth1InternalTransactionIndexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1461,24 +1520,32 @@ func (x *Eth1InternalTransactionIndexed) GetValue() []byte { return nil } +func (x *Eth1InternalTransactionIndexed) GetReverted() bool { + if x != nil { + return x.Reverted + } + return false +} + // https://eips.ethereum.org/EIPS/eip-4844 type Eth1BlobTransactionIndexed struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,3,opt,name=time,proto3" json:"time,omitempty"` - From []byte `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"` - Value []byte `protobuf:"bytes,6,opt,name=value,proto3" json:"value,omitempty"` - TxFee []byte `protobuf:"bytes,7,opt,name=tx_fee,json=txFee,proto3" json:"tx_fee,omitempty"` - GasPrice []byte `protobuf:"bytes,8,opt,name=gas_price,json=gasPrice,proto3" json:"gas_price,omitempty"` - BlobTxFee []byte `protobuf:"bytes,9,opt,name=blob_tx_fee,json=blobTxFee,proto3" json:"blob_tx_fee,omitempty"` - BlobGasPrice []byte `protobuf:"bytes,10,opt,name=blob_gas_price,json=blobGasPrice,proto3" json:"blob_gas_price,omitempty"` - ErrorMsg string `protobuf:"bytes,12,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` - BlobVersionedHashes [][]byte `protobuf:"bytes,13,rep,name=blob_versioned_hashes,json=blobVersionedHashes,proto3" json:"blob_versioned_hashes,omitempty"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time,proto3" json:"time,omitempty"` + From []byte `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` + To []byte `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"` + Value []byte `protobuf:"bytes,6,opt,name=value,proto3" json:"value,omitempty"` + TxFee []byte `protobuf:"bytes,7,opt,name=tx_fee,json=txFee,proto3" json:"tx_fee,omitempty"` + GasPrice []byte `protobuf:"bytes,8,opt,name=gas_price,json=gasPrice,proto3" json:"gas_price,omitempty"` + BlobTxFee []byte `protobuf:"bytes,9,opt,name=blob_tx_fee,json=blobTxFee,proto3" json:"blob_tx_fee,omitempty"` + BlobGasPrice []byte `protobuf:"bytes,10,opt,name=blob_gas_price,json=blobGasPrice,proto3" json:"blob_gas_price,omitempty"` + InvokesContract bool `protobuf:"varint,11,opt,name=invokes_contract,json=invokesContract,proto3" json:"invokes_contract,omitempty"` + ErrorMsg string `protobuf:"bytes,12,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"` + BlobVersionedHashes [][]byte `protobuf:"bytes,13,rep,name=blob_versioned_hashes,json=blobVersionedHashes,proto3" json:"blob_versioned_hashes,omitempty"` } func (x *Eth1BlobTransactionIndexed) Reset() { @@ -1527,7 +1594,7 @@ func (x *Eth1BlobTransactionIndexed) GetBlockNumber() uint64 { return 0 } -func (x *Eth1BlobTransactionIndexed) GetTime() *timestamp.Timestamp { +func (x *Eth1BlobTransactionIndexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1583,6 +1650,13 @@ func (x *Eth1BlobTransactionIndexed) GetBlobGasPrice() []byte { return nil } +func (x *Eth1BlobTransactionIndexed) GetInvokesContract() bool { + if x != nil { + return x.InvokesContract + } + return false +} + func (x *Eth1BlobTransactionIndexed) GetErrorMsg() string { if x != nil { return x.ErrorMsg @@ -1602,13 +1676,13 @@ type Eth1ERC20Indexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` - BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - TokenAddress []byte `protobuf:"bytes,3,opt,name=token_address,json=tokenAddress,proto3" json:"token_address,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` - From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` - Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"` + ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + TokenAddress []byte `protobuf:"bytes,3,opt,name=token_address,json=tokenAddress,proto3" json:"token_address,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` + To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"` } func (x *Eth1ERC20Indexed) Reset() { @@ -1664,7 +1738,7 @@ func (x *Eth1ERC20Indexed) GetTokenAddress() []byte { return nil } -func (x *Eth1ERC20Indexed) GetTime() *timestamp.Timestamp { +func (x *Eth1ERC20Indexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1697,13 +1771,13 @@ type Eth1ERC721Indexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` - BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - TokenAddress []byte `protobuf:"bytes,3,opt,name=token_address,json=tokenAddress,proto3" json:"token_address,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` - From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` - TokenId []byte `protobuf:"bytes,7,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + TokenAddress []byte `protobuf:"bytes,3,opt,name=token_address,json=tokenAddress,proto3" json:"token_address,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` + To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + TokenId []byte `protobuf:"bytes,7,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` } func (x *Eth1ERC721Indexed) Reset() { @@ -1759,7 +1833,7 @@ func (x *Eth1ERC721Indexed) GetTokenAddress() []byte { return nil } -func (x *Eth1ERC721Indexed) GetTime() *timestamp.Timestamp { +func (x *Eth1ERC721Indexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -1793,14 +1867,14 @@ type ETh1ERC1155Indexed struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` - BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - TokenAddress []byte `protobuf:"bytes,3,opt,name=token_address,json=tokenAddress,proto3" json:"token_address,omitempty"` - Time *timestamp.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` - From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` - TokenId []byte `protobuf:"bytes,7,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Value []byte `protobuf:"bytes,8,opt,name=value,proto3" json:"value,omitempty"` + ParentHash []byte `protobuf:"bytes,1,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + TokenAddress []byte `protobuf:"bytes,3,opt,name=token_address,json=tokenAddress,proto3" json:"token_address,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` + To []byte `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + TokenId []byte `protobuf:"bytes,7,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Value []byte `protobuf:"bytes,8,opt,name=value,proto3" json:"value,omitempty"` // the address approved to make the transfer Operator []byte `protobuf:"bytes,9,opt,name=operator,proto3" json:"operator,omitempty"` } @@ -1858,7 +1932,7 @@ func (x *ETh1ERC1155Indexed) GetTokenAddress() []byte { return nil } -func (x *ETh1ERC1155Indexed) GetTime() *timestamp.Timestamp { +func (x *ETh1ERC1155Indexed) GetTime() *timestamppb.Timestamp { if x != nil { return x.Time } @@ -2115,7 +2189,7 @@ var file_eth1_proto_rawDesc = []byte{ 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, - 0x69, 0x6d, 0x65, 0x22, 0xca, 0x03, 0x0a, 0x16, 0x45, 0x74, 0x68, 0x31, 0x54, 0x72, 0x61, 0x6e, + 0x69, 0x6d, 0x65, 0x22, 0xf5, 0x03, 0x0a, 0x16, 0x45, 0x74, 0x68, 0x31, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, @@ -2144,93 +2218,103 @@ var file_eth1_proto_rawDesc = []byte{ 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x54, 0x78, 0x46, 0x65, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x62, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, - 0x22, 0xe2, 0x01, 0x0a, 0x1e, 0x45, 0x74, 0x68, 0x31, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, - 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x8e, 0x03, 0x0a, 0x1a, 0x45, 0x74, 0x68, 0x31, 0x42, 0x6c, - 0x6f, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, + 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xfe, 0x01, 0x0a, 0x1e, + 0x45, 0x74, 0x68, 0x31, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x22, 0xb3, 0x03, 0x0a, + 0x1a, 0x45, 0x74, 0x68, 0x31, 0x42, 0x6c, 0x6f, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, + 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x15, 0x0a, 0x06, + 0x74, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x78, + 0x46, 0x65, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x12, 0x1e, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x74, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x62, 0x54, 0x78, 0x46, 0x65, 0x65, + 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x62, 0x47, 0x61, + 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, + 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x32, + 0x0a, 0x15, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x13, 0x62, + 0x6c, 0x6f, 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x48, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x10, 0x45, 0x74, 0x68, 0x31, 0x45, 0x52, 0x43, 0x32, 0x30, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x04, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, - 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x78, 0x46, 0x65, 0x65, 0x12, 0x1b, 0x0a, 0x09, - 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x08, 0x67, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, - 0x62, 0x5f, 0x74, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, - 0x62, 0x6c, 0x6f, 0x62, 0x54, 0x78, 0x46, 0x65, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, - 0x62, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x62, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, - 0x1b, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x32, 0x0a, 0x15, - 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x13, 0x62, 0x6c, 0x6f, - 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x22, 0xe5, 0x01, 0x0a, 0x10, 0x45, 0x74, 0x68, 0x31, 0x45, - 0x52, 0x43, 0x32, 0x30, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, - 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xeb, - 0x01, 0x0a, 0x11, 0x45, 0x74, 0x68, 0x31, 0x45, 0x52, 0x43, 0x37, 0x32, 0x31, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, - 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, - 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, - 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x22, 0x9e, 0x02, 0x0a, - 0x12, 0x45, 0x54, 0x68, 0x31, 0x45, 0x52, 0x43, 0x31, 0x31, 0x35, 0x35, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x04, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, - 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, - 0x12, 0x19, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x42, 0x09, 0x5a, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xeb, 0x01, 0x0a, 0x11, 0x45, + 0x74, 0x68, 0x31, 0x45, 0x52, 0x43, 0x37, 0x32, 0x31, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, + 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, + 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, + 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x19, 0x0a, + 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x22, 0x9e, 0x02, 0x0a, 0x12, 0x45, 0x54, 0x68, + 0x31, 0x45, 0x52, 0x43, 0x31, 0x31, 0x35, 0x35, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x12, + 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, + 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x19, 0x0a, 0x08, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2a, 0x32, 0x0a, 0x0a, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, + 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x41, 0x52, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x02, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } @@ -2246,48 +2330,51 @@ func file_eth1_proto_rawDescGZIP() []byte { return file_eth1_proto_rawDescData } +var file_eth1_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_eth1_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_eth1_proto_goTypes = []interface{}{ - (*Eth1Block)(nil), // 0: types.Eth1Block - (*Eth1Withdrawal)(nil), // 1: types.Eth1Withdrawal - (*Eth1Transaction)(nil), // 2: types.Eth1Transaction - (*IsContractUpdate)(nil), // 3: types.IsContractUpdate - (*AccessList)(nil), // 4: types.AccessList - (*Eth1Log)(nil), // 5: types.Eth1Log - (*Eth1InternalTransaction)(nil), // 6: types.Eth1InternalTransaction - (*Eth1BlockIndexed)(nil), // 7: types.Eth1BlockIndexed - (*Eth1UncleIndexed)(nil), // 8: types.Eth1UncleIndexed - (*Eth1WithdrawalIndexed)(nil), // 9: types.Eth1WithdrawalIndexed - (*Eth1TransactionIndexed)(nil), // 10: types.Eth1TransactionIndexed - (*Eth1InternalTransactionIndexed)(nil), // 11: types.Eth1InternalTransactionIndexed - (*Eth1BlobTransactionIndexed)(nil), // 12: types.Eth1BlobTransactionIndexed - (*Eth1ERC20Indexed)(nil), // 13: types.Eth1ERC20Indexed - (*Eth1ERC721Indexed)(nil), // 14: types.Eth1ERC721Indexed - (*ETh1ERC1155Indexed)(nil), // 15: types.ETh1ERC1155Indexed - (*timestamp.Timestamp)(nil), // 16: google.protobuf.Timestamp + (StatusType)(0), // 0: types.StatusType + (*Eth1Block)(nil), // 1: types.Eth1Block + (*Eth1Withdrawal)(nil), // 2: types.Eth1Withdrawal + (*Eth1Transaction)(nil), // 3: types.Eth1Transaction + (*IsContractUpdate)(nil), // 4: types.IsContractUpdate + (*AccessList)(nil), // 5: types.AccessList + (*Eth1Log)(nil), // 6: types.Eth1Log + (*Eth1InternalTransaction)(nil), // 7: types.Eth1InternalTransaction + (*Eth1BlockIndexed)(nil), // 8: types.Eth1BlockIndexed + (*Eth1UncleIndexed)(nil), // 9: types.Eth1UncleIndexed + (*Eth1WithdrawalIndexed)(nil), // 10: types.Eth1WithdrawalIndexed + (*Eth1TransactionIndexed)(nil), // 11: types.Eth1TransactionIndexed + (*Eth1InternalTransactionIndexed)(nil), // 12: types.Eth1InternalTransactionIndexed + (*Eth1BlobTransactionIndexed)(nil), // 13: types.Eth1BlobTransactionIndexed + (*Eth1ERC20Indexed)(nil), // 14: types.Eth1ERC20Indexed + (*Eth1ERC721Indexed)(nil), // 15: types.Eth1ERC721Indexed + (*ETh1ERC1155Indexed)(nil), // 16: types.ETh1ERC1155Indexed + (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp } var file_eth1_proto_depIdxs = []int32{ - 16, // 0: types.Eth1Block.time:type_name -> google.protobuf.Timestamp - 0, // 1: types.Eth1Block.uncles:type_name -> types.Eth1Block - 2, // 2: types.Eth1Block.transactions:type_name -> types.Eth1Transaction - 1, // 3: types.Eth1Block.withdrawals:type_name -> types.Eth1Withdrawal - 4, // 4: types.Eth1Transaction.access_list:type_name -> types.AccessList - 5, // 5: types.Eth1Transaction.logs:type_name -> types.Eth1Log - 6, // 6: types.Eth1Transaction.itx:type_name -> types.Eth1InternalTransaction - 16, // 7: types.Eth1BlockIndexed.time:type_name -> google.protobuf.Timestamp - 16, // 8: types.Eth1UncleIndexed.time:type_name -> google.protobuf.Timestamp - 16, // 9: types.Eth1WithdrawalIndexed.time:type_name -> google.protobuf.Timestamp - 16, // 10: types.Eth1TransactionIndexed.time:type_name -> google.protobuf.Timestamp - 16, // 11: types.Eth1InternalTransactionIndexed.time:type_name -> google.protobuf.Timestamp - 16, // 12: types.Eth1BlobTransactionIndexed.time:type_name -> google.protobuf.Timestamp - 16, // 13: types.Eth1ERC20Indexed.time:type_name -> google.protobuf.Timestamp - 16, // 14: types.Eth1ERC721Indexed.time:type_name -> google.protobuf.Timestamp - 16, // 15: types.ETh1ERC1155Indexed.time:type_name -> google.protobuf.Timestamp - 16, // [16:16] is the sub-list for method output_type - 16, // [16:16] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 17, // 0: types.Eth1Block.time:type_name -> google.protobuf.Timestamp + 1, // 1: types.Eth1Block.uncles:type_name -> types.Eth1Block + 3, // 2: types.Eth1Block.transactions:type_name -> types.Eth1Transaction + 2, // 3: types.Eth1Block.withdrawals:type_name -> types.Eth1Withdrawal + 5, // 4: types.Eth1Transaction.access_list:type_name -> types.AccessList + 6, // 5: types.Eth1Transaction.logs:type_name -> types.Eth1Log + 7, // 6: types.Eth1Transaction.itx:type_name -> types.Eth1InternalTransaction + 17, // 7: types.Eth1BlockIndexed.time:type_name -> google.protobuf.Timestamp + 17, // 8: types.Eth1UncleIndexed.time:type_name -> google.protobuf.Timestamp + 17, // 9: types.Eth1WithdrawalIndexed.time:type_name -> google.protobuf.Timestamp + 17, // 10: types.Eth1TransactionIndexed.time:type_name -> google.protobuf.Timestamp + 0, // 11: types.Eth1TransactionIndexed.status:type_name -> types.StatusType + 17, // 12: types.Eth1InternalTransactionIndexed.time:type_name -> google.protobuf.Timestamp + 17, // 13: types.Eth1BlobTransactionIndexed.time:type_name -> google.protobuf.Timestamp + 17, // 14: types.Eth1ERC20Indexed.time:type_name -> google.protobuf.Timestamp + 17, // 15: types.Eth1ERC721Indexed.time:type_name -> google.protobuf.Timestamp + 17, // 16: types.ETh1ERC1155Indexed.time:type_name -> google.protobuf.Timestamp + 17, // [17:17] is the sub-list for method output_type + 17, // [17:17] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_eth1_proto_init() } @@ -2494,13 +2581,14 @@ func file_eth1_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_eth1_proto_rawDesc, - NumEnums: 0, + NumEnums: 1, NumMessages: 16, NumExtensions: 0, NumServices: 0, }, GoTypes: file_eth1_proto_goTypes, DependencyIndexes: file_eth1_proto_depIdxs, + EnumInfos: file_eth1_proto_enumTypes, MessageInfos: file_eth1_proto_msgTypes, }.Build() File_eth1_proto = out.File diff --git a/backend/pkg/commons/types/eth1.proto b/backend/pkg/commons/types/eth1.proto index c6782edfc..c1a7ff9ad 100644 --- a/backend/pkg/commons/types/eth1.proto +++ b/backend/pkg/commons/types/eth1.proto @@ -64,7 +64,9 @@ message Eth1Transaction { uint64 gas_used = 19; bytes logs_bloom = 20; uint64 status = 21; + //reserved 22; // string error_msg = 22; string error_msg = 22; + repeated Eth1Log logs = 23; // Internal transactions @@ -78,6 +80,11 @@ message Eth1Transaction { uint64 blob_gas_used = 28; } +message IsContractUpdate { + bool is_contract = 1; + bool success = 2; +} + message AccessList { bytes address = 1; repeated bytes storage_keys = 2; @@ -150,6 +157,12 @@ message Eth1WithdrawalIndexed { google.protobuf.Timestamp time = 6; } +enum StatusType { + FAILED = 0; + SUCCESS = 1; + PARTIAL = 2; +} + message Eth1TransactionIndexed { bytes hash = 1; uint64 block_number = 2; @@ -161,12 +174,15 @@ message Eth1TransactionIndexed { bytes tx_fee = 8; bytes gas_price = 9; bool is_contract_creation = 10; +// reserved 11; // bool invokes_contract = 11; bool invokes_contract = 11; string error_msg = 12; // EIP 4844 bytes blob_tx_fee = 13; bytes blob_gas_price = 14; + + StatusType status = 15; } message Eth1InternalTransactionIndexed { @@ -177,6 +193,7 @@ message Eth1InternalTransactionIndexed { bytes from = 5; bytes to = 6; bytes value = 7; + bool reverted = 8; } // https://eips.ethereum.org/EIPS/eip-4844 diff --git a/backend/pkg/commons/types/geth/types.go b/backend/pkg/commons/types/geth/types.go new file mode 100644 index 000000000..e61878991 --- /dev/null +++ b/backend/pkg/commons/types/geth/types.go @@ -0,0 +1,26 @@ +package geth + +import ( + "github.com/ethereum/go-ethereum/common" +) + +type Trace struct { + TxHash string + Result *TraceCall +} + +type TraceCall struct { + TransactionPosition int // todo use something else, that field is not provided by geth, it's manually inserted + Time string + GasUsed string + From common.Address + To common.Address + Value string + Gas string + Input string + Output string + Error string + RevertReason string // todo have a look at this, it could improve revert message + Type string + Calls []*TraceCall +}