Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into darren/admin-api-lo…
Browse files Browse the repository at this point in the history
…g-toggler
  • Loading branch information
otherview committed Dec 9, 2024
2 parents 186edc6 + 7579db4 commit d8f66d7
Show file tree
Hide file tree
Showing 43 changed files with 1,498 additions and 280 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/lint-go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ jobs:
with:
go-version: '1.22'
cache: false

- name: Check `builtins` directory
# if it has any changes in the 'builtins' dir after running `go generate`, echo an error and fail the workflow
run: |
go generate ./builtin/gen
git diff --exit-code builtin/gen || (echo "\n\n\nbuiltin/gen directory is not up to date, run 'go generate ./...' to update it" && exit 1)
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ jobs:
uses: actions/checkout@v4
with:
repository: vechain/thor-e2e-tests
# https://github.com/vechain/thor-e2e-tests/tree/209f6ea9a81a98dc2d5e42bf036d2878c5837036
ref: 209f6ea9a81a98dc2d5e42bf036d2878c5837036
# https://github.com/vechain/thor-e2e-tests/tree/8b72bedff11c9e8873d88b6e2dba356d43b56779
ref: 8b72bedff11c9e8873d88b6e2dba356d43b56779

- name: Download artifact
uses: actions/download-artifact@v4
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<p align="center">
<a href="https://www.vechain.org/vechainthor/">
<picture style="padding: 80px;">
<source srcset="docs/assets/banner-dark-mode.png" media="(prefers-color-scheme: dark)" >
<img src="docs/assets/banner-light-mode.png" style="padding: 20px;">
<source srcset="https://github.com/vechain/thor/blob/master/docs/assets/banner-dark-mode.png" media="(prefers-color-scheme: dark)" >
<img src="https://github.com/vechain/thor/blob/master/docs/assets/banner-light-mode.png" style="padding: 20px;">
</picture>
</a>
</p>
Expand Down Expand Up @@ -44,9 +44,9 @@ ___

## Documentation

- [Build](./docs/build.md) - How to build the `thor` binary.
- [Usage](./docs/usage.md) - How to run thor with different configurations.
- [Hosting a Node](./docs/hosting-a-node.md) - Considerations and requirements for hosting a node.
- [Build](https://github.com/vechain/thor/blob/master/docs/build.md) - How to build the `thor` binary.
- [Usage](https://github.com/vechain/thor/blob/master/docs/usage.md) - How to run thor with different configurations.
- [Hosting a Node](https://github.com/vechain/thor/blob/master/docs/hosting-a-node.md) - Considerations and requirements for hosting a node.
- [Core Concepts](https://docs.vechain.org/core-concepts) - Core concepts of the VeChainThor blockchain.
- [API Reference](https://mainnet.vechain.org) - The API reference for the VeChainThor blockchain.

Expand All @@ -67,15 +67,15 @@ To chat with other community members you can join:
<a href="https://www.reddit.com/r/Vechain"><img src="https://img.shields.io/badge/Reddit-FF4500?style=for-the-badge&logo=reddit&logoColor=white"/></a>
</p>

Do note that our [Code of Conduct](./docs/CODE_OF_CONDUCT.md) applies to all VeChain community channels. Users are
Do note that our [Code of Conduct](https://github.com/vechain/thor/blob/master/docs/CODE_OF_CONDUCT.md) applies to all VeChain community channels. Users are
**highly encouraged** to read and adhere to them to avoid repercussions.

---

## Contributing

Contributions to VeChainThor are welcome and highly appreciated. However, before you jump right into it, we would like
you to review our [Contribution Guidelines](./docs/CONTRIBUTING.md) to make sure you have a smooth experience
you to review our [Contribution Guidelines](https://github.com/vechain/thor/blob/master/docs/CONTRIBUTING.md) to make sure you have a smooth experience
contributing to VeChainThor.

---
Expand Down
28 changes: 17 additions & 11 deletions api/accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ import (
)

type Accounts struct {
repo *chain.Repository
stater *state.Stater
callGasLimit uint64
forkConfig thor.ForkConfig
bft bft.Committer
repo *chain.Repository
stater *state.Stater
callGasLimit uint64
forkConfig thor.ForkConfig
bft bft.Committer
enabledDeprecated bool
}

func New(
Expand All @@ -40,13 +41,15 @@ func New(
callGasLimit uint64,
forkConfig thor.ForkConfig,
bft bft.Committer,
enabledDeprecated bool,
) *Accounts {
return &Accounts{
repo,
stater,
callGasLimit,
forkConfig,
bft,
enabledDeprecated,
}
}

Expand Down Expand Up @@ -168,6 +171,9 @@ func (a *Accounts) handleGetStorage(w http.ResponseWriter, req *http.Request) er
}

func (a *Accounts) handleCallContract(w http.ResponseWriter, req *http.Request) error {
if !a.enabledDeprecated {
return utils.HTTPError(nil, http.StatusGone)
}
callData := &CallData{}
if err := utils.ParseJSON(req.Body, &callData); err != nil {
return utils.BadRequest(errors.WithMessage(err, "body"))
Expand Down Expand Up @@ -358,27 +364,27 @@ func (a *Accounts) Mount(root *mux.Router, pathPrefix string) {

sub.Path("/*").
Methods(http.MethodPost).
Name("accounts_call_batch_code").
Name("POST /accounts/*").
HandlerFunc(utils.WrapHandlerFunc(a.handleCallBatchCode))
sub.Path("/{address}").
Methods(http.MethodGet).
Name("accounts_get_account").
Name("GET /accounts/{address}").
HandlerFunc(utils.WrapHandlerFunc(a.handleGetAccount))
sub.Path("/{address}/code").
Methods(http.MethodGet).
Name("accounts_get_code").
Name("GET /accounts/{address}/code").
HandlerFunc(utils.WrapHandlerFunc(a.handleGetCode))
sub.Path("/{address}/storage/{key}").
Methods("GET").
Name("accounts_get_storage").
Name("GET /accounts/{address}/storage").
HandlerFunc(utils.WrapHandlerFunc(a.handleGetStorage))
// These two methods are currently deprecated
sub.Path("").
Methods(http.MethodPost).
Name("accounts_call_contract").
Name("POST /accounts").
HandlerFunc(utils.WrapHandlerFunc(a.handleCallContract))
sub.Path("/{address}").
Methods(http.MethodPost).
Name("accounts_call_contract_address").
Name("POST /accounts/{address}").
HandlerFunc(utils.WrapHandlerFunc(a.handleCallContract))
}
21 changes: 18 additions & 3 deletions api/accounts/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ var (
)

func TestAccount(t *testing.T) {
initAccountServer(t)
initAccountServer(t, true)
defer ts.Close()

tclient = thorclient.New(ts.URL)
Expand All @@ -126,6 +126,21 @@ func TestAccount(t *testing.T) {
}
}

func TestDeprecated(t *testing.T) {
initAccountServer(t, false)
defer ts.Close()

tclient = thorclient.New(ts.URL)

body := &accounts.CallData{}

_, statusCode, _ := tclient.RawHTTPClient().RawHTTPPost("/accounts", body)
assert.Equal(t, http.StatusGone, statusCode, "invalid address")

_, statusCode, _ = tclient.RawHTTPClient().RawHTTPPost("/accounts/"+contractAddr.String(), body)
assert.Equal(t, http.StatusGone, statusCode, "invalid address")
}

func getAccount(t *testing.T) {
_, statusCode, err := tclient.RawHTTPClient().RawHTTPGet("/accounts/" + invalidAddr)
require.NoError(t, err)
Expand Down Expand Up @@ -264,7 +279,7 @@ func getStorageWithNonExistingRevision(t *testing.T) {
assert.Equal(t, "revision: leveldb: not found\n", string(res), "revision not found")
}

func initAccountServer(t *testing.T) {
func initAccountServer(t *testing.T, enabledDeprecated bool) {
thorChain, err := testchain.NewIntegrationTestChain()
require.NoError(t, err)

Expand All @@ -291,7 +306,7 @@ func initAccountServer(t *testing.T) {
)

router := mux.NewRouter()
accounts.New(thorChain.Repo(), thorChain.Stater(), uint64(gasLimit), thor.NoFork, thorChain.Engine()).
accounts.New(thorChain.Repo(), thorChain.Stater(), uint64(gasLimit), thor.NoFork, thorChain.Engine(), enabledDeprecated).
Mount(router, "/accounts")

ts = httptest.NewServer(router)
Expand Down
3 changes: 2 additions & 1 deletion api/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/vechain/thor/v2/api/admin/apilogs"
healthAPI "github.com/vechain/thor/v2/api/admin/health"
"github.com/vechain/thor/v2/api/admin/loglevel"

healthAPI "github.com/vechain/thor/v2/api/admin/health"
)

func New(logLevel *slog.LevelVar, health *healthAPI.Health, apiLogsToggle *atomic.Bool) http.HandlerFunc {
Expand Down
44 changes: 11 additions & 33 deletions api/admin/health/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package health

import (
"sync"
"time"

"github.com/vechain/thor/v2/chain"
Expand All @@ -20,17 +19,15 @@ type BlockIngestion struct {
}

type Status struct {
Healthy bool `json:"healthy"`
BestBlockTimestamp *time.Time `json:"bestBlockTimestamp"`
WasChainSynced bool `json:"wasChainSynced"`
PeerCount int `json:"peerCount"`
Healthy bool `json:"healthy"`
BestBlockTime *time.Time `json:"bestBlockTime"`
PeerCount int `json:"peerCount"`
IsNetworkProgressing bool `json:"isNetworkProgressing"`
}

type Health struct {
lock sync.RWMutex
repo *chain.Repository
p2p *comm.Communicator
isNodeBootstrapped bool
repo *chain.Repository
p2p *comm.Communicator
}

const (
Expand All @@ -50,30 +47,12 @@ func (h *Health) isNetworkProgressing(now time.Time, bestBlockTimestamp time.Tim
return now.Sub(bestBlockTimestamp) <= blockTolerance
}

// hasNodeBootstrapped checks if the node has bootstrapped by comparing the block interval.
// Once it's marked as done, it never reverts.
func (h *Health) hasNodeBootstrapped(now time.Time, bestBlockTimestamp time.Time) bool {
if h.isNodeBootstrapped {
return true
}

blockInterval := time.Duration(thor.BlockInterval) * time.Second
if bestBlockTimestamp.Add(blockInterval).After(now) {
h.isNodeBootstrapped = true
}

return h.isNodeBootstrapped
}

// isNodeConnectedP2P checks if the node is connected to peers
func (h *Health) isNodeConnectedP2P(peerCount int, minPeerCount int) bool {
return peerCount >= minPeerCount
}

func (h *Health) Status(blockTolerance time.Duration, minPeerCount int) (*Status, error) {
h.lock.RLock()
defer h.lock.RUnlock()

// Fetch the best block details
bestBlock := h.repo.BestBlockSummary()
bestBlockTimestamp := time.Unix(int64(bestBlock.Header.Timestamp()), 0)
Expand All @@ -90,17 +69,16 @@ func (h *Health) Status(blockTolerance time.Duration, minPeerCount int) (*Status

// Perform the checks
networkProgressing := h.isNetworkProgressing(now, bestBlockTimestamp, blockTolerance)
wasChainSynced := h.hasNodeBootstrapped(now, bestBlockTimestamp)
nodeConnected := h.isNodeConnectedP2P(connectedPeerCount, minPeerCount)

// Calculate overall health status
healthy := networkProgressing && wasChainSynced && nodeConnected
healthy := networkProgressing && nodeConnected

// Return the current status
return &Status{
Healthy: healthy,
BestBlockTimestamp: &bestBlockTimestamp,
WasChainSynced: wasChainSynced,
PeerCount: connectedPeerCount,
Healthy: healthy,
BestBlockTime: &bestBlockTimestamp,
IsNetworkProgressing: networkProgressing,
PeerCount: connectedPeerCount,
}, nil
}
35 changes: 0 additions & 35 deletions api/admin/health/health_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,41 +42,6 @@ func TestHealth_isNetworkProgressing(t *testing.T) {
}
}

func TestHealth_hasNodeBootstrapped(t *testing.T) {
h := &Health{}
now := time.Now()

tests := []struct {
name string
bestBlockTimestamp time.Time
expectedBootstrap bool
}{
// keep the order as it matters for health state
{
name: "Not Bootstrapped - block timestamp outside interval",
bestBlockTimestamp: now.Add(-defaultBlockTolerance + 1),
expectedBootstrap: false,
},
{
name: "Bootstrapped - block timestamp within interval",
bestBlockTimestamp: now.Add(defaultBlockTolerance),
expectedBootstrap: true,
},
{
name: "Bootstrapped only once",
bestBlockTimestamp: now.Add(-defaultBlockTolerance + 1),
expectedBootstrap: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
isBootstrapped := h.hasNodeBootstrapped(now, tt.bestBlockTimestamp)
assert.Equal(t, tt.expectedBootstrap, isBootstrapped, "hasNodeBootstrapped result mismatch")
})
}
}

func TestHealth_isNodeConnectedP2P(t *testing.T) {
h := &Health{}

Expand Down
Loading

0 comments on commit d8f66d7

Please sign in to comment.