1
0
Fork 0

add deposit/withdraw
continuous-integration/drone Build is failing Details

This commit is contained in:
Massaki Archambault 2021-09-25 15:09:40 -04:00 committed by Massaki Archambault
parent b8172f06ab
commit ff8e8cc377
8 changed files with 297 additions and 63 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
bin/

17
.drone.yml Normal file
View File

@ -0,0 +1,17 @@
kind: pipeline
type: kubernetes
name: arm64
node_selector:
beta.kubernetes.io/arch: arm64
steps:
- name: docker
image: plugins/docker
settings:
repo: badjware/nextcloud-tweak
auto_tag: true
username:
from_secret: docker_username
password:
from_secret: docker_password

10
Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM golang:1.17-alpine as builder
COPY . /app
WORKDIR /app
RUN apk add git make build-base \
&& make dist
FROM gcr.io/distroless/base-debian10
COPY --from=builder /app/bin/helium-blockchain-exporter /usr/bin/helium-blockchain-exporter
EXPOSE 9865
ENTRYPOINT [ "/usr/bin/helium-blockchain-exporter" ]

View File

@ -33,19 +33,19 @@ all: build
help: help:
@echo "clean revert back to clean state" @echo "clean revert back to clean state"
@echo "lint lint and format the code" @echo "lint lint and format the code"
@echo "run run without building"
@echo "prepare prepare environment for build" @echo "prepare prepare environment for build"
@echo "test build and run short test suite" @echo "test build and run short test suite"
@echo "coverage build and run full test suite and generate coverage report" @echo "coverage build and run full test suite and generate coverage report"
@echo "build build the binary" @echo "build build the binary"
@echo "build-docker build the docker image" @echo "dist build the binary for release"
@echo "docker build the docker image"
# clean: revert back to initial state # clean: revert back to initial state
.PHONY: clean .PHONY: clean
clean: clean:
$(GOCLEAN) $(GOCLEAN)
rm -r $(TARGET_DIR) rm -r $(TARGET_DIR) || true
# lint: lint and format the code # lint: lint and format the code
@ -53,17 +53,6 @@ clean:
lint: lint:
$(GOFMT) ./... $(GOFMT) ./...
# run: run without building with debug flags
ifeq (run,$(firstword $(MAKECMDGOALS)))
# use the rest as arguments for "run"
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# ...and turn them into do-nothing targets
$(eval $(RUN_ARGS):;@:)
endif
.PHONY: run
run: lint
$(GORUN) . $(RUN_ARGS)
# prepare: prepare environment for build # prepare: prepare environment for build
$(TARGET_DIR): $(TARGET_DIR):
@ -90,18 +79,24 @@ $(COVER_REPORT): $(TARGET_DIR) $(COVER_PROFILE)
coverage: lint $(COVER_REPORT) coverage: lint $(COVER_REPORT)
$(GOCOVER) -func=$(COVER_PROFILE) $(GOCOVER) -func=$(COVER_PROFILE)
# build: build the program for release # build: build the program
$(BIN): $(TARGET_DIR) $(SRC) $(BIN): $(TARGET_DIR) $(SRC)
$(GOBUILD) -o=$(BIN) $(GOBUILD) -o=$(BIN) -race
.PHONY: build .PHONY: build
build: lint $(BIN) build: lint $(BIN)
# build-docker: build the docker image # dist: build the program for release
.PHONY: build-docker .PHONY: dist
build-docker: $(BIN) dist: $(TARGET_DIR) $(SRC)
$(GOBUILD) -o=$(BIN) -a -ldflags "-linkmode external -extldflags -static"
# docker: build the docker image
.PHONY: docker
docker: $(BIN)
$(DOCKERBUILD) -t $(PROGRAM) . $(DOCKERBUILD) -t $(PROGRAM) .
$(foreach tag,$(DOCKER_TAGS),$(DOCKERTAG) $(PROGRAM) $(tag);) $(foreach tag,$(DOCKER_TAGS),$(DOCKERTAG) $(PROGRAM) $(tag);)

View File

@ -53,7 +53,6 @@ func NewAccount(address string) Account {
DepositTotal: 0, DepositTotal: 0,
WithdrawalTotal: 0, WithdrawalTotal: 0,
LastUpdate: time.Now(), LastUpdate: time.Now(),
// LastUpdate: time.Time{},
}, },
} }
} }
@ -69,23 +68,6 @@ const (
) )
var ( var (
// Activity classification
accountDepositActivities = []string{
"payment_v1", // if payee == account_address
"payment_v2", // if payee == account_address
"rewards_v1",
"unstake_validator_v1",
}
accountWithdrawalActivities = []string{
"add_gateway_v1",
"assert_location_v1",
"assert_location_v2",
"payment_v1", // if payer == account_address
"payment_v2", // if payer == account_address
"stake_validator_v1",
"token_burn_v1",
}
// labels // labels
commonAccountLabels = []string{"account"} commonAccountLabels = []string{"account"}
commonHotspotLabels = append(commonAccountLabels, "hotspot", "hotspot_name") commonHotspotLabels = append(commonAccountLabels, "hotspot", "hotspot_name")
@ -415,7 +397,7 @@ func (e *Exporter) collectAccountMetrics(ch chan<- prometheus.Metric, account *A
fmt.Println(err) fmt.Println(err)
return return
} }
tx, err := account.computeTransactions() err = account.collectTransactionMetrics(ch)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -435,14 +417,6 @@ func (e *Exporter) collectAccountMetrics(ch chan<- prometheus.Metric, account *A
accountRewardsHnt.Desc, accountRewardsHnt.Type, accountRewardTotalsForAddress.Data.Sum, accountRewardsHnt.Desc, accountRewardsHnt.Type, accountRewardTotalsForAddress.Data.Sum,
account.Address, account.Address,
) )
ch <- prometheus.MustNewConstMetric(
accountDepositsHnt.Desc, accountDepositsHnt.Type, float64(tx.DepositTotal),
account.Address,
)
ch <- prometheus.MustNewConstMetric(
accountWithdrawalsHnt.Desc, accountWithdrawalsHnt.Type, float64(tx.WithdrawalTotal),
account.Address,
)
} }
// collectStatsMetrics collect metrics in the hotspot group from the helium api // collectStatsMetrics collect metrics in the hotspot group from the helium api
@ -503,24 +477,90 @@ func (e *Exporter) collectHotspotMetrics(ch chan<- prometheus.Metric, account *A
} }
} }
func (a *Account) computeTransactions() (*AccountTx, error) { func (a *Account) collectTransactionMetrics(ch chan<- prometheus.Metric) error {
now := time.Now() now := time.Now()
_, err := heliumapi.GetActivityForAccount(a.Address, []string{}, &a.Tx.LastUpdate, &now) activities, err := heliumapi.GetActivityForAccount(a.Address, []string{}, &a.Tx.LastUpdate, &now)
if err != nil { if err != nil {
return nil, err return err
} }
// fmt.Println(activities) // logic based on https://github.com/helium/hotspot-app/blob/918563fba84d1abf4554a43a4d42bb838d017bd3/src/features/wallet/root/useActivityItem.tsx#L336
for _, activity := range activities.AddGatewayV1 {
a.Tx.WithdrawalTotal += activity.StakingFee
}
for _, activity := range activities.AssertLocationV1 {
a.Tx.WithdrawalTotal += activity.StakingFee
}
for _, activity := range activities.AssertLocationV2 {
a.Tx.WithdrawalTotal += activity.StakingFee
}
for _, activity := range activities.PaymentV1 {
if activity.Payer == a.Address {
a.Tx.WithdrawalTotal += activity.Amount
} else {
a.Tx.DepositTotal += activity.Amount
}
}
for _, activity := range activities.PaymentV2 {
if activity.Payer == a.Address {
paymentTotal := 0
for _, payment := range activity.Payments {
paymentTotal += payment.Amount
}
a.Tx.WithdrawalTotal += paymentTotal
} else {
for _, payment := range activity.Payments {
if payment.Payee == a.Address {
a.Tx.DepositTotal += payment.Amount
}
}
}
}
for _, activity := range activities.RewardsV1 {
for _, reward := range activity.Rewards {
a.Tx.DepositTotal += reward.Amount
}
}
for _, activity := range activities.RewardsV2 {
for _, reward := range activity.Rewards {
a.Tx.DepositTotal += reward.Amount
}
}
for _, activity := range activities.StakeValidatorV1 {
a.Tx.WithdrawalTotal += activity.Stake
}
for _, activity := range activities.TokenBurnV1 {
a.Tx.WithdrawalTotal += activity.Amount
}
for _, activity := range activities.TransferHotspotV1 {
if activity.Buyer == a.Address {
a.Tx.WithdrawalTotal += activity.AmountToSeller
} else {
a.Tx.DepositTotal += activity.AmountToSeller
}
}
for _, activity := range activities.UnstakeValidatorV1 {
a.Tx.WithdrawalTotal += activity.StakeAmount
}
a.Tx.LastUpdate = now a.Tx.LastUpdate = now
return &a.Tx, nil
ch <- prometheus.MustNewConstMetric(
accountDepositsHnt.Desc, accountDepositsHnt.Type, float64(a.Tx.DepositTotal),
a.Address,
)
ch <- prometheus.MustNewConstMetric(
accountWithdrawalsHnt.Desc, accountWithdrawalsHnt.Type, float64(a.Tx.WithdrawalTotal),
a.Address,
)
return nil
} }
func main() { func main() {
fHeliumAccounts := flag.String("accounts", "", "A comma-delimited list of helium accounts to scrape.") fHeliumAccounts := flag.String("accounts", "", "A comma-delimited list of helium accounts to scrape (optional)")
fMetricsPath := flag.String("metricpath", "/metrics", "The metrics path") fMetricsPath := flag.String("metricpath", "/metrics", "The metrics path")
fListenAddress := flag.String("listenAddress", "0.0.0.0", "The http server listen address") fListenAddress := flag.String("listenAddress", "0.0.0.0", "The http server listen address")
fListenPort := flag.String("listenPort", "9111", "The http server listen port") fListenPort := flag.String("listenPort", "9865", "The http server listen port")
flag.Parse() flag.Parse()
heliumAccounts := strings.Split(*fHeliumAccounts, ",") heliumAccounts := strings.Split(*fHeliumAccounts, ",")

View File

@ -9,8 +9,6 @@ type ActivityResp struct {
Data []json.RawMessage `json:"data"` Data []json.RawMessage `json:"data"`
} }
type Activities struct{}
func NewActivities(resp ActivityResp) (*Activities, error) { func NewActivities(resp ActivityResp) (*Activities, error) {
type ActivityType struct { type ActivityType struct {
Type string `json:"type"` Type string `json:"type"`
@ -26,16 +24,67 @@ func NewActivities(resp ActivityResp) (*Activities, error) {
fmt.Println(activityType.Type) fmt.Println(activityType.Type)
switch activityType.Type { switch activityType.Type {
case "add_gateway_v1": case "add_gateway_v1":
addGatewayV1 := AddGatewayV1{}
if err := json.Unmarshal(activityRaw, &addGatewayV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.AddGatewayV1 = append(activities.AddGatewayV1, addGatewayV1)
case "assert_location_v1": case "assert_location_v1":
assertLocationV1 := AssertLocationV1{}
if err := json.Unmarshal(activityRaw, &assertLocationV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.AssertLocationV1 = append(activities.AssertLocationV1, assertLocationV1)
case "assert_location_v2": case "assert_location_v2":
assertLocationV2 := AssertLocationV2{}
if err := json.Unmarshal(activityRaw, &assertLocationV2); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.AssertLocationV2 = append(activities.AssertLocationV2, assertLocationV2)
case "payment_v1": case "payment_v1":
paymentV1 := PaymentV1{}
if err := json.Unmarshal(activityRaw, &paymentV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.PaymentV1 = append(activities.PaymentV1, paymentV1)
case "payment_v2": case "payment_v2":
paymentV2 := PaymentV2{}
if err := json.Unmarshal(activityRaw, &paymentV2); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.PaymentV2 = append(activities.PaymentV2, paymentV2)
case "rewards_v1": case "rewards_v1":
rewardV1 := RewardsV1{}
if err := json.Unmarshal(activityRaw, &rewardV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.RewardsV1 = append(activities.RewardsV1, rewardV1)
case "rewards_v2":
rewardV2 := RewardsV2{}
if err := json.Unmarshal(activityRaw, &rewardV2); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.RewardsV2 = append(activities.RewardsV2, rewardV2)
case "stake_validator_v1": case "stake_validator_v1":
stakeValidatorV1 := StakeValidatorV1{}
if err := json.Unmarshal(activityRaw, &stakeValidatorV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.StakeValidatorV1 = append(activities.StakeValidatorV1, stakeValidatorV1)
case "token_burn_v1": case "token_burn_v1":
tokenBurnV1 := TokenBurnV1{}
if err := json.Unmarshal(activityRaw, &activities.TokenBurnV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.TokenBurnV1 = append(activities.TokenBurnV1, tokenBurnV1)
case "unstake_validator_v1": case "unstake_validator_v1":
unstakeValidatorV1 := UnstakeValidatorV1{}
if err := json.Unmarshal(activityRaw, &activities.UnstakeValidatorV1); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", activityType.Type, err)
}
activities.UnstakeValidatorV1 = append(activities.UnstakeValidatorV1, unstakeValidatorV1)
default: default:
fmt.Printf("unimplemented activy type: %v", activityType.Type) fmt.Printf("ignoring unimplemented activy type: %v", activityType.Type)
} }
} }

View File

@ -1 +1,129 @@
package activity package activity
type Activities struct {
AddGatewayV1 []AddGatewayV1
AssertLocationV1 []AssertLocationV1
AssertLocationV2 []AssertLocationV2
PaymentV1 []PaymentV1
PaymentV2 []PaymentV2
RewardsV1 []RewardsV1
RewardsV2 []RewardsV2
StakeValidatorV1 []StakeValidatorV1
TokenBurnV1 []TokenBurnV1
TransferHotspotV1 []TransferHotspotV1
UnstakeValidatorV1 []UnstakeValidatorV1
}
type AddGatewayV1 struct {
Hash string `json:"hash"`
Fee int `json:"fee"`
Owner string `json:"owner"`
Payer string `json:"payer"`
Gateway string `json:"gateway"`
StakingFee int `json:"staking_fee"`
}
type AssertLocationV1 struct {
Hash string `json:"hash"`
Fee int `json:"fee"`
Nonce int `json:"nonce"`
Owner string `json:"owner"`
Payer string `json:"payer,omitempty"`
Gateway string `json:"gateway"`
Location string `json:"location"`
StakingFee int `json:"staking_fee"`
}
type AssertLocationV2 struct {
Hash string `json:"hash"`
Fee int `json:"fee"`
Gain int `json:"gain"`
Nonce int `json:"nonce"`
Owner string `json:"owner"`
Payer string `json:"payer,omitempty"`
Gateway string `json:"gateway"`
Location string `json:"location"`
Elevation int `json:"elevation"`
StakingFee int `json:"staking_fee"`
}
type PaymentV1 struct {
Hash string `json:"hash"`
Amount int `json:"amount"`
Fee int `json:"fee"`
Nonce int `json:"nonce"`
Payer string `json:"payer"`
Payee string `json:"payee"`
}
type PaymentV2 struct {
Hash string `json:"hash"`
Fee int `json:"fee"`
Nonce int `json:"nonce"`
Payer string `json:"payer"`
Payments []struct {
Amount int `json:"amount"`
Memo string `json:"memo"`
Payee string `json:"payee"`
}
}
type reward struct {
Account string `json:"account,omitempty"`
Amount int `json:"amount"`
Gateway string `json:"gateway,omitempty"`
Type string `json:"type"`
}
type RewardsV1 struct {
Hash string `json:"hash"`
StartEpoch int `json:"start_epoch"`
EndEpoch int `json:"end_epoch"`
Rewards []reward `json:"rewards"`
}
type RewardsV2 struct {
Hash string `json:"hash"`
StartEpoch int `json:"start_epoch"`
EndEpoch int `json:"end_epoch"`
Rewards []reward `json:"rewards"`
}
type StakeValidatorV1 struct {
Address string `json:"address"`
Fee int `json:"fee"`
Hash string `json:"hash"`
Owner string `json:"owner"`
Stake int `json:"stake"`
OwnerSignature string `json:"owner_signature"`
}
type TokenBurnV1 struct {
Fee int `json:"fee"`
Hash string `json:"hash"`
Memo string `json:"memo"`
Nonce int `json:"nonce"`
Payer string `json:"payer"`
Payee string `json:"payee"`
Amount int `json:"amount"`
}
type TransferHotspotV1 struct {
Hash string `json:"hash"`
Fee int `json:"fee"`
Buyer string `json:"buyer"`
Seller string `json:"seller"`
Gateway string `json:"gateway"`
BuyerNonce int `json:"buyer_nonce"`
AmountToSeller int `json:"amount_to_seller"`
}
type UnstakeValidatorV1 struct {
Address string `json:"address"`
Owner string `json:"owner"`
OwnerSignature string `json:"owner_signature"`
Fee int `json:"fee"`
StakeAmount int `json:"stake_amount"`
StakeReleaseHeight int `json:"stake_release_height"`
Hash string `json:"hash"`
}

View File

@ -13,12 +13,6 @@ type Account struct {
} `json:"data"` } `json:"data"`
} }
// Time int `json:"time"`
// StartEpoch int `json:"start_epoch"`
// Height int `json:"height"`
// Hash string `json:"hash"`
// EndEpoch int `json:"end_epoch"`
type AccountHotspots struct { type AccountHotspots struct {
Data []struct { Data []struct {
Lng float64 `json:"lng"` Lng float64 `json:"lng"`