Skip to content

Commit

Permalink
Merge pull request #20 from Kava-Labs/rp-util
Browse files Browse the repository at this point in the history
add a script to trigger block reindex
  • Loading branch information
pirtleshell authored Nov 7, 2023
2 parents 57e0dfc + cd4c51d commit d3c246d
Show file tree
Hide file tree
Showing 7 changed files with 444 additions and 0 deletions.
9 changes: 9 additions & 0 deletions util/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# AWS ARN for the RDS cluster. Looks like below
RDS_RESOURCE_ARN=arn:aws:rds:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:cluster:{CLUSTER_NAME}
# AWS Secret ARN for accessing the database. Looks like below
# see https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_database_secret.html
RDS_SECRET_ARN=arn:aws:secretsmanager:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:secret:{SECRET_NAME}
# Name of the database
RDS_DB_NAME=blockscout
# JSON-RPC API url for the EVM
EVM_JSON_RPC_URL=https://evm.data.kava.io:443
1 change: 1 addition & 0 deletions util/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
144 changes: 144 additions & 0 deletions util/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package client

import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
awsconfig "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/rdsdata"
"github.com/aws/aws-sdk-go-v2/service/rdsdata/types"
"github.com/ethereum/go-ethereum/ethclient"
)

// Config wraps the necessary parameters to create a Client
type Config struct {
// ARN of the RDS cluster
RdsResourceArn string
// see https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_database_secret.html
RdsSecretArn string
// name of the database inside the RDS cluster
RdsDbName string
// json-rpc api url for connecting to the evm, including port number
EvmJsonRpcUrl string
}

// Client wraps functionality for interacting with a blockscout postgres database in AWS.
type Client struct {
evm *ethclient.Client
rds *rdsdata.Client

rdsResourceArn string
rdsSecretArn string
rdsDbName string
}

// New creates a new client for interacting with a blockscout database in AWS.
func New(config Config) (*Client, error) {
awsConfig, err := awsconfig.LoadDefaultConfig(context.Background())
if err != nil {
return nil, fmt.Errorf("loading aws config failed: %s", err)
}

evmClient, err := ethclient.Dial(config.EvmJsonRpcUrl)
if err != nil {
return nil, fmt.Errorf("failed to dial evm: %s", err)
}

return &Client{
rdsResourceArn: config.RdsResourceArn,
rdsSecretArn: config.RdsSecretArn,
rdsDbName: config.RdsDbName,
rds: rdsdata.NewFromConfig(awsConfig),
evm: evmClient,
}, nil
}

// executeStatement runs raw sql (with param inputs) on the blockscout database
func (c *Client) executeStatement(sql string, params []types.SqlParameter) (*rdsdata.ExecuteStatementOutput, error) {
return c.rds.ExecuteStatement(context.Background(), &rdsdata.ExecuteStatementInput{
ResourceArn: aws.String(c.rdsResourceArn),
SecretArn: aws.String(c.rdsSecretArn),
Sql: aws.String(sql),
Database: aws.String(c.rdsDbName),
FormatRecordsAs: "JSON",
IncludeResultMetadata: true,
Parameters: params,
})
}

// PendingBlockOperations represents a blocks currently in blockscout's index queue
// They are rows of the public.pending_block_operations table.
type PendingBlockOperations struct {
BlockHash string `json:"block_hash"` //base64 encoded
InsertedAt string `json:"inserted_at"`
UpdatedAt string `json:"updated_at"`
BlockNumber int64 `json:"block_number"`
}

// PendingBlockOperations queries for all the currently pending block operations.
// These represent all the blocks currently in blockscout's index queue.
func (c *Client) PendingBlockOperations() ([]PendingBlockOperations, error) {
var result []PendingBlockOperations
res, err := c.executeStatement("SELECT * FROM public.pending_block_operations;", []types.SqlParameter{})
if err != nil {
return result, err
}

if err := json.Unmarshal([]byte(*res.FormattedRecords), &result); err != nil {
return result, err
}

return result, nil
}

// QueueBlockReindex queries for the evm block hash by height & then injects a pending block operation
// for the block. Triggers blockscout to re-index the txs & internal txs in the block.
func (c *Client) QueueBlockReindex(height int64) error {
// for some ungodly reason, ethclient doesn't expose the hash property from BlockByNumber...
// it only exposes a Hash() calculation that doesn't result in the correct hash value.
// get around that by making a direct call to the api and extracting the `hash`.
var blockHashRes *struct {
Hash string `json:"hash"`
}

// fetch the evm block hash for this height
hexHeight := fmt.Sprintf("0x%s", hex.EncodeToString(big.NewInt(height).Bytes()))
err := c.evm.Client().Call(&blockHashRes, "eth_getBlockByNumber", hexHeight, false)
if err != nil {
return err
}

fmt.Printf("block %d has hash %s\n", height, blockHashRes.Hash)
// drop the 0x prefix
blockHash := strings.Replace(blockHashRes.Hash, "0x", "", 1)

// build sql to add new pending block operation
statement := `
INSERT into public.pending_block_operations (block_hash,inserted_at,updated_at,block_number)
values (
decode(:blockhash, 'hex'),
now(),
now(),
:height
);
`
params := []types.SqlParameter{
{
Name: aws.String("blockhash"),
Value: &types.FieldMemberStringValue{Value: blockHash},
},
{
Name: aws.String("height"),
Value: &types.FieldMemberLongValue{Value: height},
},
}

// execute statement
_, err = c.executeStatement(statement, params)
return err
}
50 changes: 50 additions & 0 deletions util/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module github.com/kava-labs/kava-blockscout-build/util

go 1.20

require (
github.com/aws/aws-sdk-go-v2 v1.22.1
github.com/aws/aws-sdk-go-v2/config v1.22.0
github.com/aws/aws-sdk-go-v2/service/rdsdata v1.17.0
github.com/ethereum/go-ethereum v1.13.4
github.com/joho/godotenv v1.5.1
)

require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.15.1 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.5.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.17.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.25.0 // indirect
github.com/aws/smithy-go v1.16.0 // indirect
github.com/bits-and-blooms/bitset v1.7.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum/c-kzg-4844 v0.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/holiman/uint256 v1.2.3 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/tools v0.13.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
Loading

0 comments on commit d3c246d

Please sign in to comment.