diff --git a/packages/bridge-ui-v2/src/components/Activities/MobileDetailsDialog.svelte b/packages/bridge-ui-v2/src/components/Activities/MobileDetailsDialog.svelte index 55b467db2c5..6077e555914 100644 --- a/packages/bridge-ui-v2/src/components/Activities/MobileDetailsDialog.svelte +++ b/packages/bridge-ui-v2/src/components/Activities/MobileDetailsDialog.svelte @@ -11,18 +11,25 @@ import ChainSymbolName from './ChainSymbolName.svelte'; import Status from './Status.svelte'; + import StatusInfoDialog from './StatusInfoDialog.svelte'; export let closeDetails = noop; export let detailsOpen = false; export let selectedItem: BridgeTransaction | null; + let openStatusDialog = false; + let tooltipOpen = false; const openToolTip = (event: Event) => { event.stopPropagation(); tooltipOpen = !tooltipOpen; }; let dialogId = `dialog-${uid()}`; + + const handleStatusDialog = () => { + openStatusDialog = !openStatusDialog; + }; @@ -54,7 +61,9 @@ - TODO: add description about status here +
@@ -77,3 +86,5 @@
+ + diff --git a/packages/bridge-ui-v2/src/components/Activities/StatusInfoDialog.svelte b/packages/bridge-ui-v2/src/components/Activities/StatusInfoDialog.svelte index 969734705ad..3a1af6a844d 100644 --- a/packages/bridge-ui-v2/src/components/Activities/StatusInfoDialog.svelte +++ b/packages/bridge-ui-v2/src/components/Activities/StatusInfoDialog.svelte @@ -4,8 +4,11 @@ import { Icon } from '$components/Icon'; import { uid } from '$libs/util/uid'; - let dialogId = `dialog-${uid()}`; - let modalOpen = false; + export let modalOpen = false; + + export let noIcon = false; + + const dialogId = `dialog-${uid()}`; const closeModal = () => (modalOpen = false); @@ -34,7 +37,9 @@ on:click={openModal} on:focus={openModal} class=" ml-[4px]"> - + {#if !noIcon} + + {/if} diff --git a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte index c95249dabc5..99b23917b58 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte @@ -258,13 +258,13 @@ bridgeTxService.addTxByAddress($account.address, bridgeTx); - // Reset the form - amountComponent.clearAmount(); - recipientComponent.clearRecipient(); - processingFeeComponent.resetProcessingFee(); + // Reset the form (we check if these are still mounted, as the user might have left the page) + if (amountComponent) amountComponent.clearAmount(); + if (recipientComponent) recipientComponent.clearRecipient(); + if (processingFeeComponent) processingFeeComponent.resetProcessingFee(); // Update balance after bridging - amountComponent.updateBalance(); + if (amountComponent) amountComponent.updateBalance(); // Refresh user's balance refreshUserBalance(); diff --git a/packages/bridge-ui-v2/src/components/Bridge/ChainSelectorWrapper.svelte b/packages/bridge-ui-v2/src/components/Bridge/ChainSelectorWrapper.svelte index e92be3c7a79..4354e8b006b 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/ChainSelectorWrapper.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/ChainSelectorWrapper.svelte @@ -1,5 +1,6 @@ diff --git a/packages/bridge-ui-v2/src/components/TokenDropdown/DropdownView.svelte b/packages/bridge-ui-v2/src/components/TokenDropdown/DropdownView.svelte index 79c13ca570f..eb20ddc6521 100644 --- a/packages/bridge-ui-v2/src/components/TokenDropdown/DropdownView.svelte +++ b/packages/bridge-ui-v2/src/components/TokenDropdown/DropdownView.svelte @@ -60,39 +60,39 @@
    - {#each tokens as token (token.symbol)} + {#each tokens as t (t.symbol)}
  • selectToken(token)} - on:keydown={getTokenKeydownHandler(token)}> + aria-selected={t === value} + on:click={() => selectToken(t)} + on:keydown={getTokenKeydownHandler(t)}>
    - {#if symbolToIconMap[token.symbol]} - - + {#if symbolToIconMap[t.symbol]} + + {:else} - + {/if} - {token.symbol} + {t.symbol}
  • {/each} - {#each customTokens as token, index (index)} + {#each customTokens as ct, index (index)}
  • selectToken(token)} - on:keydown={getTokenKeydownHandler(token)}> + aria-selected={ct === value} + on:click={() => selectToken(ct)} + on:keydown={getTokenKeydownHandler(ct)}>
    - + - {token.symbol} + {ct.symbol}
  • {/each} @@ -105,7 +105,6 @@ body-bold bg-transparent flex-1 - px-0"> {$t('token_dropdown.add_custom')} diff --git a/packages/bridge-ui-v2/src/libs/relayer/RelayerAPIService.test.ts b/packages/bridge-ui-v2/src/libs/relayer/RelayerAPIService.test.ts new file mode 100644 index 00000000000..8ec8e3170d0 --- /dev/null +++ b/packages/bridge-ui-v2/src/libs/relayer/RelayerAPIService.test.ts @@ -0,0 +1,88 @@ +import axios from 'axios'; +import type { Address } from 'viem'; + +import { RelayerAPIService } from './RelayerAPIService'; + +vi.mock('axios'); + +function setupMocks() { + vi.mock('$customToken', () => { + return { + customToken: [ + { + name: 'Bull Token', + addresses: { + '31336': '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0', + '167002': '0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE', + }, + symbol: 'BLL', + decimals: 18, + type: 'ERC20', + logoURI: 'ipfs://QmezMTpT6ovJ3szb3SKDM9GVGeQ1R8DfjYyXG12ppMe2BY', + mintable: true, + }, + { + name: 'Horse Token', + addresses: { + '31336': '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e', + '167002': '0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1', + }, + symbol: 'HORSE', + decimals: 18, + type: 'ERC20', + logoURI: 'ipfs://QmU52ZxmSiGX24uDPNUGG3URyZr5aQdLpACCiD6tap4Mgc', + mintable: true, + }, + ], + }; + }); +} + +describe('RelayerAPIService', () => { + beforeEach(() => { + setupMocks(); + }); + + // Given + const mockedAxios = vi.mocked(axios, true); + + test('getTransactionsFromAPI should return API response', async () => { + // Given + const baseUrl = 'http://example.com'; + const relayerAPIService = new RelayerAPIService(baseUrl); + const params = { address: '0x123' as Address, chainID: 1, event: 'MessageSent' }; + const mockResponse = { + data: { + page: 1, + size: 10, + total: 100, + items: [], + }, + status: 200, + }; + mockedAxios.get.mockResolvedValue(mockResponse); + + // When + const result = await relayerAPIService.getTransactionsFromAPI(params); + + // Then + expect(result).toEqual(mockResponse.data); + }); + + test('getAllBridgeTransactionByAddress should return filtered transactions', async () => { + // Given + const baseUrl = 'http://example.com'; + const relayerAPIService = new RelayerAPIService(baseUrl); + const address = '0x123'; + const paginationParams = { page: 1, size: 10 }; + const chainID = 1; + + // When + const result = await relayerAPIService.getAllBridgeTransactionByAddress(address, paginationParams, chainID); + + // Then + expect(result).toBeDefined(); + expect(result.txs).toBeInstanceOf(Array); + expect(result.paginationInfo).toBeDefined(); + }); +}); diff --git a/packages/bridge-ui-v2/src/libs/storage/CustomTokenService.test.ts b/packages/bridge-ui-v2/src/libs/storage/CustomTokenService.test.ts index 6430e83549c..572fe821b42 100644 --- a/packages/bridge-ui-v2/src/libs/storage/CustomTokenService.test.ts +++ b/packages/bridge-ui-v2/src/libs/storage/CustomTokenService.test.ts @@ -1,5 +1,5 @@ import { type Address, zeroAddress } from 'viem'; -import { describe, expect, test, vi } from 'vitest'; +import { describe, expect, vi } from 'vitest'; import { type Token, TokenType } from '$libs/token'; @@ -7,6 +7,39 @@ import { CustomTokenService } from './CustomTokenService'; const STORAGE_PREFIX = 'custom-tokens'; +function setupMocks() { + vi.mock('$customToken', () => { + return { + customToken: [ + { + name: 'Bull Token', + addresses: { + '31336': '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0', + '167002': '0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE', + }, + symbol: 'BLL', + decimals: 18, + type: 'ERC20', + logoURI: 'ipfs://QmezMTpT6ovJ3szb3SKDM9GVGeQ1R8DfjYyXG12ppMe2BY', + mintable: true, + }, + { + name: 'Horse Token', + addresses: { + '31336': '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e', + '167002': '0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1', + }, + symbol: 'HORSE', + decimals: 18, + type: 'ERC20', + logoURI: 'ipfs://QmU52ZxmSiGX24uDPNUGG3URyZr5aQdLpACCiD6tap4Mgc', + mintable: true, + }, + ], + }; + }); +} + describe('CustomTokenService', () => { const localStorage = global.localStorage; let token1: Token; @@ -20,6 +53,8 @@ describe('CustomTokenService', () => { const removeItemSpy = vi.spyOn(Storage.prototype, 'removeItem'); beforeEach(() => { + setupMocks(); + tokenService = new CustomTokenService(localStorage); address = '0x1234'; storageKey = STORAGE_PREFIX + '-' + address; diff --git a/packages/bridge-ui-v2/src/libs/token/getBalance.test.ts b/packages/bridge-ui-v2/src/libs/token/getBalance.test.ts index 3fdd8e91e19..6a17133be05 100644 --- a/packages/bridge-ui-v2/src/libs/token/getBalance.test.ts +++ b/packages/bridge-ui-v2/src/libs/token/getBalance.test.ts @@ -85,6 +85,7 @@ describe('getBalance', () => { }); expect(fetchBalance).toHaveBeenCalledWith({ address: mockWalletClient.account.address, + chainId: Number(PUBLIC_L1_CHAIN_ID), token: BLLToken.addresses[PUBLIC_L1_CHAIN_ID], }); }); diff --git a/packages/bridge-ui-v2/src/libs/token/getBalance.ts b/packages/bridge-ui-v2/src/libs/token/getBalance.ts index 1c26c9f93df..a4710f8c79f 100644 --- a/packages/bridge-ui-v2/src/libs/token/getBalance.ts +++ b/packages/bridge-ui-v2/src/libs/token/getBalance.ts @@ -31,11 +31,10 @@ export async function getBalance({ userAddress, token, srcChainId, destChainId } if (!tokenAddress || tokenAddress === zeroAddress) return; - // Wagmi is such an amazing library. We had to do this - // more manually before. tokenBalance = await fetchBalance({ address: userAddress, token: tokenAddress, + chainId: srcChainId, }); } diff --git a/packages/bridge-ui-v2/src/libs/token/getCrossChainAddress.test.ts b/packages/bridge-ui-v2/src/libs/token/getCrossChainAddress.test.ts index 61c0df32d2d..0fa73137a19 100644 --- a/packages/bridge-ui-v2/src/libs/token/getCrossChainAddress.test.ts +++ b/packages/bridge-ui-v2/src/libs/token/getCrossChainAddress.test.ts @@ -25,13 +25,17 @@ const mockTokenVaultContract = { }, } as unknown as GetContractResult; -vi.mock('$libs/chain', () => ({ - chainContractsMap: { +vi.mock('$bridgeConfig', () => ({ + routingContractsMap: { 1: { - tokenVaultAddress: '0x00001', + 2: { + erc20VaultAddress: '0x00001', + }, }, 2: { - tokenVaultAddress: '0x00002', + 1: { + erc20VaultAddress: '0x00002', + }, }, }, })); diff --git a/packages/bridge-ui-v2/src/test/libs/util/mergeTransactions.test.ts b/packages/bridge-ui-v2/src/libs/util/mergeTransactions.test.ts similarity index 73% rename from packages/bridge-ui-v2/src/test/libs/util/mergeTransactions.test.ts rename to packages/bridge-ui-v2/src/libs/util/mergeTransactions.test.ts index c21857eff4f..6d6e9125b8a 100644 --- a/packages/bridge-ui-v2/src/test/libs/util/mergeTransactions.test.ts +++ b/packages/bridge-ui-v2/src/libs/util/mergeTransactions.test.ts @@ -1,10 +1,47 @@ import type { Address, Hex } from 'viem'; import { type BridgeTransaction, MessageStatus } from '$libs/bridge'; -import { TokenType } from '$libs/token'; +import type { TokenType } from '$libs/token'; import { mergeAndCaptureOutdatedTransactions } from '$libs/util/mergeTransactions'; +function setupMocks() { + vi.mock('$customToken', () => { + return { + customToken: [ + { + name: 'Bull Token', + addresses: { + '31336': '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0', + '167002': '0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE', + }, + symbol: 'BLL', + decimals: 18, + type: 'ERC20', + logoURI: 'ipfs://QmezMTpT6ovJ3szb3SKDM9GVGeQ1R8DfjYyXG12ppMe2BY', + mintable: true, + }, + { + name: 'Horse Token', + addresses: { + '31336': '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e', + '167002': '0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1', + }, + symbol: 'HORSE', + decimals: 18, + type: 'ERC20', + logoURI: 'ipfs://QmU52ZxmSiGX24uDPNUGG3URyZr5aQdLpACCiD6tap4Mgc', + mintable: true, + }, + ], + }; + }); +} + describe('mergeUniqueTransactions', () => { + beforeEach(() => { + setupMocks(); + }); + // Given const localTxs: BridgeTransaction[] = [ { @@ -18,7 +55,7 @@ describe('mergeUniqueTransactions', () => { status: MessageStatus.DONE, msgHash: 'msg1' as Hex, receipt: undefined, - tokenType: TokenType.ERC20, + tokenType: 'ERC20' as TokenType, }, { hash: 'hash2' as Hex, @@ -31,7 +68,7 @@ describe('mergeUniqueTransactions', () => { status: MessageStatus.DONE, msgHash: 'msg2' as Hex, receipt: undefined, - tokenType: TokenType.ERC20, + tokenType: 'ERC20' as TokenType, }, ]; @@ -47,7 +84,7 @@ describe('mergeUniqueTransactions', () => { status: MessageStatus.DONE, msgHash: 'msg3' as Hex, receipt: undefined, - tokenType: TokenType.ERC20, + tokenType: 'ERC20' as TokenType, }, { hash: 'hash4' as Hex, @@ -60,7 +97,7 @@ describe('mergeUniqueTransactions', () => { status: MessageStatus.DONE, msgHash: 'msg4' as Hex, receipt: undefined, - tokenType: TokenType.ERC20, + tokenType: 'ERC20' as TokenType, }, ]; @@ -102,7 +139,7 @@ describe('mergeUniqueTransactions', () => { status: MessageStatus.DONE, msgHash: 'msg2' as Hex, receipt: undefined, - tokenType: TokenType.ERC20, + tokenType: 'ERC20' as TokenType, }, ]; diff --git a/packages/eventindexer/.l1.env b/packages/eventindexer/.l1.env index e137fc178ce..1a0131b7af8 100644 --- a/packages/eventindexer/.l1.env +++ b/packages/eventindexer/.l1.env @@ -13,4 +13,5 @@ RPC_URL=wss://l1ws.internal.taiko.xyz CORS_ORIGINS=* BLOCK_BATCH_SIZE=10 CACHE_INTERVAL_IN_SECONDS=60 -LAYER=l1 \ No newline at end of file +LAYER=l1 +GENESIS_DATE=2023-09-08 \ No newline at end of file diff --git a/packages/eventindexer/cmd/flags/generator.go b/packages/eventindexer/cmd/flags/generator.go index b9388df43ac..9c53b437f50 100644 --- a/packages/eventindexer/cmd/flags/generator.go +++ b/packages/eventindexer/cmd/flags/generator.go @@ -10,7 +10,15 @@ var ( Category: generatorCategory, EnvVars: []string{"GENESIS_DATE"}, } + Regenerate = &cli.StringFlag{ + Name: "regenerate", + Usage: "True to delete all existing data and regenerate from genesis, false to not", + Required: false, + Category: generatorCategory, + EnvVars: []string{"REGENERATE"}, + } ) var GeneratorFlags = MergeFlags(CommonFlags, []cli.Flag{ GenesisDate, + Regenerate, }) diff --git a/packages/eventindexer/cmd/flags/indexer.go b/packages/eventindexer/cmd/flags/indexer.go index 3b19820b05b..37c845599bf 100644 --- a/packages/eventindexer/cmd/flags/indexer.go +++ b/packages/eventindexer/cmd/flags/indexer.go @@ -121,6 +121,7 @@ var ( var IndexerFlags = MergeFlags(CommonFlags, []cli.Flag{ RPCUrl, // optional + ETHClientTimeout, L1TaikoAddress, HTTPPort, MetricsHTTPPort, diff --git a/packages/eventindexer/db/db.go b/packages/eventindexer/db/db.go index 9223263b3cb..3b865643fb7 100644 --- a/packages/eventindexer/db/db.go +++ b/packages/eventindexer/db/db.go @@ -46,14 +46,14 @@ func OpenDBConnection(opts DBConnectionOpts) (*DB, error) { dsn := "" if opts.Password == "" { dsn = fmt.Sprintf( - "%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", + "%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True", opts.Name, opts.Host, opts.Database, ) } else { dsn = fmt.Sprintf( - "%v:%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", + "%v:%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True", opts.Name, opts.Password, opts.Host, diff --git a/packages/eventindexer/event.go b/packages/eventindexer/event.go index 288801324ac..8fd589ae4b0 100644 --- a/packages/eventindexer/event.go +++ b/packages/eventindexer/event.go @@ -34,6 +34,8 @@ type Event struct { Address string `json:"address"` BlockID sql.NullInt64 `json:"blockID"` Amount decimal.NullDecimal `json:"amount"` + ProofReward decimal.NullDecimal `json:"proofReward"` + ProposerReward decimal.NullDecimal `json:"proposerReward"` AssignedProver string `json:"assignedProver"` To string `json:"to"` TokenID sql.NullInt64 `json:"tokenID"` @@ -50,6 +52,8 @@ type SaveEventOpts struct { Address string BlockID *int64 Amount *big.Int + ProposerReward *big.Int + ProofReward *big.Int AssignedProver *string To *string TokenID *int64 diff --git a/packages/eventindexer/generator/config.go b/packages/eventindexer/generator/config.go index 1cf9ec83675..378b03c24c0 100644 --- a/packages/eventindexer/generator/config.go +++ b/packages/eventindexer/generator/config.go @@ -28,6 +28,7 @@ type Config struct { DatabaseMaxConnLifetime uint64 MetricsHTTPPort uint64 GenesisDate time.Time + Regenerate bool OpenDBFunc func() (DB, error) } @@ -48,6 +49,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { DatabaseMaxConnLifetime: c.Uint64(flags.DatabaseConnMaxLifetime.Name), MetricsHTTPPort: c.Uint64(flags.MetricsHTTPPort.Name), GenesisDate: date, + Regenerate: c.Bool(flags.Regenerate.Name), OpenDBFunc: func() (DB, error) { return db.OpenDBConnection(db.DBConnectionOpts{ Name: c.String(flags.DatabaseUsername.Name), diff --git a/packages/eventindexer/generator/config_test.go b/packages/eventindexer/generator/config_test.go index 2731d49fb0f..f38f1ed1205 100644 --- a/packages/eventindexer/generator/config_test.go +++ b/packages/eventindexer/generator/config_test.go @@ -32,6 +32,7 @@ func TestNewConfigFromCliContext(t *testing.T) { assert.Equal(t, "dbpass", c.DatabasePassword) assert.Equal(t, "dbname", c.DatabaseName) assert.Equal(t, "dbhost", c.DatabaseHost) + assert.Equal(t, true, c.Regenerate) wantTime, _ := time.Parse("2006-01-02", "2023-07-07") assert.Equal(t, wantTime, c.GenesisDate) @@ -52,5 +53,6 @@ func TestNewConfigFromCliContext(t *testing.T) { "-" + flags.DatabaseHost.Name, "dbhost", "-" + flags.DatabaseName.Name, "dbname", "-" + flags.GenesisDate.Name, "2023-07-07", + "-" + flags.Regenerate.Name, "true", })) } diff --git a/packages/eventindexer/generator/generator.go b/packages/eventindexer/generator/generator.go index 0b933732148..b60228f9b4c 100644 --- a/packages/eventindexer/generator/generator.go +++ b/packages/eventindexer/generator/generator.go @@ -4,11 +4,10 @@ import ( "context" "errors" "log/slog" - "strconv" - "syscall" "time" "github.com/ethereum/go-ethereum/common" + "github.com/shopspring/decimal" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/tasks" "github.com/urfave/cli/v2" @@ -24,6 +23,7 @@ var ( type Generator struct { db DB genesisDate time.Time + regenerate bool } func (g *Generator) InitFromCli(ctx context.Context, c *cli.Context) error { @@ -43,6 +43,7 @@ func InitFromConfig(ctx context.Context, g *Generator, cfg *Config) error { g.db = db g.genesisDate = cfg.GenesisDate + g.regenerate = cfg.Regenerate return nil } @@ -52,13 +53,17 @@ func (g *Generator) Name() string { } func (g *Generator) Start() error { - slog.Info("generating time series data") + if g.regenerate { + slog.Info("regenerating, deleting existing data") - if err := g.generateTimeSeriesData(context.Background()); err != nil { - return err + if err := g.deleteTimeSeriesData(context.Background()); err != nil { + return err + } } - if err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM); err != nil { + slog.Info("generating time series data") + + if err := g.generateTimeSeriesData(context.Background()); err != nil { return err } @@ -76,6 +81,15 @@ func (g *Generator) Close(ctx context.Context) { } } +func (g *Generator) deleteTimeSeriesData(ctx context.Context) error { + deleteStmt := "DELETE FROM time_series_data;" + if err := g.db.GormDB().Exec(deleteStmt).Error; err != nil { + return err + } + + return nil +} + // generateTimeSeriesData iterates over each task and generates time series data. func (g *Generator) generateTimeSeriesData(ctx context.Context) error { for _, task := range tasks.Tasks { @@ -93,19 +107,25 @@ func (g *Generator) generateTimeSeriesData(ctx context.Context) error { func (g *Generator) generateByTask(ctx context.Context, task string) error { slog.Info("generating for task", "task", task) - latestDate, err := g.getLatestDateByTask(ctx, task) + startingDate, err := g.getStartingDateByTask(ctx, task) if err != nil { return err } currentDate := g.getCurrentDate() - if latestDate.AddDate(0, 0, 1).Compare(currentDate) == 0 { - slog.Info("data already generated up-to-date for task", "task", task, "date", latestDate.Format("2006-01-02")) + if startingDate.Compare(currentDate) == 0 { + slog.Info( + "data already generated up-to-date for task", + "task", task, + "date", startingDate.Format("2006-01-02"), + "currentDate", currentDate.Format("2006-01-02"), + ) + return nil } // Loop through each date from latestDate to currentDate - for d := latestDate; d.Before(currentDate); d = d.AddDate(0, 0, 1) { + for d := startingDate; d.Before(currentDate); d = d.AddDate(0, 0, 1) { slog.Info("Processing", "task", task, "date", d.Format("2006-01-02"), "currentDate", currentDate.Format("2006-01-02")) result, err := g.queryByTask(task, d) @@ -114,7 +134,7 @@ func (g *Generator) generateByTask(ctx context.Context, task string) error { return err } - slog.Info("Query successful", "task", task, "date", d.Format("2006-01-02"), "result", result) + slog.Info("Query successful", "task", task, "date", d.Format("2006-01-02"), "result", result.String()) insertStmt := ` INSERT INTO time_series_data(task, value, date) @@ -132,12 +152,12 @@ func (g *Generator) generateByTask(ctx context.Context, task string) error { return nil } -// getLatestDateByTask returns the last time time series data has been generated -// for the given task. -func (g *Generator) getLatestDateByTask(ctx context.Context, task string) (time.Time, error) { +// getStartingDateByTask returns first required time series data, one after the latest date entry, +// or the genesis date. +func (g *Generator) getStartingDateByTask(ctx context.Context, task string) (time.Time, error) { var latestDateString string - var latestDate time.Time + var nextRequiredDate time.Time q := `SELECT date FROM time_series_data WHERE task = ? ORDER BY date DESC LIMIT 1;` @@ -146,178 +166,207 @@ func (g *Generator) getLatestDateByTask(ctx context.Context, task string) (time. slog.Info("latestDateString", "task", task, "date", latestDateString) if err != nil || latestDateString == "" { - latestDate = g.genesisDate + nextRequiredDate = g.genesisDate } else { - latestDate, err = time.Parse("2006-01-02", latestDateString) - } + latestDate, err := time.Parse("2006-01-02", latestDateString) + if err != nil { + return time.Time{}, err + } - if err != nil { - return time.Time{}, err + nextRequiredDate = latestDate.AddDate(0, 0, 1) } - slog.Info("latest date for task", "task", task, "latestDate", latestDate.Format("2006-01-02")) + slog.Info("next required date for task", "task", task, "nextRequiredDate", nextRequiredDate.Format("2006-01-02")) - return latestDate, nil + return nextRequiredDate, nil } // getCurrentDate returns the current date in YYYY-MM-DD format func (g *Generator) getCurrentDate() time.Time { // Get current date - currentTime := time.Now() + currentTime := time.Now().UTC() currentDate := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, time.UTC) return currentDate } -// nolint: funlen +// nolint: funlen, gocognit // queryByTask runs a database query which should return result data based on the // task -func (g *Generator) queryByTask(task string, date time.Time) (string, error) { +func (g *Generator) queryByTask(task string, date time.Time) (decimal.Decimal, error) { dateString := date.Format("2006-01-02") - var result string + var result decimal.Decimal var err error switch task { + case tasks.ProposerRewardsPerDay: + query := "SELECT COALESCE(SUM(proposer_reward), 0) FROM events WHERE event = ? AND DATE(transacted_at) = ?" + err = g.db.GormDB(). + Raw(query, eventindexer.EventNameBlockProposed, dateString). + Scan(&result).Error + + case tasks.TotalProposerRewards: + var dailyProposerRewards decimal.NullDecimal + + query := "SELECT COALESCE(SUM(proposer_reward), 0) FROM events WHERE event = ? AND DATE(transacted_at) = ?" + err = g.db.GormDB(). + Raw(query, eventindexer.EventNameBlockProposed, dateString). + Scan(&dailyProposerRewards).Error + + tsdResult, err := g.previousDayTsdResultByTask(task, date) + if err != nil { + return result, err + } + + result = tsdResult.Decimal.Add(dailyProposerRewards.Decimal) + + case tasks.TotalProofRewards: + var dailyProofRewards decimal.NullDecimal + + query := "SELECT COALESCE(SUM(proof_reward), 0) FROM events WHERE event = ? AND DATE(transacted_at) = ?" + err = g.db.GormDB(). + Raw(query, eventindexer.EventNameBlockProposed, dateString). + Scan(&dailyProofRewards).Error + + tsdResult, err := g.previousDayTsdResultByTask(task, date) + if err != nil { + return result, err + } + + result = tsdResult.Decimal.Add(dailyProofRewards.Decimal) + case tasks.ProofRewardsPerDay: + query := "SELECT COALESCE(SUM(proof_reward), 0) FROM events WHERE event = ? AND DATE(transacted_at) = ?" + err = g.db.GormDB(). + Raw(query, eventindexer.EventNameBlockProposed, dateString). + Scan(&result).Error case tasks.BridgeMessagesSentPerDay: err = g.eventCount(task, date, eventindexer.EventNameMessageSent, &result) case tasks.TotalBridgeMessagesSent: - var dailyMsgSentCount int + var dailyMsgSentCount decimal.NullDecimal err = g.eventCount(task, date, eventindexer.EventNameMessageSent, &dailyMsgSentCount) if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyMsgSentCount + tsdResult) + result = tsdResult.Decimal.Add(dailyMsgSentCount.Decimal) case tasks.ProposeBlockTxPerDay: err = g.eventCount(task, date, eventindexer.EventNameBlockProposed, &result) case tasks.TotalProposeBlockTx: - var dailyProposerCount int + var dailyProposerCount decimal.NullDecimal err = g.eventCount(task, date, eventindexer.EventNameBlockProposed, &dailyProposerCount) if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyProposerCount + tsdResult) + result = tsdResult.Decimal.Add(dailyProposerCount.Decimal) case tasks.UniqueProposersPerDay: query := "SELECT COUNT(DISTINCT address) FROM events WHERE event = ? AND DATE(transacted_at) = ?" err = g.db.GormDB(). - Raw(query, eventindexer.EventNameBlockProposed, date). + Raw(query, eventindexer.EventNameBlockProposed, dateString). Scan(&result).Error case tasks.TotalUniqueProposers: - var dailyProposerCount int - - query := `SELECT COUNT(DISTINCT address) FROM events WHERE event = ? AND DATE(transacted_at) = ?` + query := `SELECT COUNT(DISTINCT address) FROM events WHERE event = ?` - err = g.db.GormDB().Raw(query, eventindexer.EventNameBlockProposed, dateString).Scan(&dailyProposerCount).Error + err = g.db.GormDB().Raw( + query, + eventindexer.EventNameBlockProposed, + ).Scan(&result).Error if err != nil { - return "", err + return result, err } - - tsdResult, err := g.previousDayTsdResultByTask(task, date) - if err != nil { - return "", err - } - - result = strconv.Itoa(dailyProposerCount + tsdResult) case tasks.UniqueProversPerDay: query := "SELECT COUNT(DISTINCT address) FROM events WHERE event = ? AND DATE(transacted_at) = ?" err = g.db.GormDB(). - Raw(query, eventindexer.EventNameBlockProven, date). + Raw(query, eventindexer.EventNameBlockProven, dateString). Scan(&result).Error case tasks.TotalUniqueProvers: - var dailyProposerCount int - - query := `SELECT COUNT(DISTINCT address) FROM events WHERE event = ? AND DATE(transacted_at) = ?` + query := `SELECT COUNT(DISTINCT address) FROM events WHERE event = ?` - err = g.db.GormDB().Raw(query, eventindexer.EventNameBlockProven, dateString).Scan(&dailyProposerCount).Error + err = g.db.GormDB().Raw( + query, + eventindexer.EventNameBlockProven, + ).Scan(&result).Error if err != nil { - return "", err + return result, err } - - tsdResult, err := g.previousDayTsdResultByTask(task, date) - if err != nil { - return "", err - } - - result = strconv.Itoa(dailyProposerCount + tsdResult) case tasks.ProveBlockTxPerDay: query := "SELECT COUNT(*) FROM events WHERE event = ? AND DATE(transacted_at) = ?" err = g.db.GormDB(). - Raw(query, eventindexer.EventNameBlockProven, date). + Raw(query, eventindexer.EventNameBlockProven, dateString). Scan(&result).Error case tasks.TotalProveBlockTx: - var dailyProposerCount int + var dailyProveBlockCount decimal.NullDecimal query := `SELECT COUNT(*) FROM events WHERE event = ? AND DATE(transacted_at) = ?` - err = g.db.GormDB().Raw(query, eventindexer.EventNameBlockProven, dateString).Scan(&dailyProposerCount).Error + err = g.db.GormDB().Raw(query, eventindexer.EventNameBlockProven, dateString).Scan(&dailyProveBlockCount).Error if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyProposerCount + tsdResult) + result = tsdResult.Decimal.Add(dailyProveBlockCount.Decimal) case tasks.AccountsPerDay: query := `SELECT COUNT(*) FROM accounts WHERE DATE(transacted_at) = ?` err = g.db.GormDB().Raw(query, dateString).Scan(&result).Error case tasks.TotalAccounts: - var dailyAccountsCount int + var dailyAccountsCount decimal.NullDecimal query := `SELECT COUNT(*) FROM accounts WHERE DATE(transacted_at) = ?` err = g.db.GormDB().Raw(query, dateString).Scan(&dailyAccountsCount).Error if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyAccountsCount + tsdResult) + result = tsdResult.Decimal.Add(dailyAccountsCount.Decimal) case tasks.BlocksPerDay: query := `SELECT COUNT(*) FROM blocks WHERE DATE(transacted_at) = ?` err = g.db.GormDB().Raw(query, dateString).Scan(&result).Error case tasks.TotalBlocks: - var dailyBlockCount int + var dailyBlockCount decimal.NullDecimal query := `SELECT COUNT(*) FROM blocks WHERE DATE(transacted_at) = ?` err = g.db.GormDB().Raw(query, dateString).Scan(&dailyBlockCount).Error if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyBlockCount + tsdResult) + result = tsdResult.Decimal.Add(dailyBlockCount.Decimal) case tasks.TransactionsPerDay: query := `SELECT COUNT(*) FROM transactions WHERE DATE(transacted_at) = ?` err = g.db.GormDB().Raw(query, dateString).Scan(&result).Error case tasks.TotalTransactions: - var dailyTxCount int + var dailyTxCount decimal.NullDecimal // get current days txs, get previous entry for the time series data, add them together. @@ -325,41 +374,41 @@ func (g *Generator) queryByTask(task string, date time.Time) (string, error) { err = g.db.GormDB().Raw(query, dateString).Scan(&dailyTxCount).Error if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyTxCount + tsdResult) + result = tsdResult.Decimal.Add(dailyTxCount.Decimal) case tasks.ContractDeploymentsPerDay: query := `SELECT COUNT(*) FROM transactions WHERE DATE(transacted_at) = ? AND contract_address != ?` - err = g.db.GormDB().Raw(query, dateString, ZeroAddress).Scan(&result).Error + err = g.db.GormDB().Raw(query, dateString, ZeroAddress.Hex()).Scan(&result).Error case tasks.TotalContractDeployments: - var dailyContractCount int + var dailyContractCount decimal.NullDecimal // get current days txs, get previous entry for the time series data, add them together. query := `SELECT COUNT(*) FROM transactions WHERE DATE(transacted_at) = ? AND contract_address != ?` - err = g.db.GormDB().Raw(query, dateString, ZeroAddress).Scan(&dailyContractCount).Error + err = g.db.GormDB().Raw(query, dateString, ZeroAddress.Hex()).Scan(&dailyContractCount).Error if err != nil { - return "", err + return result, err } tsdResult, err := g.previousDayTsdResultByTask(task, date) if err != nil { - return "", err + return result, err } - result = strconv.Itoa(dailyContractCount + tsdResult) + result = tsdResult.Decimal.Add(dailyContractCount.Decimal) default: - return "", errors.New("task not supported") + return result, errors.New("task not supported") } if err != nil { - return "", err + return result, err } return result, nil @@ -367,14 +416,21 @@ func (g *Generator) queryByTask(task string, date time.Time) (string, error) { // previousDayTsdResultByTask returns the previous day's time series data, based on // task and time passed in. -func (g *Generator) previousDayTsdResultByTask(task string, date time.Time) (int, error) { - var tsdResult int +func (g *Generator) previousDayTsdResultByTask(task string, date time.Time) (decimal.NullDecimal, error) { + var tsdResult decimal.NullDecimal tsdQuery := `SELECT value FROM time_series_data WHERE task = ? AND date = ?` err := g.db.GormDB().Raw(tsdQuery, task, date.AddDate(0, 0, -1).Format("2006-01-02")).Scan(&tsdResult).Error if err != nil { - return 0, err + return tsdResult, err + } + + if !tsdResult.Valid { + return decimal.NullDecimal{ + Valid: true, + Decimal: decimal.Zero, + }, nil } return tsdResult, nil @@ -386,6 +442,6 @@ func (g *Generator) eventCount(task string, date time.Time, event string, result query := "SELECT COUNT(*) FROM events WHERE event = ? AND DATE(transacted_at) = ?" return g.db.GormDB(). - Raw(query, event, date). + Raw(query, event, date.Format("2006-01-02")). Scan(result).Error } diff --git a/packages/eventindexer/http/get_stats.go b/packages/eventindexer/http/get_stats.go index cbb68858c6d..c66e26a4109 100644 --- a/packages/eventindexer/http/get_stats.go +++ b/packages/eventindexer/http/get_stats.go @@ -2,10 +2,10 @@ package http import ( "net/http" + "time" "github.com/cyberhorsey/webutils" "github.com/labstack/echo/v4" - "github.com/patrickmn/go-cache" "github.com/taikoxyz/taiko-mono/packages/eventindexer" ) @@ -26,7 +26,7 @@ func (srv *Server) GetStats(c echo.Context) error { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - srv.cache.Set(CacheKeyStats, stats, cache.DefaultExpiration) + srv.cache.Set(CacheKeyStats, stats, 1*time.Minute) } return c.JSON(http.StatusOK, stats) diff --git a/packages/eventindexer/http/get_stats_test.go b/packages/eventindexer/http/get_stats_test.go index a4c5c6000fb..9926d1f9a25 100644 --- a/packages/eventindexer/http/get_stats_test.go +++ b/packages/eventindexer/http/get_stats_test.go @@ -37,7 +37,8 @@ func Test_GetStats(t *testing.T) { "success", "0x123", http.StatusOK, - []string{`{"id":1,"averageProofTime":"5","averageProofReward":"7","numProofs":1,"numVerifiedBlocks":1}`}, + // nolint: lll + []string{`{"id":1,"averageProofTime":"5","averageProofReward":"7","averageProposerReward":"","numProposerRewards":0,"numProofs":1,"numVerifiedBlocks":1}`}, }, } diff --git a/packages/eventindexer/indexer/config.go b/packages/eventindexer/indexer/config.go index 10279990797..a46bd5c4afe 100644 --- a/packages/eventindexer/indexer/config.go +++ b/packages/eventindexer/indexer/config.go @@ -36,7 +36,7 @@ type Config struct { SwapAddresses []common.Address CORSOrigins []string BlockBatchSize uint64 - Subscriptionbackoff uint64 + SubscriptionBackoff uint64 SyncMode SyncMode WatchMode WatchMode IndexNFTs bool @@ -78,7 +78,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { SwapAddresses: swaps, CORSOrigins: cors, BlockBatchSize: c.Uint64(flags.BlockBatchSize.Name), - Subscriptionbackoff: c.Uint64(flags.SubscriptionBackoff.Name), + SubscriptionBackoff: c.Uint64(flags.SubscriptionBackoff.Name), RPCUrl: c.String(flags.RPCUrl.Name), WatchMode: WatchMode(c.String(flags.WatchMode.Name)), SyncMode: SyncMode(c.String(flags.SyncMode.Name)), diff --git a/packages/eventindexer/indexer/config_test.go b/packages/eventindexer/indexer/config_test.go index cc59a482030..8513c8a5b41 100644 --- a/packages/eventindexer/indexer/config_test.go +++ b/packages/eventindexer/indexer/config_test.go @@ -10,11 +10,22 @@ import ( ) var ( - httpPort = "1000" - metricsHttpPort = "1001" - l1TaikoAddress = "0x63FaC9201494f0bd17B9892B9fae4d52fe3BD377" - bridgeAddress = "0x73FaC9201494f0bd17B9892B9fae4d52fe3BD377" - swapAddresses = "0x33FaC9201494f0bd17B9892B9fae4d52fe3BD377,0x13FaC9201494f0bd17B9892B9fae4d52fe3BD377" + httpPort = "1000" + metricsHttpPort = "1001" + l1TaikoAddress = "0x63FaC9201494f0bd17B9892B9fae4d52fe3BD377" + bridgeAddress = "0x73FaC9201494f0bd17B9892B9fae4d52fe3BD377" + swapAddresses = "0x33FaC9201494f0bd17B9892B9fae4d52fe3BD377,0x13FaC9201494f0bd17B9892B9fae4d52fe3BD377" + corsOrigins = "http://localhost:3000,http://localhost:3001" + databaseMaxIdleConns = "10" + databaseMaxOpenConns = "10" + databaseMaxConnLifetime = "30" + ethClientTimeout = "30" + blockBatchSize = "100" + subscriptionBackoff = "30" + syncMode = "sync" + watchMode = "filter" + indexNFTs = "true" + layer = "l1" ) func setupApp() *cli.App { @@ -44,6 +55,17 @@ func TestNewConfigFromCliContext(t *testing.T) { assert.Equal(t, uint64(1001), c.MetricsHTTPPort) assert.Equal(t, common.HexToAddress(l1TaikoAddress), c.L1TaikoAddress) assert.Equal(t, common.HexToAddress(bridgeAddress), c.BridgeAddress) + assert.Equal(t, uint64(10), c.DatabaseMaxIdleConns) + assert.Equal(t, uint64(10), c.DatabaseMaxOpenConns) + assert.Equal(t, uint64(30), c.DatabaseMaxConnLifetime) + assert.Equal(t, uint64(30), c.ETHClientTimeout) + assert.Equal(t, uint64(100), c.BlockBatchSize) + assert.Equal(t, uint64(30), c.SubscriptionBackoff) + assert.Equal(t, SyncMode(syncMode), c.SyncMode) + assert.Equal(t, WatchMode(watchMode), c.WatchMode) + assert.Equal(t, true, c.IndexNFTs) + assert.Equal(t, layer, c.Layer) + assert.NotNil(t, c.OpenDBFunc) // assert.Nil(t, InitFromConfig(context.Background(), new(Indexer), c)) @@ -62,5 +84,16 @@ func TestNewConfigFromCliContext(t *testing.T) { "-" + flags.SwapAddresses.Name, swapAddresses, "-" + flags.HTTPPort.Name, httpPort, "-" + flags.MetricsHTTPPort.Name, metricsHttpPort, + "-" + flags.CORSOrigins.Name, corsOrigins, + "-" + flags.DatabaseMaxIdleConns.Name, databaseMaxIdleConns, + "-" + flags.DatabaseMaxOpenConns.Name, databaseMaxOpenConns, + "-" + flags.DatabaseConnMaxLifetime.Name, databaseMaxConnLifetime, + "-" + flags.ETHClientTimeout.Name, ethClientTimeout, + "-" + flags.BlockBatchSize.Name, blockBatchSize, + "-" + flags.SubscriptionBackoff.Name, subscriptionBackoff, + "-" + flags.SyncMode.Name, syncMode, + "-" + flags.WatchMode.Name, watchMode, + "-" + flags.IndexNFTs.Name, indexNFTs, + "-" + flags.Layer.Name, layer, })) } diff --git a/packages/eventindexer/indexer/indexer.go b/packages/eventindexer/indexer/indexer.go index e1e8a53cd69..31d6ca2a6fe 100644 --- a/packages/eventindexer/indexer/indexer.go +++ b/packages/eventindexer/indexer/indexer.go @@ -229,7 +229,7 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) error { i.bridge = bridgeContract i.swaps = swapContracts i.blockBatchSize = cfg.BlockBatchSize - i.subscriptionBackoff = time.Duration(cfg.Subscriptionbackoff) * time.Second + i.subscriptionBackoff = time.Duration(cfg.SubscriptionBackoff) * time.Second i.srv = srv i.httpPort = cfg.HTTPPort i.wg = &sync.WaitGroup{} diff --git a/packages/eventindexer/indexer/save_block_proposed_event.go b/packages/eventindexer/indexer/save_block_proposed_event.go index 6d2c2b027fd..6564efcef1f 100644 --- a/packages/eventindexer/indexer/save_block_proposed_event.go +++ b/packages/eventindexer/indexer/save_block_proposed_event.go @@ -75,6 +75,16 @@ func (indxr *Indexer) saveBlockProposedEvent( return errors.Wrap(err, "indxr.ethClient.BlockByNumber") } + proposerReward, err := indxr.updateAverageProposerReward(ctx, event) + if err != nil { + return errors.Wrap(err, "indxr.updateAverageProposerReward") + } + + proverReward, err := indxr.updateAverageProverReward(ctx, event) + if err != nil { + return errors.Wrap(err, "indxr.updateAverageProposerReward") + } + _, err = indxr.eventRepo.Save(ctx, eventindexer.SaveEventOpts{ Name: eventindexer.EventNameBlockProposed, Data: string(marshaled), @@ -83,7 +93,10 @@ func (indxr *Indexer) saveBlockProposedEvent( Address: sender.Hex(), BlockID: &blockID, AssignedProver: &assignedProver, - TransactedAt: time.Unix(int64(block.Time()), 0), + TransactedAt: time.Unix(int64(block.Time()), 0).UTC(), + Amount: event.Reward, + ProposerReward: proposerReward, + ProofReward: proverReward, }) if err != nil { return errors.Wrap(err, "indxr.eventRepo.Save") @@ -93,3 +106,94 @@ func (indxr *Indexer) saveBlockProposedEvent( return nil } + +func (indxr *Indexer) updateAverageProposerReward( + ctx context.Context, + event *taikol1.TaikoL1BlockProposed, +) (*big.Int, error) { + stat, err := indxr.statRepo.Find(ctx) + if err != nil { + return nil, errors.Wrap(err, "indxr.statRepo.Find") + } + + reward := event.Reward + + avg, ok := new(big.Int).SetString(stat.AverageProposerReward, 10) + if !ok { + return nil, errors.New("unable to convert average proposer to string") + } + + newAverageProposerReward := calcNewAverage( + avg, + new(big.Int).SetUint64(stat.NumProposerRewards), + reward, + ) + + slog.Info("newAverageProposerReward update", + "id", + event.BlockId.Int64(), + "prover", + event.Prover.Hex(), + "avg", + avg.String(), + "newAvg", + newAverageProposerReward.String(), + ) + + _, err = indxr.statRepo.Save(ctx, eventindexer.SaveStatOpts{ + ProposerReward: newAverageProposerReward, + }) + if err != nil { + return nil, errors.Wrap(err, "indxr.statRepo.Save") + } + + return reward, err +} + +func (indxr *Indexer) updateAverageProverReward( + ctx context.Context, + event *taikol1.TaikoL1BlockProposed, +) (*big.Int, error) { + stat, err := indxr.statRepo.Find(ctx) + if err != nil { + return nil, errors.Wrap(err, "indxr.statRepo.Find") + } + + tx, _, err := indxr.ethClient.TransactionByHash(ctx, event.Raw.TxHash) + if err != nil { + return nil, errors.Wrap(err, "indxr.ethClient.TransactionByHash") + } + + reward := tx.Value() + + avg, ok := new(big.Int).SetString(stat.AverageProofReward, 10) + if !ok { + return nil, errors.New("unable to convert average proof time to string") + } + + newAverageProofReward := calcNewAverage( + avg, + new(big.Int).SetUint64(stat.NumProofs), + reward, + ) + + slog.Info("newAverageProofReward update", + "id", + event.BlockId.Int64(), + "prover", + event.Prover.Hex(), + "avg", + avg.String(), + "newAvg", + newAverageProofReward.String(), + ) + + _, err = indxr.statRepo.Save(ctx, eventindexer.SaveStatOpts{ + ProofReward: newAverageProofReward, + }) + if err != nil { + return nil, errors.Wrap(err, "indxr.statRepo.Save") + } + + return reward, nil +} diff --git a/packages/eventindexer/migrations/1666650599_create_events_table.sql b/packages/eventindexer/migrations/1666650599_create_events_table.sql index e5b027fa73c..40fe273e1f1 100644 --- a/packages/eventindexer/migrations/1666650599_create_events_table.sql +++ b/packages/eventindexer/migrations/1666650599_create_events_table.sql @@ -9,6 +9,8 @@ CREATE TABLE IF NOT EXISTS events ( address VARCHAR(42) NOT NULL DEFAULT "", block_id int DEFAULT NULL, amount DECIMAL(65, 0) DEFAULT NULL, + proof_reward VARCHAR(255) DEFAULT NULL, + proposer_reward VARCHAR(255) DEFAULT NULL, assigned_prover VARCHAR(42) NOT NULL DEFAULT "", transacted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP , diff --git a/packages/eventindexer/migrations/1666650701_create_stats_table.sql b/packages/eventindexer/migrations/1666650701_create_stats_table.sql index 9a8ea8a6e93..60bbbeea6fc 100644 --- a/packages/eventindexer/migrations/1666650701_create_stats_table.sql +++ b/packages/eventindexer/migrations/1666650701_create_stats_table.sql @@ -4,6 +4,8 @@ CREATE TABLE IF NOT EXISTS stats ( id int NOT NULL PRIMARY KEY AUTO_INCREMENT, average_proof_time VARCHAR(255) NOT NULL DEFAULT "0", average_proof_reward VARCHAR(255) NOT NULL DEFAULT "0", + average_proposer_reward VARCHAR(255) NOT NULL DEFAULT "0", + num_proposer_rewards int NOT NULL default 0, num_proofs int NOT NULL default 0, num_verified_blocks int NOT NULL default 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP , diff --git a/packages/eventindexer/migrations/20230906203931_create_time_series_data_table.sql b/packages/eventindexer/migrations/20230906203931_create_time_series_data_table.sql index 64bd23e013e..b41b7cf0bcc 100644 --- a/packages/eventindexer/migrations/20230906203931_create_time_series_data_table.sql +++ b/packages/eventindexer/migrations/20230906203931_create_time_series_data_table.sql @@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS time_series_data ( id int NOT NULL PRIMARY KEY AUTO_INCREMENT, task VARCHAR(40) NOT NULL, - value VARCHAR(100) NOT NULL, + value DECIMAL(65, 0) NOT NULL, date VARCHAR(20) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP , updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, diff --git a/packages/eventindexer/repo/chart_repo.go b/packages/eventindexer/repo/chart.go similarity index 96% rename from packages/eventindexer/repo/chart_repo.go rename to packages/eventindexer/repo/chart.go index e1326c4a35c..590ed4e92f5 100644 --- a/packages/eventindexer/repo/chart_repo.go +++ b/packages/eventindexer/repo/chart.go @@ -48,7 +48,7 @@ func (r *ChartRepository) Find( for _, d := range tsd { chart.Chart = append(chart.Chart, eventindexer.ChartItem{ Date: d.Date, - Value: d.Value, + Value: d.Value.Decimal.String(), }) } diff --git a/packages/eventindexer/repo/event.go b/packages/eventindexer/repo/event.go index 4b940615a6d..cb28860426a 100644 --- a/packages/eventindexer/repo/event.go +++ b/packages/eventindexer/repo/event.go @@ -56,6 +56,30 @@ func (r *EventRepository) Save(ctx context.Context, opts eventindexer.SaveEventO } } + if opts.ProposerReward != nil { + amt, err := decimal.NewFromString(opts.ProposerReward.String()) + if err != nil { + return nil, errors.Wrap(err, "decimal.NewFromString") + } + + e.ProposerReward = decimal.NullDecimal{ + Valid: true, + Decimal: amt, + } + } + + if opts.ProofReward != nil { + amt, err := decimal.NewFromString(opts.ProofReward.String()) + if err != nil { + return nil, errors.Wrap(err, "decimal.NewFromString") + } + + e.ProofReward = decimal.NullDecimal{ + Valid: true, + Decimal: amt, + } + } + if opts.AssignedProver != nil { e.AssignedProver = *opts.AssignedProver } diff --git a/packages/eventindexer/repo/stat.go b/packages/eventindexer/repo/stat.go index 65174abb912..82a5efd31b4 100644 --- a/packages/eventindexer/repo/stat.go +++ b/packages/eventindexer/repo/stat.go @@ -41,6 +41,11 @@ func (r *StatRepository) Save(ctx context.Context, opts eventindexer.SaveStatOpt s.AverageProofTime = opts.ProofTime.String() } + if opts.ProposerReward != nil { + s.NumProposerRewards++ + s.AverageProposerReward = opts.ProposerReward.String() + } + if err := r.db.GormDB().Save(s).Error; err != nil { return nil, errors.Wrap(err, "r.db.Save") } @@ -66,5 +71,9 @@ func (r *StatRepository) Find(ctx context.Context) (*eventindexer.Stat, error) { s.AverageProofTime = "0" } + if s.AverageProposerReward == "" { + s.AverageProposerReward = "0" + } + return s, nil } diff --git a/packages/eventindexer/repo/stat_test.go b/packages/eventindexer/repo/stat_test.go index 1c7d9128c3a..37abb5b81cf 100644 --- a/packages/eventindexer/repo/stat_test.go +++ b/packages/eventindexer/repo/stat_test.go @@ -5,7 +5,6 @@ import ( "math/big" "testing" - "github.com/davecgh/go-spew/spew" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "gotest.tools/assert" ) @@ -54,9 +53,14 @@ func TestIntegration_Stat_Find(t *testing.T) { var proofReward = big.NewInt(4) - _, err = statRepo.Save(context.Background(), eventindexer.SaveStatOpts{ - ProofReward: proofReward, - }) + var proposerReward = big.NewInt(7) + + for i := 0; i < 3; i++ { + _, err = statRepo.Save(context.Background(), eventindexer.SaveStatOpts{ + ProofReward: proofReward, + ProposerReward: proposerReward, + }) + } assert.Equal(t, nil, err) @@ -68,11 +72,13 @@ func TestIntegration_Stat_Find(t *testing.T) { { "success", &eventindexer.Stat{ - ID: 1, - AverageProofReward: proofReward.String(), - AverageProofTime: "0", - NumProofs: 0, - NumVerifiedBlocks: 1, + ID: 1, + AverageProofReward: proofReward.String(), + AverageProofTime: "0", + AverageProposerReward: proposerReward.String(), + NumProposerRewards: 3, + NumProofs: 0, + NumVerifiedBlocks: 3, }, nil, }, @@ -81,7 +87,7 @@ func TestIntegration_Stat_Find(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, err := statRepo.Find(context.Background()) - spew.Dump(resp) + assert.Equal(t, tt.wantErr, err) assert.Equal(t, *tt.wantResp, *resp) }) diff --git a/packages/eventindexer/stat.go b/packages/eventindexer/stat.go index 58752298b66..0734ca64def 100644 --- a/packages/eventindexer/stat.go +++ b/packages/eventindexer/stat.go @@ -9,17 +9,20 @@ import ( // into the Data field to be unmarshalled into a concrete struct // dependant on the name of the event type Stat struct { - ID int `json:"id"` - AverageProofTime string `json:"averageProofTime"` - AverageProofReward string `json:"averageProofReward"` - NumProofs uint64 `json:"numProofs"` - NumVerifiedBlocks uint64 `json:"numVerifiedBlocks"` + ID int `json:"id"` + AverageProofTime string `json:"averageProofTime"` + AverageProofReward string `json:"averageProofReward"` + AverageProposerReward string `json:"averageProposerReward"` + NumProposerRewards uint64 `json:"numProposerRewards"` + NumProofs uint64 `json:"numProofs"` + NumVerifiedBlocks uint64 `json:"numVerifiedBlocks"` } // SaveStatOpts type SaveStatOpts struct { - ProofTime *big.Int - ProofReward *big.Int + ProofTime *big.Int + ProofReward *big.Int + ProposerReward *big.Int } // StatRepository is used to interact with stats in the store diff --git a/packages/eventindexer/tasks/tasks.go b/packages/eventindexer/tasks/tasks.go index 971a8ffb717..62e4bc5cab5 100644 --- a/packages/eventindexer/tasks/tasks.go +++ b/packages/eventindexer/tasks/tasks.go @@ -19,6 +19,10 @@ var ( TotalProposeBlockTx = "total-propose-block-tx" BridgeMessagesSentPerDay = "bridge-messages-sent-per-day" TotalBridgeMessagesSent = "total-bridge-messages-sent" + TotalProofRewards = "total-proof-rewards" + ProofRewardsPerDay = "proof-rewards-per-day" + TotalProposerRewards = "total-proposer-rewards" + ProposerRewardsPerDay = "proposer-rewards-per-day" ) var Tasks = []string{ @@ -40,4 +44,8 @@ var Tasks = []string{ TotalProposeBlockTx, BridgeMessagesSentPerDay, TotalBridgeMessagesSent, + TotalProofRewards, + ProofRewardsPerDay, + TotalProposerRewards, + ProposerRewardsPerDay, } diff --git a/packages/eventindexer/time_series_data.go b/packages/eventindexer/time_series_data.go index 4d593b901b0..35c7dd8ec84 100644 --- a/packages/eventindexer/time_series_data.go +++ b/packages/eventindexer/time_series_data.go @@ -1,11 +1,15 @@ package eventindexer -import "time" +import ( + "time" + + "github.com/shopspring/decimal" +) type TimeSeriesData struct { ID int Task string - Value string + Value decimal.NullDecimal Date string CreatedAt time.Time UpdatedAt time.Time diff --git a/packages/fork-diff/index.html b/packages/fork-diff/index.html index e62685754f0..4bf32a4977e 100755 --- a/packages/fork-diff/index.html +++ b/packages/fork-diff/index.html @@ -337,19 +337,19 @@
    -
    +

    taiko-geth

    -
    +2139
    +
    +2148
    -63
    -
    +

    This is an overview of the changes between taiko-geth (taiko branch) and go-ethereum (v1.12.2 tag).

    @@ -357,19 +357,19 @@
    -