diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 67694fb..842d88e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: "1.18" + go-version: "1.21" - name: Download modules run: go mod download @@ -24,11 +24,11 @@ jobs: - name: gofmt check run: ./gofmt-check.sh - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: latest - args: --timeout 5m0s +# - name: golangci-lint +# uses: golangci/golangci-lint-action@v7 +# with: +# version: latest +# args: --timeout 15m0s - name: Build executables run: go build ./... diff --git a/.vscode/launch.json b/.vscode/launch.json index 6ddc14a..ed79d66 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,7 +4,15 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - + { + "name": "Launch Indexer (coston)", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/indexer/main/indexer.go", + "args": ["--config", "${workspaceFolder}/config.coston.toml"], + "cwd": "${workspaceFolder}" + }, { "name": "Launch Indexer (costwo)", "type": "go", diff --git a/database/pchain_entities.go b/database/pchain_entities.go index d2bb866..92e5236 100644 --- a/database/pchain_entities.go +++ b/database/pchain_entities.go @@ -7,24 +7,27 @@ import ( // Table with indexed data for a P-chain transaction type PChainTx struct { BaseEntity - Type PChainTxType `gorm:"type:varchar(20);index"` // Transaction type - TxID *string `gorm:"type:varchar(50);unique"` // Transaction ID - BlockID string `gorm:"type:varchar(50);not null"` // Block ID - BlockType PChainBlockType `gorm:"type:varchar(20)"` // Block type (proposal, accepted, rejected, etc.) - RewardTxID string `gorm:"type:varchar(50)"` // Referred transaction id in case of reward validator tx - BlockHeight uint64 `gorm:"index"` // Block height - Timestamp time.Time // Time when indexed - ChainID string `gorm:"type:varchar(50)"` // Filled in case of export or import transaction - NodeID string `gorm:"type:varchar(50)"` // Filled in case of add delegator or validator transaction - StartTime *time.Time `gorm:"index"` // Start time of validator or delegator (when NodeID is not null) - EndTime *time.Time `gorm:"index"` // End time of validator or delegator (when NodeID is not null) - Time *time.Time // Chain time (in case of advance time transaction) - Weight uint64 // Weight (stake amount) (when NodeID is not null) - RewardsOwner string `gorm:"type:varchar(60)"` // Rewards owner address (in case of add delegator or validator transaction) - Memo string `gorm:"type:varchar(256)"` - Bytes []byte `gorm:"type:mediumblob"` - FeePercentage uint32 // Fee percentage (in case of add validator transaction) - BlockTime *time.Time `gorm:"index"` // Block time, non-null from Banff block activation on (Avalanche 1.9.0) + Type PChainTxType `gorm:"type:varchar(40);index"` // Transaction type + TxID *string `gorm:"type:varchar(50);unique"` // Transaction ID + BlockID string `gorm:"type:varchar(50);not null"` // Block ID + BlockType PChainBlockType `gorm:"type:varchar(20)"` // Block type (proposal, accepted, rejected, etc.) + RewardTxID string `gorm:"type:varchar(50)"` // Referred transaction id in case of reward validator tx + BlockHeight uint64 `gorm:"index"` // Block height + Timestamp time.Time // Time when indexed + ChainID string `gorm:"type:varchar(50)"` // Filled in case of export or import transaction + NodeID string `gorm:"type:varchar(50)"` // Filled in case of add delegator or validator transaction + StartTime *time.Time `gorm:"index"` // Start time of validator or delegator (when NodeID is not null) + EndTime *time.Time `gorm:"index"` // End time of validator or delegator (when NodeID is not null) + Time *time.Time // Chain time (in case of advance time transaction) + Weight uint64 // Weight (stake amount) (when NodeID is not null) + RewardsOwner string `gorm:"type:varchar(60)"` // Rewards owner address (in case of add delegator or validator transaction) + DelegationRewardsOwner string `gorm:"type:varchar(60)"` // Delegation rewards owner address (in case of add validator transaction) + SubnetID string `gorm:"type:varchar(50)"` // Subnet ID (from Cortina update on, will be empty for pre-Cortina) + SignerPublicKey *string `gorm:"type:varchar(256)"` // Signer public key (for PermissionlessStaker transactions) + Memo string `gorm:"type:varchar(256)"` + Bytes []byte `gorm:"type:mediumblob"` + FeePercentage uint32 // Fee percentage (in case of add validator transaction) + BlockTime *time.Time `gorm:"index"` // Block time, non-null from Banff block activation on (Avalanche 1.9.0) } type PChainTxInput struct { diff --git a/database/pchain_queries.go b/database/pchain_queries.go index 045f416..0b69047 100644 --- a/database/pchain_queries.go +++ b/database/pchain_queries.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "golang.org/x/exp/slices" "gorm.io/gorm" ) @@ -43,7 +44,7 @@ func CreatePChainEntities(db *gorm.DB, txs []*PChainTx, ins []*PChainTxInput, ou // - if nodeID is not empty, only returns transactions where the given node ID is the validator node ID func FetchPChainStakingTransactions( db *gorm.DB, - txType PChainTxType, + txTypes []PChainTxType, nodeID string, address string, time time.Time, @@ -52,8 +53,10 @@ func FetchPChainStakingTransactions( ) ([]string, error) { var validatorTxs []PChainTx - if txType != PChainAddValidatorTx && txType != PChainAddDelegatorTx { - return nil, errInvalidTransactionType + for _, txType := range txTypes { + if !slices.Contains(PChainStakingTransactions[:], txType) { + return nil, errInvalidTransactionType + } } if limit <= 0 { limit = 100 @@ -62,7 +65,7 @@ func FetchPChainStakingTransactions( offset = 0 } - query := db.Where(&PChainTx{Type: txType}) + query := db.Where("type IN ?", txTypes) if len(nodeID) > 0 { query = query.Where("node_id = ?", nodeID) } @@ -87,7 +90,7 @@ func FetchPChainStakingTransactions( func FetchPChainStakingData( db *gorm.DB, time time.Time, - txType PChainTxType, + txTypes []PChainTxType, offset int, limit int, ) ([]PChainTxData, error) { @@ -104,7 +107,7 @@ func FetchPChainStakingData( Table("p_chain_txes"). Joins("left join p_chain_tx_inputs as inputs on inputs.tx_id = p_chain_txes.tx_id"). Where("start_time <= ?", time).Where("? <= end_time", time). - Where("type = ?", txType). + Where("type IN ?", txTypes). Group("p_chain_txes.id"). Order("p_chain_txes.id").Offset(offset).Limit(limit). Select("p_chain_txes.*, group_concat(distinct(inputs.address)) as input_address"). @@ -238,7 +241,7 @@ func FetchPChainVotingData(db *gorm.DB, from time.Time, to time.Time) ([]PChainT query := db. Table("p_chain_txes"). Joins("left join p_chain_tx_inputs as inputs on inputs.tx_id = p_chain_txes.tx_id"). - Where("type = ? OR type = ?", PChainAddValidatorTx, PChainAddDelegatorTx). + Where("type IN ?", PChainStakingTransactions). Where("start_time >= ?", from).Where("start_time < ?", to). Select("p_chain_txes.*, inputs.address as input_address, inputs.in_idx as input_index"). Scan(&data) @@ -258,10 +261,7 @@ func GetPChainTxsForEpoch(in *GetPChainTxsForEpochInput) ([]PChainTxData, error) Joins("left join p_chain_tx_inputs as inputs on inputs.tx_id = p_chain_txes.tx_id"). Where("p_chain_txes.start_time >= ?", in.StartTimestamp). Where("p_chain_txes.start_time < ?", in.EndTimestamp). - Where( - in.DB.Where("p_chain_txes.type = ?", PChainAddDelegatorTx). - Or("p_chain_txes.type = ?", PChainAddValidatorTx), - ). + Where("p_chain_txes.type IN ?", PChainStakingTransactions). Select("p_chain_txes.*, inputs.address as input_address, inputs.in_idx as input_index"). Find(&txs). Error @@ -273,13 +273,15 @@ func GetPChainTxsForEpoch(in *GetPChainTxsForEpochInput) ([]PChainTxData, error) } // Fetches all P-chain staking transactions of type txType intersecting the given time interval -func FetchNodeStakingIntervals(db *gorm.DB, txType PChainTxType, startTime time.Time, endTime time.Time) ([]PChainTx, error) { - if txType != PChainAddValidatorTx && txType != PChainAddDelegatorTx { - return nil, errInvalidTransactionType +func FetchNodeStakingIntervals(db *gorm.DB, txTypes []PChainTxType, startTime time.Time, endTime time.Time) ([]PChainTx, error) { + for _, txType := range txTypes { + if !slices.Contains(PChainStakingTransactions[:], txType) { + return nil, errInvalidTransactionType + } } var txs []PChainTx - err := db.Where(&PChainTx{Type: txType}). + err := db.Where("type IN ?", txTypes). Where("start_time <= ?", endTime). Where("end_time >= ?", startTime). Find(&txs).Error diff --git a/database/types.go b/database/types.go index 501fc9e..481ae79 100644 --- a/database/types.go +++ b/database/types.go @@ -30,6 +30,8 @@ const ( PChainUnknownTx PChainTxType = "UNKNOWN_TX" ) +var PChainStakingTransactions = [...]PChainTxType{PChainAddValidatorTx, PChainAddDelegatorTx, PChainAddPermissionlessValidatorTx, PChainAddPermissionlessDelegatorTx} + type PChainBlockType string const ( diff --git a/dockerfile.indexer b/dockerfile.indexer index 32906a3..e0b2974 100644 --- a/dockerfile.indexer +++ b/dockerfile.indexer @@ -1,5 +1,5 @@ # build executable -FROM golang:1.18 AS builder +FROM golang:1.21 AS builder WORKDIR /build diff --git a/dockerfile.services b/dockerfile.services index b709271..dd4745c 100644 --- a/dockerfile.services +++ b/dockerfile.services @@ -1,5 +1,5 @@ # build executable -FROM golang:1.18 AS builder +FROM golang:1.21 AS builder WORKDIR /build diff --git a/go.mod b/go.mod index 8059af4..287f7bf 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.21 require ( github.com/BurntSushi/toml v1.2.1 - github.com/ava-labs/avalanchego v1.9.7 - github.com/ava-labs/coreth v0.11.6-rc.0 + github.com/ava-labs/avalanchego v1.10.0 + github.com/ava-labs/coreth v0.12.0-rc.2 github.com/bradleyjkemp/cupaloy v2.3.0+incompatible github.com/davidebianchi/gswagger v0.9.0 github.com/deckarep/golang-set/v2 v2.1.0 @@ -30,6 +30,7 @@ require ( ) require ( + github.com/DataDog/zstd v1.5.2 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -39,8 +40,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set v1.8.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -72,11 +72,12 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect github.com/perimeterx/marshmallow v1.1.4 // indirect + github.com/pires/go-proxyproto v0.6.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.39.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect - github.com/rjeczalik/notify v0.9.2 // indirect + github.com/rjeczalik/notify v0.9.3 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/go.sum b/go.sum index 35cdfd7..295a6d0 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -44,10 +46,10 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA 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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/ava-labs/avalanchego v1.9.7 h1:f2vS8jUBZmrqPcfU5NEa7dSHXbKfTB0EyjcCyvqxqPw= -github.com/ava-labs/avalanchego v1.9.7/go.mod h1:ckdSQHeoRN6PmQ3TLgWAe6Kh9tFpU4Lu6MgDW4GrU/Q= -github.com/ava-labs/coreth v0.11.6-rc.0 h1:P8g/vqVx7nZBUHhM95oq9bcsY37P1Y7NNVb7RPe0mW8= -github.com/ava-labs/coreth v0.11.6-rc.0/go.mod h1:xgjjJdl50zhHlWPP+3Ux5LxfvFcbSG60tGK6QUkFDhI= +github.com/ava-labs/avalanchego v1.10.0 h1:Rn6Nyd62OkzQG5QpCgtCGVXtjuiaEzxV000kqG9aUIg= +github.com/ava-labs/avalanchego v1.10.0/go.mod h1:hTaSLGN4y/EmhmYd+yjUj9Lsm00q70V78jOYDdnLrgQ= +github.com/ava-labs/coreth v0.12.0-rc.2 h1:UNyGhuC2HxZ8eCLZiZON8xRiJkNHVZ75zknu/xqkKBA= +github.com/ava-labs/coreth v0.12.0-rc.2/go.mod h1:ZGhoIZTWbIaTmzEbprXu0hLtLdoE2PSTEFnCTYr0BRk= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -114,14 +116,11 @@ github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsP github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= -github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 h1:sgNeV1VRMDzs6rzyPpxyM0jp317hnwiq58Filgag2xw= -github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0/go.mod h1:J70FGZSbzsjecRTiTzER+3f1KZLNaXkuv+yeFTKoxM8= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -349,6 +348,8 @@ github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= +github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -366,8 +367,8 @@ github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38i github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= -github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= +github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= +github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= diff --git a/indexer/cronjob/mirror.go b/indexer/cronjob/mirror.go index b6a1533..3d376a1 100644 --- a/indexer/cronjob/mirror.go +++ b/indexer/cronjob/mirror.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/ava-labs/avalanchego/utils/crypto" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" mapset "github.com/deckarep/golang-set/v2" "github.com/pkg/errors" ) @@ -43,7 +43,7 @@ type mirrorContracts interface { merkleProof [][32]byte, ) error IsAddressRegistered(address string) (bool, error) - RegisterPublicKey(publicKey crypto.PublicKey) error + RegisterPublicKey(publicKey *secp256k1.PublicKey) error EpochConfig() (time.Time, time.Duration, error) } diff --git a/indexer/cronjob/mirror_stubs.go b/indexer/cronjob/mirror_stubs.go index e8f2665..5519490 100644 --- a/indexer/cronjob/mirror_stubs.go +++ b/indexer/cronjob/mirror_stubs.go @@ -14,7 +14,7 @@ import ( "math/big" "time" - "github.com/ava-labs/avalanchego/utils/crypto" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" @@ -163,11 +163,8 @@ func (m mirrorContractsCChain) IsAddressRegistered(address string) (bool, error) return boundAddress != (common.Address{}), nil } -func (m mirrorContractsCChain) RegisterPublicKey(publicKey crypto.PublicKey) error { - ethAddress, err := chain.PublicKeyToEthAddress(publicKey) - if err != nil { - return err - } +func (m mirrorContractsCChain) RegisterPublicKey(publicKey *secp256k1.PublicKey) error { + ethAddress := chain.PublicKeyToEthAddress(publicKey) tx, err := m.addressBinder.RegisterAddresses(m.txOpts, publicKey.Bytes(), publicKey.Address(), ethAddress) if err != nil { return err diff --git a/indexer/cronjob/mirror_test.go b/indexer/cronjob/mirror_test.go index 643f72e..13621cc 100644 --- a/indexer/cronjob/mirror_test.go +++ b/indexer/cronjob/mirror_test.go @@ -14,7 +14,7 @@ import ( "time" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/crypto" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/bradleyjkemp/cupaloy" mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" @@ -327,7 +327,7 @@ func (c testContracts) IsAddressRegistered(address string) (bool, error) { return true, nil } -func (c testContracts) RegisterPublicKey(publicKey crypto.PublicKey) error { +func (c testContracts) RegisterPublicKey(publicKey *secp256k1.PublicKey) error { return nil } diff --git a/indexer/cronjob/uptime_voting.go b/indexer/cronjob/uptime_voting.go index 697f46f..c423524 100644 --- a/indexer/cronjob/uptime_voting.go +++ b/indexer/cronjob/uptime_voting.go @@ -301,7 +301,11 @@ type nodeStakingInterval struct { // Return the staking intervals for each node, sorted by nodeID, note that it is possible // that a node has multiple intervals func fetchNodeStakingIntervals(db *gorm.DB, start time.Time, end time.Time) ([]nodeStakingInterval, error) { - txs, err := database.FetchNodeStakingIntervals(db, database.PChainAddValidatorTx, start, end) + txs, err := database.FetchNodeStakingIntervals( + db, + []database.PChainTxType{database.PChainAddValidatorTx, database.PChainAddPermissionlessValidatorTx}, + start, end, + ) if err != nil { return nil, err } diff --git a/indexer/pchain/batch_indexer.go b/indexer/pchain/batch_indexer.go index 88e3d6e..52a0764 100644 --- a/indexer/pchain/batch_indexer.go +++ b/indexer/pchain/batch_indexer.go @@ -1,6 +1,7 @@ package pchain import ( + "encoding/hex" "flare-indexer/database" "flare-indexer/indexer/context" "flare-indexer/indexer/shared" @@ -12,7 +13,6 @@ import ( "github.com/ava-labs/avalanchego/indexer" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/blocks" - "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "gorm.io/gorm" ) @@ -133,8 +133,12 @@ func (xi *txBatchIndexer) addTx(container *indexer.Container, blockType database err = xi.updateRewardValidatorTx(dbTx, unsignedTx) case *txs.AddValidatorTx: err = xi.updateAddValidatorTx(dbTx, unsignedTx) + case *txs.AddPermissionlessValidatorTx: + err = xi.updateAddPermissionlessValidatorTx(dbTx, unsignedTx) case *txs.AddDelegatorTx: err = xi.updateAddDelegatorTx(dbTx, unsignedTx) + case *txs.AddPermissionlessDelegatorTx: + err = xi.updateAddPermissionlessDelegatorTx(dbTx, unsignedTx) case *txs.ImportTx: err = xi.updateImportTx(dbTx, unsignedTx) case *txs.ExportTx: @@ -151,8 +155,6 @@ func (xi *txBatchIndexer) addTx(container *indexer.Container, blockType database err = xi.updateGeneralBaseTx(dbTx, database.PChainTransformSubnetTx, &unsignedTx.BaseTx) // We leave out the following transaction types as they are rejected by Flare nodes // - AddSubnetValidatorTx - // - AddPermissionlessValidatorTx - // - AddPermissionlessDelegatorTx default: err = fmt.Errorf("p-chain transaction %v with type %T in block %d is not indexed", dbTx.TxID, unsignedTx, height) } @@ -190,13 +192,22 @@ func (xi *txBatchIndexer) updateRewardValidatorTx(dbTx *database.PChainTx, tx *t func (xi *txBatchIndexer) updateAddValidatorTx(dbTx *database.PChainTx, tx *txs.AddValidatorTx) error { dbTx.Type = database.PChainAddValidatorTx - dbTx.FeePercentage = tx.DelegationShares - return xi.updateAddStakerTx(dbTx, tx, tx.Ins, tx.RewardsOwner) + return xi.updateValidatorTx(dbTx, tx, tx.Ins) +} + +func (xi *txBatchIndexer) updateAddPermissionlessValidatorTx(dbTx *database.PChainTx, tx *txs.AddPermissionlessValidatorTx) error { + dbTx.Type = database.PChainAddPermissionlessValidatorTx + return xi.updateValidatorTx(dbTx, tx, tx.Ins) } func (xi *txBatchIndexer) updateAddDelegatorTx(dbTx *database.PChainTx, tx *txs.AddDelegatorTx) error { dbTx.Type = database.PChainAddDelegatorTx - return xi.updateAddStakerTx(dbTx, tx, tx.Ins, tx.DelegationRewardsOwner) + return xi.updateDelegatorTx(dbTx, tx, tx.Ins) +} + +func (xi *txBatchIndexer) updateAddPermissionlessDelegatorTx(dbTx *database.PChainTx, tx *txs.AddPermissionlessDelegatorTx) error { + dbTx.Type = database.PChainAddPermissionlessDelegatorTx + return xi.updateDelegatorTx(dbTx, tx, tx.Ins) } func (xi *txBatchIndexer) updateImportTx(dbTx *database.PChainTx, tx *txs.ImportTx) error { @@ -246,12 +257,47 @@ func (xi *txBatchIndexer) PersistEntities(db *gorm.DB) error { return database.CreatePChainEntities(db, txs, ins, outs) } -// Common code for AddDelegatorTx and AddValidatorTx +// Common code for addValidatorTx and addPermissionlessValidatorTx (ValidatorTx interface) +func (xi *txBatchIndexer) updateValidatorTx( + dbTx *database.PChainTx, + tx txs.ValidatorTx, + txIns []*avax.TransferableInput, +) error { + ownerAddress, err := shared.RewardsOwnerAddress(tx.ValidationRewardsOwner()) + if err != nil { + return err + } + dbTx.RewardsOwner = ownerAddress + + ownerAddress, err = shared.RewardsOwnerAddress(tx.DelegationRewardsOwner()) + if err != nil { + return err + } + dbTx.DelegationRewardsOwner = ownerAddress + + dbTx.FeePercentage = tx.Shares() + return xi.updateAddStakerTx(dbTx, tx, txIns) +} + +// Common code for AddDelegatorTx and AddPermissionlessDelegatorTx (DelegatorTx interface) +func (xi *txBatchIndexer) updateDelegatorTx( + dbTx *database.PChainTx, + tx txs.DelegatorTx, + txIns []*avax.TransferableInput, +) error { + ownerAddress, err := shared.RewardsOwnerAddress(tx.RewardsOwner()) + if err != nil { + return err + } + dbTx.RewardsOwner = ownerAddress + return xi.updateAddStakerTx(dbTx, tx, txIns) +} + +// Common code for Add[Permissionless]DelegatorTx and Add[Permissionless]ValidatorTx func (xi *txBatchIndexer) updateAddStakerTx( dbTx *database.PChainTx, tx txs.PermissionlessStaker, txIns []*avax.TransferableInput, - rewardsOwner fx.Owner, ) error { startTime := tx.StartTime() endTime := tx.EndTime() @@ -259,12 +305,16 @@ func (xi *txBatchIndexer) updateAddStakerTx( dbTx.StartTime = &startTime dbTx.EndTime = &endTime dbTx.Weight = tx.Weight() + dbTx.SubnetID = tx.SubnetID().String() - ownerAddress, err := shared.RewardsOwnerAddress(rewardsOwner) + publicKey, _, err := tx.PublicKey() if err != nil { return err } - dbTx.RewardsOwner = ownerAddress + if publicKey != nil { + pkString := hex.EncodeToString(publicKey.Compress()) + dbTx.SignerPublicKey = &pkString + } outs, err := getAddStakerTxOutputs(*dbTx.TxID, tx) if err != nil { diff --git a/indexer/shared/constants.go b/indexer/shared/constants.go index 3227c7d..3bb676f 100644 --- a/indexer/shared/constants.go +++ b/indexer/shared/constants.go @@ -1,5 +1,5 @@ package shared const ( - ApplicationVersion = "2.0.2" + ApplicationVersion = "2.1.0" ) diff --git a/services/routes/query.go b/services/routes/query.go index d827562..ff37eb6 100644 --- a/services/routes/query.go +++ b/services/routes/query.go @@ -11,6 +11,7 @@ import ( "net/http" "github.com/ava-labs/avalanchego/ids" + "golang.org/x/exp/slices" "gorm.io/gorm" ) @@ -155,11 +156,11 @@ func (qr *queryRouteHandlers) executePChainStakingRequest( response.Status = api.VerificationStatusNonExistentBlock case tx == nil: response.Status = api.VerificationStatusNonExistentTransaction - case tx.Type != database.PChainAddValidatorTx && tx.Type != database.PChainAddDelegatorTx: + case !slices.Contains(database.PChainStakingTransactions[:], tx.Type): response.Status = api.VerificationStatusNonExistentTransaction default: var txType byte - if tx.Type == database.PChainAddValidatorTx { + if tx.Type == database.PChainAddValidatorTx || tx.Type == database.PChainAddPermissionlessValidatorTx { txType = 0 } else { txType = 1 diff --git a/services/routes/staking.go b/services/routes/staking.go index f9b7a26..56f95ac 100644 --- a/services/routes/staking.go +++ b/services/routes/staking.go @@ -43,9 +43,9 @@ func newStakerRouteHandlers(ctx context.ServicesContext) *stakerRouteHandlers { } } -func (rh *stakerRouteHandlers) listStakingTransactions(txType database.PChainTxType) utils.RouteHandler { +func (rh *stakerRouteHandlers) listStakingTransactions(txTypes ...database.PChainTxType) utils.RouteHandler { handler := func(request GetStakerTxRequest) (TxIDsResponse, *utils.ErrorHandler) { - txIDs, err := database.FetchPChainStakingTransactions(rh.db, txType, request.NodeID, + txIDs, err := database.FetchPChainStakingTransactions(rh.db, txTypes, request.NodeID, request.Address, request.Time, request.Offset, request.Limit) if err != nil { return TxIDsResponse{}, utils.InternalServerErrorHandler(err) @@ -55,9 +55,9 @@ func (rh *stakerRouteHandlers) listStakingTransactions(txType database.PChainTxT return utils.NewRouteHandler(handler, http.MethodPost, GetStakerTxRequest{}, TxIDsResponse{}) } -func (rh *stakerRouteHandlers) listStakers(txType database.PChainTxType) utils.RouteHandler { +func (rh *stakerRouteHandlers) listStakers(txTypes ...database.PChainTxType) utils.RouteHandler { handler := func(request GetStakerRequest) ([]GetStakerResponse, *utils.ErrorHandler) { - stakerTxData, err := database.FetchPChainStakingData(rh.db, request.Time, txType, request.Offset, request.Limit) + stakerTxData, err := database.FetchPChainStakingData(rh.db, request.Time, txTypes, request.Offset, request.Limit) if err != nil { return nil, utils.InternalServerErrorHandler(err) } @@ -82,10 +82,14 @@ func AddStakerRoutes(router utils.Router, ctx context.ServicesContext) { vr := newStakerRouteHandlers(ctx) validatorSubrouter := router.WithPrefix("/validators", "Staking") - validatorSubrouter.AddRoute("/transactions", vr.listStakingTransactions(database.PChainAddValidatorTx)) - validatorSubrouter.AddRoute("/list", vr.listStakers(database.PChainAddValidatorTx)) + validatorSubrouter.AddRoute("/transactions", + vr.listStakingTransactions(database.PChainAddValidatorTx, database.PChainAddPermissionlessValidatorTx)) + validatorSubrouter.AddRoute("/list", + vr.listStakers(database.PChainAddValidatorTx, database.PChainAddPermissionlessValidatorTx)) delegatorSubrouter := router.WithPrefix("/delegators", "Staking") - delegatorSubrouter.AddRoute("/transactions", vr.listStakingTransactions(database.PChainAddDelegatorTx)) - delegatorSubrouter.AddRoute("/list", vr.listStakers(database.PChainAddDelegatorTx)) + delegatorSubrouter.AddRoute("/transactions", + vr.listStakingTransactions(database.PChainAddDelegatorTx, database.PChainAddPermissionlessDelegatorTx)) + delegatorSubrouter.AddRoute("/list", + vr.listStakers(database.PChainAddDelegatorTx, database.PChainAddPermissionlessDelegatorTx)) } diff --git a/utils/chain/address.go b/utils/chain/address.go index b8e646a..d263d03 100644 --- a/utils/chain/address.go +++ b/utils/chain/address.go @@ -4,7 +4,7 @@ import ( "flare-indexer/config" "fmt" - "github.com/ava-labs/avalanchego/utils/crypto" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" @@ -43,9 +43,6 @@ func ParseAddress(addr string) ([20]byte, error) { return address20, nil } -func PublicKeyToEthAddress(publicKey crypto.PublicKey) (common.Address, error) { - if pk, ok := publicKey.(*crypto.PublicKeySECP256K1R); ok { - return ethCrypto.PubkeyToAddress(*pk.ToECDSA()), nil - } - return common.Address{}, ErrInvalidPublicKeyType +func PublicKeyToEthAddress(publicKey *secp256k1.PublicKey) common.Address { + return ethCrypto.PubkeyToAddress(*publicKey.ToECDSA()) } diff --git a/utils/chain/p_chain_pk_test.go b/utils/chain/p_chain_pk_test.go index 3160ee6..95678a6 100644 --- a/utils/chain/p_chain_pk_test.go +++ b/utils/chain/p_chain_pk_test.go @@ -24,10 +24,7 @@ func TestPublicKeysFromProposalBlock(t *testing.T) { t.Fatal(err) } - ethAddress, err := PublicKeyToEthAddress(pk) - if err != nil { - t.Fatal(err) - } + ethAddress := PublicKeyToEthAddress(pk) if ethAddress.Hex() != "0x91401C111C3adD819e73bc8C109A2c9e5BF502d9" { t.Fatal("Wrong address") } @@ -50,10 +47,7 @@ func TestPublicKeysFromStandardBlockEth(t *testing.T) { t.Fatal(err) } - ethAddress, err := PublicKeyToEthAddress(pk) - if err != nil { - t.Fatal(err) - } + ethAddress := PublicKeyToEthAddress(pk) if ethAddress.Hex() != "0x8ab7028638854AE968EF5174996C17D010Af4bD5" { t.Fatal("Wrong address") } @@ -76,10 +70,7 @@ func TestPublicKeysFromStandardBlockAvalanche(t *testing.T) { t.Fatal(err) } - ethAddress, err := PublicKeyToEthAddress(pk) - if err != nil { - t.Fatal(err) - } + ethAddress := PublicKeyToEthAddress(pk) if ethAddress.Hex() != "0x9327a86e5942da03Bd397576546ABBe7eAA4bd03" { t.Fatal("Wrong address") } diff --git a/utils/chain/p_chain_tx.go b/utils/chain/p_chain_tx.go index 496d3e3..5ef96a9 100644 --- a/utils/chain/p_chain_tx.go +++ b/utils/chain/p_chain_tx.go @@ -4,7 +4,7 @@ import ( "encoding/hex" "fmt" - "github.com/ava-labs/avalanchego/utils/crypto" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/blocks" @@ -42,7 +42,7 @@ func ParsePChainBlock(blockBytes []byte) (blocks.Block, error) { // For a given block (byte array), transaction ID, address bytes and input index, returns a public key // that signed the input at the provided index and address -func PublicKeyFromPChainBlock(txID string, addrBytes [20]byte, addrIndex uint32, blockBytes []byte) (crypto.PublicKey, error) { +func PublicKeyFromPChainBlock(txID string, addrBytes [20]byte, addrIndex uint32, blockBytes []byte) (*secp256k1.PublicKey, error) { innerBlk, err := ParsePChainBlock(blockBytes) if err != nil { return nil, err @@ -90,8 +90,8 @@ func PublicKeyFromPChainBlock(txID string, addrBytes [20]byte, addrIndex uint32, // For a given P-chain transaction hash return a public key for // a signature of a transaction hash that matches the provided address -func PublicKeyForAddressAndSignedHash(cred verify.Verifiable, address [20]byte, signedTxHash []byte) (crypto.PublicKey, error) { - factory := crypto.FactorySECP256K1R{} +func PublicKeyForAddressAndSignedHash(cred verify.Verifiable, address [20]byte, signedTxHash []byte) (*secp256k1.PublicKey, error) { + factory := secp256k1.Factory{} if secpCred, ok := cred.(*secp256k1fx.Credential); !ok { return nil, ErrInvalidCredentialType } else { diff --git a/utils/staking/utils.go b/utils/staking/utils.go index 802c2fe..6c23f56 100644 --- a/utils/staking/utils.go +++ b/utils/staking/utils.go @@ -158,12 +158,10 @@ func encodeTreeItem(tx *database.PChainTxData) ([]byte, error) { func GetTxType(txType database.PChainTxType) (uint8, error) { switch txType { - case database.PChainAddValidatorTx: + case database.PChainAddValidatorTx, database.PChainAddPermissionlessValidatorTx: return 0, nil - - case database.PChainAddDelegatorTx: + case database.PChainAddDelegatorTx, database.PChainAddPermissionlessDelegatorTx: return 1, nil - default: return 0, errors.New("invalid tx type") }